Flutter, use DynamicLibrary.open() on prebuild GO .so library without the need to write Native Code(Java/Swift)

3,083

I think the problem might be that Dart's FFI doesn't directly support Strings. Have a look at this sample for a way to marshal strings using the separate ffi package: https://github.com/dart-lang/samples/blob/master/ffi/system-command/linux.dart

Share:
3,083
jalanga
Author by

jalanga

Life is just a game.

Updated on December 14, 2022

Comments

  • jalanga
    jalanga over 1 year

    I made a GO library and build it as an .so library. Is working loading the library in Java with System.loadLibrary() but I can not manage it to load directly from flutter/dart using DynamicLibrary.open().

    I want to skip the process of calling native code, and load Shared Libraries directly in flutter.

    DynamicLibrary.open is only available on dev channel v1.10.14.

    Documentation with examples using Cmake: https://flutter.dev/docs/development/platform-integration/c-interop

    My code:

    static final DynamicLibrary nativeAddLib = DynamicLibrary.open("lib-mylib.so");
    final int Function (String ifName, int tunFd, String settings) addStuff = nativeAddLib.lookup<NativeFunction<Int32 Function(String, Int32, String)>>("addStuff").asFunction();
    

    Error:

    Compiler message:
    lib/vpn_connection/vpn_connection_bloc.dart:20:164: Error: Expected type 'NativeFunction<Int32 Function(String, Int32, String)>' to be a valid   and instantiated subtype of 'NativeType'.
    - 'NativeFunction' is from 'dart:ffi'.
    - 'Int32' is from 'dart:ffi'.
    final int Function (String ifName, int tunFd, String settings) addStuff = nativeAddLib.lookup<NativeFunction<Int32 Function(String, Int32, String)>>("addStuff").asFunction();
                                                                                                                                                                     ^
    Exception: Errors during snapshot creation: null
    #0      KernelSnapshot.build (package:flutter_tools/src/build_system  /targets/dart.dart:226:7)
    <asynchronous suspension>
    #1      _BuildInstance._invokeInternal (package:flutter_tools/src/build_system/build_system.dart:526:25)
    <asynchronous suspension>
    #2      _BuildInstance.invokeTarget.<anonymous closure>   (package:flutter_tools/src/build_system/build_system.dart:481:35)
    #3      new Future.sync (dart:async/future.dart:224:31)
    #4      AsyncMemoizer.runOnce (package:async/src/async_memoizer.dart:43:45)
    #5      _BuildInstance.invokeTarget (package:flutter_tools/src/build_system/build_system.dart:481:21)
    

    It looks like is not finding the file/function.

    My gradle:

    android {
    compileSdkVersion 28
    
    lintOptions {
        disable 'InvalidPackage'
    }
    
    sourceSets.main {
        jniLibs.srcDirs += files(extraJniDirectory)
    }
    
    defaultConfig {
        applicationId "com.custom.android"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    
        ndk {
            abiFilters "armeabi", "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
        }
    }
    
    buildTypes {
        release {
            signingConfig signingConfigs.debug
    
            ndk {
                if (project.hasProperty('target-platform') &&
                        project.property('target-platform') == 'android-arm64') {
                    abiFilters 'arm64-v8a'
                } else {
                    abiFilters 'armeabi-v7a'
                }
            }
        }
    }
    }
    

    Update:

    I created a .so file with CMake as in the flutter example, I extract it from the apk and put it in the same folder with my go build .so file, and is working, but I can't find why my first .so file is not working from flutter but, is working from android.

    Update2:

    DynamicLibrary.open("lib-mylib.so") is loaded, nativeAddLib.lookup<NativeFunction<Int32 Function(String, Int32, String)>>("addStuff") is returning a pointer, that means the function is found, but when calling .asFunction() it breaks.

    By simplifying the code:

    var addStuff = nativeAddLib.lookup("addStuff").asFunction();
    

    I get the error:

    Error: Expected type 'NativeType' to be a valid and instantiated subtype of 'NativeType'.
    - 'NativeType' is from 'dart:ffi'.
    
  • jalanga
    jalanga over 4 years
    I will give it a try, I don't think is from String support, because I tried with different methods which are accepting Int32 and not returning(void).
  • eug
    eug over 4 years
    If you paste the code & error messages from the simpler Int32 example that might help. void is actually similar to String - one needs to use a special ffi.Void type in the native typedef.
  • eug
    eug over 4 years
    Glad that helped! I sure hope they improve the error messages soon..