-
Notifications
You must be signed in to change notification settings - Fork 67
Missing Dart_InitializeApiDL
symbol in plugin using package:objective_c
#1671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Looks like the swift example is hitting #1220 |
@alevlako Do want to file a separate bug to discuss the issues you're having with your own Swift bindings? The first thing to check is whether you can see the APIs you expect in the generated ObjC header. |
@liamappelbe I see in generated swift_api.h following code:
I commented out getter isProxy in generated file swift_api_bindings.dart and was able to receive the error in this example that I get in my project: Exception has occurred. The exception occurs here (in last line of the code, in generated file swift_api_bindings.dart ):
I am using the actual versions of dependencies: |
Ok, let's set aside the swift example for now (I know what the issue is there, and I'll fix that separately). Let's just focus on your project.
Can you tell me more about your project? Are you writing a flutter app or a dart command line tool? What does your project do? What are you using swift interop for? From that error, my guess is you're writing a dart tool, not a flutter app. That's possible, but has some limitations (certain Apple APIs won't work in a pure dart tool, such as UI APIs). |
@liamappelbe thank you for your interest in my problem. The ultimate goal of my project is to create a flutter plugin package for all desktop operating systems. The Windows part I finished whithin limits of pure dart package, using only WinAPI. For Mac and Linux I need work with ffi for access to native libs. I already realized that pure dart package will not enough for this purpose. In particular, in MacOS, my code accesses the Carbon library, or if I want to be more accurate its part HIToolbox/TextInputSources.h. At this stage, I can call my swift library in the Flutter application, which runs from Xcode or which is launched in macOS after release build in VSCode. The application crashes when I launch code in debug mode in VSCode because of carbon call. |
Ok, if you're writing an ObjC/Swift plugin, then this shouldn't be too hard. The missing |
The examples are fixed, so this bug is now tracking @alevlako's specific issue, where the missing symbol error is showing up in a flutter plugin. @alevlako The next step to debug this is to make sure that your plugin depends on the package:objective_c plugin, then build your plugin, then find your plugin's dylib and use |
Dart_InitializeApiDL
symbol in plugin using package:objective_c
@liamappelbe thank you for your assistance, I really managed to advance thanks to your help. |
Does In the meantime you can use |
@liamappelbe Thanks to your hint, the application does not crash, but also does not do the useful work for which it is created. Looks like I need to try using the method channel instead of ffi ( |
@alevlako I forgot that For MacOS I'd recommend writing a little bit of ObjC code that dispatches that call to the main thread. Since your callback didn't run, we still don't actually know if your original crash was caused by the call needing to be done on the main thread. So before you get too deep into writing that native code, try writing a little test function to check if dispatching to the main thread fixes the crash: void callCarbonOnMainThread() {
dispatch_async(dispatch_get_main_queue(), ^{
// Call carbon.
// Log/print the result to confirm that it works.
});
} If that works, then we can talk about how to send the result back to Dart land. |
@liamappelbe great, it works! |
@alevlako It's actually pretty simple. Just pass a listener block to // Objective-C
void callCarbonOnMainThread(void (^completionHandler)(NSArray *)) {
dispatch_async(dispatch_get_main_queue(), ^{
// Call carbon.
completionHandler(result);
});
} Add // Dart
final completionHandler = ObjCBlock_ffiVoid_NSArray.listener((NSArray result) {
callCarbonResult = result;
});
callCarbonOnMainThread(completionHandler); On some older versions of ffigen we've had bugs to do with memory management of blocks. So if you see a crash when the completion handler is invoked, try holding a reference to it on the Dart side (eg stick it in a global variable). Hopefully that bug won't affect you though. |
@liamappelbe Unfortunately, the proposed solution produces an error even without any implementation, at the call protocol level. What am I missing?
Now I generate the dart file with ffigen (the package version is up to date: ^16.0.0)
Method callCarbon prints mesage to console.
|
@alevlako That error means you're not linking the ffigen generated ObjC code into your app. Newer versions of ffigen generate a little bit of ObjC trampoline code for each listener block (to fix that memory management issue I mentioned). It'll be sitting next to the generated dart file (same name, with We should probably make that error more descriptive. |
@liamappelbe FYI, I tested all my methods that call the Carbon library in the ffigen swift example. They work as intended without using dispatch_async(dispatch_get_main_queue() or DispatchQueue.global(qos: .background).async |
I assume these are thread locked APIs? Yeah, very recent versions of Flutter have started merging the UI thread and the platform thread, so that makes calling these sorts of APIs simpler. |
@liamappelbe No, it's only possible in the mentioned example (native/pkgs/ffigen/swift). When I try to use ffigen & objective_c packages in the standard plugin_ffi example of the Flutter, I still can't do Carbon calls without these methods. At least, I haven't succeeded yet. I wrote one working function in Objective C. Estimating the time I'll have to spend to rewrite my swift code to Objective C, I'm inclined to abandon the idea of using ffi in favor of method channel. Also, the dart documentation describes creating a .dylib library, not a .framework from swift code. |
It depends what version of Flutter you're using. I think the thread merging I mentioned is only available in Flutter 3.29, and only on iOS/Android. Not sure what the situation is on macOS. If you're on an older version of Flutter you can use |
Uh oh!
There was an error while loading. Please reload this page.
I wrote and tested my code in Swift, made a wrapper for it in Objective C, everything works up to this point. Now I need to call this code from Dart. I turned to the ffigen package and for several days I could not achieve a working result. Then I decided to check the simplest option - and I found that even base Swift example here does not work (
I have the macOs 13.7 installed.
I get the following error message when I try to run the example after all the preparation described in the readme (for default example pubspec.yaml):
swift_api_bindings.dart:26780:12: Error: Can't declare a member that conflicts with an inherited one.
bool get isProxy {
^^^^^^^
../../../objective_c/lib/src/objective_c_bindings_generated.dart:6785:8: Context: This is the inherited member.
bool isProxy() {
^^^^^^^
Or for dependencies: objective_c: ^3.0.0, ffigen: ^15.0.0:
swift_api_bindings.dart:25294:12: Error: Can't declare a member that conflicts with an inherited one.
bool get isProxy {
^^^^^^^
../../../../../../../.pub-cache/hosted/pub.dev/objective_c-3.0.0/lib/src/objective_c_bindings_generated.dart:6785:8: Context: This is the inherited member.
bool isProxy() {
^^^^^^^
The text was updated successfully, but these errors were encountered: