rive-app / rive-flutter

Flutter runtime for Rive
https://rive.app
MIT License
1.16k stars 180 forks source link

Crash - Failed to load dynamic library 'librive_text.so' #403

Open daniel102102 opened 1 week ago

daniel102102 commented 1 week ago

Hi. We are using rive for flutter.

We see a massive crash in firabse on Android 5 and Android 6, see callstack below. It happens on various devices. librive_text.so is included in compilation for all architectures.

      Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Invalid argument(s): Failed to load dynamic library 'librive_text.so': dlopen failed: library "librive_text.so" not found
   at new DynamicLibrary.open(dart:ffi)
   at ._loadLibrary(rive_audio_ffi.dart:41)
   at .nativeLib(rive_text_ffi.dart:11)
   at .init(rive_text_ffi.dart)
   at .initFont(rive_text_ffi.dart)
   at Font.initialize(rive_text.dart:477)
   at RiveFile.initialize(rive_file.dart:383)
   at EndScreenAnimation.initializeRive(end_screen_animation.dart:15)
   at TapToZoomTutorialState._loadRiveFile(tap_to_zoom_tutorial.dart:32)
   at TapToZoomTutorialState.initState(tap_to_zoom_tutorial.dart:28)
   at StatefulElement._firstBuild(framework.dart:5618)
   at ComponentElement.mount(framework.dart:5463)
   at Element.inflateWidget(framework.dart:4340)
   at MultiChildRenderObjectElement.inflateWidget(framework.dart:6904)
   at MultiChildRenderObjectElement.mount(framework.dart:6916)
   at Element.inflateWidget(framework.dart:4340)
   at Element.updateChild(framework.dart:3849)
   at ComponentElement.performRebuild(framework.dart:5512)
   at Element.rebuild(framework.dart:5203)
   at ComponentElement._firstBuild(framework.dart:5469)
   at ComponentElement.mount(framework.dart:5463)
   at Element.inflateWidget(framework.dart:4340)
   at Element.updateChild(framework.dart:3849)
   at ComponentElement.performRebuild(framework.dart:5512)
   at Element.rebuild(framework.dart:5203)
   at ComponentElement._firstBuild(framework.dart:5469)
   at ComponentElement.mount(framework.dart:5463)
   at Element.inflateWidget(framework.dart:4340)
   at Element.updateChild(framework.dart:3849)
   at _LayoutBuilderElement._layout.layoutCallback(layout_builder.dart:155)
   at BuildOwner.buildScope(framework.dart:2845)
   at _LayoutBuilderElement._layout(layout_builder.dart:173)
   at RenderObject.invokeLayoutCallback.<fn>(object.dart:2688)
   at PipelineOwner._enableMutationsToDirtySubtrees(object.dart:1097)
   at RenderObject.invokeLayoutCallback(object.dart:2688)
   at RenderConstrainedLayoutBuilder.rebuildIfNecessary(layout_builder.dart:248)
   at _RenderLayoutBuilder.performLayout(layout_builder.dart:331)
   at RenderObject.layout(object.dart:2577)
   at MultiChildLayoutDelegate.layoutChild(custom_layout.dart:173)
   at _ScaffoldLayout.performLayout(scaffold.dart:1097)
   at MultiChildLayoutDelegate._callPerformLayout(custom_layout.dart:237)
   at RenderCustomMultiChildLayoutBox.performLayout(custom_layout.dart:404)
   at RenderObject.layout(object.dart:2577)
   at RenderProxyBoxMixin.performLayout(proxy_box.dart:105)
   at RenderObject.layout(object.dart:2577)
   at RenderProxyBoxMixin.performLayout(proxy_box.dart:105)
   at _RenderCustomClip.performLayout(proxy_box.dart:1426)
   at RenderObject.layout(object.dart:2577)
   at RenderPadding.performLayout(shifted_box.dart:239)
   at RenderObject.layout(object.dart:2577)
   at RenderProxyBoxMixin.performLayout(proxy_box.dart:105)
   at RenderObject._layoutWithoutResize(object.dart:2416)
   at PipelineOwner.flushLayout(object.dart:1051)
   at PipelineOwner.flushLayout(object.dart:1064)
   at RendererBinding.drawFrame(binding.dart:577)
   at WidgetsBinding.drawFrame(binding.dart:1138)
   at RendererBinding._handlePersistentFrameCallback(binding.dart:443)
   at SchedulerBinding._invokeFrameCallback(binding.dart:1392)
   at SchedulerBinding.handleDrawFrame(binding.dart:1313)
   at SchedulerBinding._handleDrawFrame(binding.dart:1171)
HayesGordon commented 1 week ago

Hi @daniel102102, which version of the Rive-Flutter runtime are you using? And did this recently start after updating?

kaptnkoala commented 1 week ago

Hi @HayesGordon, we also see this error occur in our production app after updating the rive dependency from 0.13.1 to 0.13.7 (which bumps the rive_common dependency from 0.3.3 to 0.4.9 under the hood). We did not see any problems regarding the Rive-Flutter runtime before, it recently started to occur after the mentioned update.

Like @daniel102102 mentioned this problem happens to 99% on devices running Android 6.

HayesGordon commented 5 days ago

@kaptnkoala I'd just like to confirm a few things.

One potentially relevant issue I've found is: https://github.com/simolus3/drift/issues/895#issuecomment-720195005

More info here: https://github.com/simolus3/drift/issues/895#issuecomment-720195005

We could look into doing something similar (it's a bit of a hack) but I'm unable to verify my side if this will work as I cannot reproduce the issue. Can you reproduce this issue on your end, or are you only seeing this in production?

daniel102102 commented 5 days ago

Hi @HayesGordon. We are using rive: 0.13.8 and rive_common: ^0.4.9. Massive crashes started in last days, after switching to new version. Before crash was avialble but was rare.

HayesGordon commented 5 days ago

Could you please confirm if you're Rive file makes use of Rive Text or Rive Audio. Answering this is important to help me pinpoint the issue.

Could you also answer the other questions if possible.

kaptnkoala commented 5 days ago

Hey @HayesGordon, please find the answers to your questions attached.

Does your Rive file contain Rive Text or Rive Audio?

No, in our case the affected rive files are not using Rive Text or Rive Audio?

Are you specifying a buildType or using the defaults? For example:

Yes, we are not building our app for the 'x86' architecture, so our release NDK settings look like this:

    buildTypes {
        release {
            ndk {
                abiFilters 'armeabi-v7a','arm64-v8a','x86_64'
                debugSymbolLevel 'FULL'
            }
        }
    }

Are you passing in any additional flags when building the release APK?

We only pass additional --dart-define Flags when building the release APK?

You mentioned that you verified that the release APK in production contained the .so files?

Yes, i can verify that the generated APK contains the librive_text.so in the 'lib/arm64-v8a', 'lib/armabi-v7a' and 'lib/x86_64' directories.

Which version of Flutter are you using?

We are using Flutter 3.19.6

I am not exactly sure what workaround you are suggesting, because you seemed to have referenced the same issue comment twice. We also do not have Apps at Hand here right now and can reproduce the issue, we only see it as error with high volume in our reporting tools. For the moment we have reverted back to rive 0.13.1, which mitigated the problem for the production app.

HayesGordon commented 5 days ago

Thanks for the info @kaptnkoala. The other link I wanted to send was this: https://github.com/simolus3/sqlite3.dart/tree/main/sqlcipher_flutter_libs#problems-on-android-6

In older versions of Flutter, Android 6 caused issues, old documentation mentions:

If you build an App Bundle Edit android/gradle.properties and add the flag: android.bundle.enableUncompressedNativeLibs=false.

If you build an APK Make sure android/app/src/AndroidManifest.xml doesn’t set android:extractNativeLibs=false in the <application> tag.

But I do not know if that is still relevant.

We can push out the same solution that sqlite3 did. It requires loading the library natively from Kotlin and then accessing it through the data directory.

I'll let you know here once that is out.

kaptnkoala commented 5 days ago

We have set the flag android.bundle.enableUncompressedNativeLibs=false in the android/gradle.properties and not set the android:extractNativeLibs=false Flag in AndroidManifest.

Has anything changed between version 0.13.1 and 0.13.8 how the livrive_text.so is loaded, that this problem is starting to gain track now and not in the previous version. I am not sure, if this is really the best solution to the problem. I will ping a colleague that is more familiar with the native parts of Flutter. @blaugold What do you think about this?

HayesGordon commented 5 days ago

After version 0.13.1 the requirement to load in these libraries changed. Previously the native libraries were only loaded if a .riv file contained Rive Text. We optimistically checked to see if the .riv file had Rive Text in it - if not we would not initliaze the library.

But since then we've introduced more features, specifically a new layout engine, which requires Rive Flutter to always load + initialize the native library.

That is why you're seeing it now and not before.

On the Rive Android runtime we had similar issues in the past where Android has issues linking these libraries. There exists a package for Android called ReLinker which we use to ensure the libraries are linked on older devices.

This is the first/only report about Rive Flutter not working on older Android devices.

HayesGordon commented 5 days ago

Link to the PR that made the change to require the libraries to always be loaded: https://github.com/rive-app/rive-flutter/commit/a22fc5f0471551f45d9c2534ad70f99b0f6a5810

centy commented 4 days ago

Have you tried https://github.com/KeepSafe/ReLinker ?

If your app includes native libraries, and your minimum SDK is below API 23 (Marshmallow), you need ReLinker.

There are a number of different bugs addressed by ReLinker; the last of these was resolved as of Marshmallow. As long as your app's min SDK is at or above it, loading libraries via System.loadLibrary("foo") is safe.

blaugold commented 3 hours ago

We are using minSdkVersion 23, so we should not need ReLinker.

@kaptnkoala Those workarounds feel a bit hacky, but the only solution for those older Android versions. 🫠