How to access methods in a Flutter for desktop (macOS) app

Issue

I have been trying to write a Flutter desktop app which can communicate with Go methods.

Go file:

package main

import "C"
import "fmt"

func PrintHello() {
    fmt.Print("Hello,World")
}

func main() {}
import 'dart:ffi' as ffi;

typedef PrintHello_func = ffi.Void Function();
typedef PrintHello = void Function();

void ffi_test(List<String> arguments) {
  var path = '/path/to/libhello_ffi.dylib';

  final ffi.DynamicLibrary dylib = ffi.DynamicLibrary.open(path);

  final PrintHello hello = dylib
      .lookup<ffi.NativeFunction<PrintHello_func>>('PrintHello')
      .asFunction();

  hello();
}

The execution of the above Flutter code fails with an error:

The following ArgumentError was thrown while handling a gesture:
Invalid argument(s): Failed to load dynamic library
(dlopen(/path/to/libhello_ffi.dylib, 1):
no suitable image found.  Did find:
    file system sandbox blocked open() of
'/path/to/libhello_ffi.dylib')

But it works just fine if I execute the dart directly instead of flutter run.

I even tried to create a separate FFI package but unfortunately it failed as well.

FFI package name: /my_app/packages/libhello_ffi

I placed the libhello_ffi.dylib file under /my_app/packages/libhello_ffi/macos directory

Flutter code:


import 'dart:ffi';
import 'dart:io';

final DynamicLibrary _dl = _open();

DynamicLibrary _open() {
  if (Platform.isMacOS) return DynamicLibrary.executable();
  throw UnsupportedError('This platform is not supported.');
}

typedef sayhello_C = Void Function();
typedef sayhello_Dart = void Function();

void sayhello() {
  _dl.lookup<NativeFunction<sayhello_C>>('PrintHello')
      .asFunction();
}

Error:

The following ArgumentError was thrown while handling a gesture:
Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, PrintHello): symbol not found)

When the exception was thrown, this was the stack:
#0      DynamicLibrary.lookup (dart:ffi-patch/ffi_dynamic_library_patch.dart:31:29)
#1      sayhello (package:libhello_ffi/ffi.dart:17:7)
#2      LibhelloFfi.sayhello (package:libhello_ffi/libhello_ffi.dart:5:12)
#3      ffi_test (package:squash_archiver/features/home/ui/widgets/ffi_test.dart:10:13)
#4      _HomeScreenState._buildTestFfi.<anonymous closure> (package:squash_archiver/features/home/ui/pages/home_screen.dart:73:13)
#5      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:992:19)
#6      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1098:38)

There isn’t any proper article on the Go and Flutter for Desktop integration available online.

Solution

But it works just fine if I execute the dart directly instead of flutter run

Dart isn’t a sandboxed app, while a Flutter app is sandboxed by default. That’s why you are only getting a sandbox error in your Flutter app.

I placed the libhello_ffi.dylib file under /my_app/packages/libhello_ffi/macos directory

This sounds like a location in your source tree, not your application. You can’t reference arbitrary files outside your application unless you disable the sandbox.

If you are just testing locally, turning off the sandbox is the easy solution. If you want something you can distribute, you need to package the library in your bundle (by adding it as a bundled resource in your Xcode project) anyway, at which point I would expect loading it to work even with the sandbox.

Answered By – smorgan

Answer Checked By – Timothy Miller (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *