My app's backend is written in C++ and the frontend in Dart/flutter. I'd love to have the backend notify frontend whenever data is ready. This requires implementing an async callback scheme between Dart and C++.
$ flutter doctor -v
[✓] Flutter (Channel stable, 1.20.1, on Mac OS X 10.15.5 19F101, locale
en-CN)
• Flutter version 1.20.1 at /Applications/Android/flutter
• Framework revision 2ae34518b8 (2 days ago), 2020-08-05 19:53:19 -0700
• Engine revision c8e3b94853
• Dart version 2.9.0
• Pub download mirror https://pub.flutter-io.cn
• Flutter download mirror https://storage.flutter-io.cn
[✓] Android toolchain - develop for Android devices (Android SDK version
30.0.1)
• Android SDK at /Applications/Android/sdk
• Platform android-30, build-tools 30.0.1
• ANDROID_HOME = /Applications/Android/sdk
• ANDROID_SDK_ROOT = /Applications/Android/sdk
• Java binary at: /Applications/Android
Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6222593)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.6, Build version 11E708
• CocoaPods version 1.8.4
[✓] Android Studio (version 4.0)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 48.0.2
• Dart plugin version 193.7361
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6222593)
[✓] VS Code (version 1.47.3)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.8.1
[!] Connected device
! No devices available
I looked at the github example from the Dart team.
To adapt the sample code to a flutter project, I did the following
main
function with the sample functionexpect
dart-sdk-master/runtime/bin/ffi_test/ffi_test_functions.cc
However, I couldn't get the sample to run.
The first problem I had was that the dart version was not supported when I run the sample directly. I'm on latest stable channel, and also tried dev channel. The error says
Error: The specified language version is too high. The highest supported language version is 2.9.
The information on the native-side implementation is missing in the example. So I'm left with lots of compiler errors.
Launching lib/main.dart on ONEPLUS A6000 in debug mode...
Running Gradle task 'assembleDebug'...
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing process /Applications/Android/sdk/cmake/3.6.4111459/bin/cmake with arguments {--build /path/to/ffiasync/example/android/app/.cxx/cmake/debug/armeabi-v7a --target ffiasync}
[1/2] Building CXX object CMakeFiles/ffiasync.dir/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc.o
[2/2] Linking CXX shared library /path/to/ffiasync/example/build/app/intermediates/cmake/debug/obj/armeabi-v7a/libffiasync.so
FAILED: : && /Applications/Android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=armv7-none-linux-androideabi16 --gcc-toolchain=/Applications/Android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64 --sysroot=/Applications/Android/sdk/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libffiasync.so -o /path/to/ffiasync/example/build/app/intermediates/cmake/debug/obj/armeabi-v7a/libffiasync.so CMakeFiles/ffiasync.dir/path/to/ffiasync/lib/ffiasync.cpp.o CMakeFiles/ffiasync.dir/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc.o -latomic -lm && :
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:54: error: undefined reference to 'Dart_ExecuteInternalCommand'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:60: error: undefined reference to 'Dart_ExecuteInternalCommand'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:66: error: undefined reference to 'Dart_ExecuteInternalCommand'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:74: error: undefined reference to 'Dart_ExecuteInternalCommand'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:143: error: undefined reference to 'Dart_CurrentIsolate'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:183: error: undefined reference to 'ClobberAndCall'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:277: error: undefined reference to 'Dart_InitializeApiDL(void*)'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:288: error: undefined reference to 'Dart_DumpNativeStackTrace'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:289: error: undefined reference to 'Dart_PrepareToAbort'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_PostCObject_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_NewNativePort_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_PostCObject_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_CloseNativePort_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_PostCObject_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:791: error: undefined reference to 'Dart_NewPersistentHandle'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:793: error: undefined reference to 'Dart_HandleFromPersistent'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:794: error: undefined reference to 'Dart_DeletePersistentHandle'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:795: error: undefined reference to 'Dart_IsError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:796: error: undefined reference to 'Dart_PropagateError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:800: error: undefined reference to 'Dart_IsNull'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:802: error: undefined reference to 'Dart_NewWeakPersistentHandle'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:804: error: undefined reference to 'Dart_HandleFromWeakPersistent'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:809: error: undefined reference to 'Dart_DeleteWeakPersistentHandle'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:826: error: undefined reference to 'Dart_IsError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:829: error: undefined reference to 'Dart_PropagateError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:846: error: undefined reference to 'Dart_NewStringFromCString'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:847: error: undefined reference to 'Dart_IsError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:848: error: undefined reference to 'Dart_PropagateError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:850: error: undefined reference to 'Dart_NewInteger'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:851: error: undefined reference to 'Dart_IsError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:852: error: undefined reference to 'Dart_PropagateError'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:855: error: undefined reference to 'Dart_Invoke'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:874: error: undefined reference to 'Dart_NewStringFromCString'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:879: error: undefined reference to 'Dart_GetField'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:885: error: undefined reference to 'Dart_IntegerToInt64'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:895: error: undefined reference to 'Dart_EnterScope'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:900: error: undefined reference to 'Dart_ExitScope'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:905: error: undefined reference to 'Dart_True'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_NewPersistentHandle_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_HandleFromPersistent_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_SetPersistentHandle_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_DeletePersistentHandle_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_NewWeakPersistentHandle_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_HandleFromWeakPersistent_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_DeleteWeakPersistentHandle_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_NewPersistentHandle_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_HandleFromPersistent_DL'
/path/to/ffiasync/lib/ffi_test_functions_vmspecific.cc:0: error: undefined reference to 'Dart_DeletePersistentHandle_DL'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 12s
Exception: Gradle task assembleDebug failed with exit code 1
Unable to get answers from Dart team, I have a few questions
I'm afraid that with this little info, it would be too difficult to figure it out by trail-and-error.
Agreed, it's not clear how you link against the Dart SDK executable(?)/shared library(?) while building your Android shared library or your iOS code. It compiles, but won't link.
Given that Dart is single-threaded and the async callback technique involves signalling the main Dart thread to indicate that it's time to call down to C to allow a callback to take place on that single, main thread, I've never seen much advantage over, say, polling from Dart (maybe from a timer) to see whether the response is ready. At 60fps, is there much point knowing that the response is ready half way through a 16ms inter-frame interval? The change isn't going to reflect until the next paint anyway. Sure, it doesn't feel very efficient to poll, but once every 16ms isn't that expensive.