Skip to content
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

Missing symbols in static Flutter plugin builds #1475

Open
stuartmorgan opened this issue Aug 28, 2024 · 2 comments
Open

Missing symbols in static Flutter plugin builds #1475

stuartmorgan opened this issue Aug 28, 2024 · 2 comments
Assignees

Comments

@stuartmorgan
Copy link

stuartmorgan commented Aug 28, 2024

When adding some new usage of .listener for blocks, I started hitting this error at runtime:

Unhandled Exception: Invalid argument(s): Couldn't resolve native function 'disposeObjCBlockWithClosure' in 'objective_c.framework/objective_c' : No asset with id 'objective_c.framework/objective_c' found. No available native assets. Attempted to fallback to process lookup. dlsym(RTLD_DEFAULT, disposeObjCBlockWithClosure): symbol not found.

It looks like there's nothing guaranteeing that this symbol is preserved, so in certain build configurations it's being dead-code stripped. For some important context here, CocoaPod-based plugins can be built in two configurations: as frameworks that are bundled into the app bundle, or as static libraries that are linked directly into the Runner. This depends on both plugin-level settings and app-level settings. flutter create using a Swift app template defaults to forcing framework builds (for somewhat complicated and mostly legacy reasons), while an Obj-C app template does not. In the new SPM-based system Flutter is moving to, there is a similar divergence in build types depending on whether it's a release build.

I'm currently working on a plugin old enough that its example app is Obj-C, so it uses static library builds. In that app, disposeObjCBlockWithClosure is not present anywhere in my final build; the plugin is being built statically and linked in, but the symbol isn't in the resulting binary, so presumably it's been stripped. I was able to fix my app by adding use_frameworks!, but plugins need to support both modes.

I assume this will be migrating to native assets at some point; I'm not sure how far out that is, and if we need another workaround in the short term.

@mkustermann
Copy link
Member

mkustermann commented Aug 28, 2024

The error message indicates it's based on our declarative FFI (e.g. @Native annotations) which works only with the native code asset experiment flag turned on and a hook/build.dart was adding the "native code asset" with an id.

(It does has a fallback path - if nohook/build.dart was used - to look the symbol in the process namespace - so @Native works e.g. for binding with malloc(). On some platforms DynamicLibrary.open(<foo>') will make the symbols available in process namespace - which means a manual open of a library will make declarative API work without hook/build.dart)

/cc @dcharkes

@dcharkes
Copy link
Collaborator

dcharkes commented Sep 3, 2024

It does have a fallback path

It's using the fallback path. package:objective_c is not using a build hook. It's using DynamicLibrary.open on the dylib and subsequently uses @Natives relying on the fact that on iOS and MacOS the symbols are loaded with global visibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Todo
Development

No branches or pull requests

4 participants