[Bug] Runtime error calling functions across bridge in iOS release mode
Describe the bug
When my app calls into the bridge functions in the debug mode of my app on iOS, it works correctly (simulator or real device), however in release mode it fails with errors like these:
Invalid argument(s): Failed to lookup symbol 'store_dart_post_cobject': dlsym(RTLD_DEFAULT, store_dart_post_cobject): symbol not found
Exception: Subclasses of `FlutterRustBridgeBase` should be singletons - there should not be two instances (runtimeType=NativeImpl)
The first one only ever appears once, then the rest are always the second error. Sometimes I only see the second error.
To get to this point I've followed all the steps in the docs. I've also tried to look through all the issues in this repo.
Codegen logs with RUST_LOG=debug env variable
cd native && cargo build && cargo build --release && cd .. && RUST_LOG=debug just >& /tmp/eh
Output: https://gist.github.com/banool/3d1143f9acb02bb79f9cff2011bcc323.
To Reproduce
git clone [email protected]:banool/aclip.git
cd frontend
cd native
cargo build
cargo build --release
cd ..
just
flutter run -d 'My Real iPhone' --release
Once in the app, go to Settings -> Offline download errors to see the errors pasted above.
Expected behavior
You can see the expected behavior by running the above repro but without --release.
Generated binding code
See https://github.com/banool/aclip/.
OS
MacOS 12.4
Version of flutter_rust_bridge_codegen
1.34.1
Flutter info
https://gist.github.com/5ecf66d7f10d20932a4db7072464c232
Version of clang++
13.1.6
Version of ffigen
5.0.1
Additional context
Linking a possibly (but probably not) related issue that I've also been struggling with a lot: https://github.com/bbqsrc/cargo-ndk/issues/65.
Hi! Thanks for opening your first issue here! :smile:
Invalid argument(s): Failed to lookup symbol 'store_dart_post_cobject': dlsym(RTLD_DEFAULT, store_dart_post_cobject): symbol not found
Guess ios just think the symbol is unused and thus strip it. Try http://cjycode.com/flutter_rust_bridge/integrate/ios_headers.html.
In addition, try this template project http://cjycode.com/flutter_rust_bridge/template.html.
Exception: Subclasses of
FlutterRustBridgeBaseshould be singletons - there should not be two instances (runtimeType=NativeImpl)
Sounds like bug in your code. Do not create two instances of your flutterrustbridge class.
Hi, I've done everything suggested at http://cjycode.com/flutter_rust_bridge/integrate/ios_headers.html already, and I've done it again multiple times just to make sure.
I started by using that template and I didn't change it, so I'm not sure it's that either, I haven't touched the code that creates the FlutterRustBridgeBase. You can see that I only do it once here: https://github.com/banool/aclip/blob/main/frontend/lib/ffi.dart#L20.
/cc @Desdaemon who wrote the wonderful template
And, does this work: http://cjycode.com/flutter_rust_bridge/integrate/ios_headers.html.
Hey yeah I did that and it doesn't help, at frontend/ios in the attached repo.
- print some log around https://github.com/banool/aclip/blob/a8c16c7a0641c411f1296af3bbd3d5b8a669d2d4/frontend/ios/Runner/AppDelegate.swift#L10, and see whether this is really executed or not.
- try to use the
store_dart_post_cobjectfunction in raw ios code, and see whether you can use it or not. - use toolings around ios packages to see whether the store_dart_post_cobject symbol is really there or not (e.g. objdump or nm for linux builds, ios should have similar things)
- I just put in logging and can confirm this gets executed, in both debug and release mode.
- It seems to work. Code in
AppDelegate.swift: https://gist.github.com/banool/0e2a2f9e325f2d0fd51c6c9e2bfff862, the output from the logs: https://gist.github.com/banool/67879b72d5298b5a9ff59d6a58ebd7ce. I'm not sure if I should expect to see "TESTING" too though. - It does seem to be there.
Okay I just figured it out. tl;dr, dummy_method_to_enforce_bundling doesn't actually do its job. What does work is this in AppDelegate.swift:
print(wire_download_page)
print(wire_platform)
print(wire_rust_release_mode)
print(new_box_autoadd_options)
print(new_uint_8_list)
print(free_WireSyncReturnStruct)
print(store_dart_post_cobject)
As in, just printing each of the methods that I see in dummy_method_to_enforce_bundling .
I figure there must be a more elegant solution than this. If y'all can think of one, I can make a PR.
Okay a better method is this:
let dummy = dummy_method_to_enforce_bundling()
print(dummy)
It seems they just throw out the function call if you don't use the value from it. I will make a PR suggesting this change.
See PR: https://github.com/fzyzcjy/flutter_rust_bridge/pull/502.
It seems they just throw out the function call if you don't use the value from it. I will make a PR suggesting this change.
Oh you are right! Indeed in my code in production I do print it. But when considering your issue I forgot this...
Btw the template here also prints it: https://github.com/Desdaemon/flutter_rust_bridge_template/blob/d5526258ac59065f14e71a49fffa6a71ec3907a3/ios/Runner/AppDelegate.swift#L10
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.