Dart use in Flutter: FFI DART synchronous call C is officially supported. However, there is no official description of how to implement C call Dart, and there is no relevant implementation available online. Ali is said to have implemented C’s method of calling Dart, patented it and open-source it in the Kraken project. Can’t wait to see the source code. Let’s summarize.

The Dart layer is used to register the Dart method address. The Dart layer is used to register the Dart method address by passing ffI to C Pointer, which is a Pointer to native C memory. _dartNativeMethods is an array that holds the Dart method address

void registerDartMethodsToCpp() {
  Pointer<Uint64> bytes = allocate<Uint64>(count: _dartNativeMethods.length);
  Uint64List nativeMethodList = bytes.asTypedList(_dartNativeMethods.length);
  nativeMethodList.setAll(0, _dartNativeMethods);
  _registerDartMethods(bytes, _dartNativeMethods.length);
}
Copy the code

How do I get the Dart method address? Using Pointer. FromFunction Dart method can be converted to the C method Pointers, then use the _nativeInvokeModule. Can get to the Dart method to address the address.

final Pointer<NativeFunction<Native_InvokeModule>> _nativeInvokeModule = Pointer.fromFunction(_invokeModule);
Copy the code

Dart: ffI is used to call C layer code. RegisterDartMethods (Pointer methodBytes, Int32 length) is called;

final Dart_RegisterDartMethods _registerDartMethods =
    nativeDynamicLibrary.lookup<NativeFunction<Native_RegisterDartMethods>>('registerDartMethods').asFunction();
    
typedef Native_RegisterDartMethods = Void Function(Pointer<Uint64> methodBytes, Int32 length);
Copy the code

Following is code for the C layer that converts the Dart layer function address into a function pointer using reinterpret_cast

void registerDartMethods(uint64_t *methodBytes, int32_t length) {
  size_t i = 0; methodPointer->invokeModule = reinterpret_cast<InvokeModule>(methodBytes[i++]); . } typedef NativeString *(*InvokeModule)(void *callbackContext, int32_t contextId, NativeString *moduleName, NativeString *method, NativeString *params, AsyncModuleCallback callback);
Copy the code

Finally, you can call the Dart method at the C layer

NativeString *response = getDartMethod()->invokeModule(bridgeContext, contextId, moduleName, method, params,
                                                               handleInvokeModuleTransientCallback);
Copy the code

One thing to note here is that the Dart method must be called in the Flutter UI thread or Crash

Dart String is utF-16, and C is UTF-8. Dart String is utF-16, and C is UTF-8. Dart String is UTF-16, and C is UTF-8. Officially, the encoding is all UTF-16 with no conversion costs

class NativeString extends Struct {
  Pointer<Uint16> string;

  @Int32()
  int length;
}

String uint16ToString(Pointer<Uint16> pointer, int length) {
  return String.fromCharCodes(pointer.asTypedList(length));
}

Pointer<Uint16> _stringToUint16(String string) {
  final units = string.codeUnits;
  final Pointer<Uint16> result = allocate<Uint16>(count: units.length);
  final Uint16List nativeString = result.asTypedList(units.length);
  nativeString.setAll(0, units);
  return result;
}

Pointer<NativeString> stringToNativeString(String string){ assert(string ! =null);
  Pointer<NativeString> nativeString = allocate<NativeString>();
  nativeString.ref.string = _stringToUint16(string);
  nativeString.ref.length = string.length;
  return nativeString;
}

String nativeStringToString(Pointer<NativeString> pointer) {
  return uint16ToString(pointer.ref.string, pointer.ref.length);
}
Copy the code