ignite icon indicating copy to clipboard operation
ignite copied to clipboard

When using Hermes in release build variants, Android crashes with java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libjscexecutor.so

Open jvgeee opened this issue 2 years ago • 3 comments

Describe the bug

As the title says, I'm using a build variant called development, which uses our release signing config and generally replicates a release build.

When I build the app locally in debug mode, it works fine. When I build the development build the app crashes immediately, and in Android Studio I see:

--------- beginning of crash E/AndroidRuntime: FATAL EXCEPTION: main Process: com.appname.development, PID: 4513 java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libjscexecutor.so SoSource 0: com.facebook.soloader.DirectorySoSource[root = /data/app/~~yknNsxEbOR9vWgYxlcKx6g==/com.appname.development-uGOd6eC09Qm6p_dL_1XTtQ==/lib/arm64 flags = 0] SoSource 1: com.facebook.soloader.DirectApkSoSource[root = /data/app/~~yknNsxEbOR9vWgYxlcKx6g==/com.appname.development-uGOd6eC09Qm6p_dL_1XTtQ==/base.apk!/lib/arm64-v8a] SoSource 2: com.facebook.soloader.DirectorySoSource[root = /system/lib64 flags = 2] SoSource 3: com.facebook.soloader.DirectorySoSource[root = /vendor/lib64 flags = 2] Native lib dir: /data/app/~~yknNsxEbOR9vWgYxlcKx6g==/com.appname.development-uGOd6eC09Qm6p_dL_1XTtQ==/lib/arm64 result: 0 at com.facebook.soloader.SoLoader.doLoadLibraryBySoName(SoLoader.java:1098) at com.facebook.soloader.SoLoader.loadLibraryBySoNameImpl(SoLoader.java:914) at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:826) at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:773) at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:743) at com.facebook.react.jscexecutor.JSCExecutor.loadLibrary(JSCExecutor.java:24) at com.facebook.react.jscexecutor.JSCExecutor.(JSCExecutor.java:20) at com.facebook.react.jscexecutor.JSCExecutor.loadLibrary(Unknown Source:0) at com.facebook.react.ReactInstanceManagerBuilder.getDefaultJSExecutorFactory(ReactInstanceManagerBuilder.java:351) at com.facebook.react.ReactInstanceManagerBuilder.build(ReactInstanceManagerBuilder.java:318) at com.facebook.react.ReactNativeHost.createReactInstanceManager(ReactNativeHost.java:95) at expo.modules.ReactNativeHostWrapperBase.createReactInstanceManager(ReactNativeHostWrapperBase.kt:33) at com.facebook.react.ReactNativeHost.getReactInstanceManager(ReactNativeHost.java:42) at com.appname.MainApplication.onCreate(MainApplication.java:66) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1211) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6725) at android.app.ActivityThread.access$1500(ActivityThread.java:247) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2053) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7839) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

Ignite version

7.15.0

Additional info

This ONLY happens when using Hermes, and only happened after I upgraded to RN 0.68.2 (from 0.66.3 I think, where it worked fine).

Relevant parts of build.gradle:


// React native config setup
project.ext.envConfigFiles = [
    debug: ".env.development",
    development: ".env.development",
    qa: ".env.qa",
    release: ".env.production",
]

// later...

 buildTypes {
        debug {
            signingConfig signingConfigs.debug
            applicationIdSuffix ".development"
        }
    
        development {
            signingConfig signingConfigs.debug
            applicationIdSuffix ".development"
            matchingFallbacks = ['release']
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
        
        qa {
            signingConfig signingConfigs.release
            applicationIdSuffix ".qa"
            matchingFallbacks = ['release']
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
        
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.release
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            // https://developer.android.com/studio/build/configure-apk-splits.html
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        defaultConfig.versionCode * 1000 + versionCodes.get(abi)

            }
        }
    }

jvgeee avatar Sep 07 '22 06:09 jvgeee

Thanks for the issue, @jvgeee! Do you know if this is an Ignite-specific issue? If not, you'll probably want to ask in the #react-native channel in the IR Community Slack.

jamonholmgren avatar Sep 07 '22 17:09 jamonholmgren

Hey @jvgeee I recently had this issue with my Android build, it has to do with having multiple build variants.

You need to add the following:

...
    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        developmentImplementation files(hermesPath + "hermes-debug.aar") // Add
        qaImplementation files(hermesPath + "hermes-debug.aar") // Add
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
...

This way the android build references the correct hermes files for your custom build type

carlosa54 avatar Sep 07 '22 22:09 carlosa54

@carlosa54 unfortunately I'm already doing that

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        developmentImplementation files(hermesPath + "hermes-release.aar")
        qaImplementation files(hermesPath + "hermes-release.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")

    } else {
        implementation jscFlavor
    }

@jamonholmgren Not sure if it's Ignite or vanilla RN related tbh, I'm using your build templates and I can't find any matching bugs with generic RN builds so I'm assuming there is something funky going on with using build variants (potentially ones that use a release build profile?) + hermes

jvgeee avatar Sep 08 '22 03:09 jvgeee

Since this isn't entirely related to Ignite, and our default workflow out of the box, I'm going to close this issue for now.

However, in the future, we are working on a project called Ignite Cookbook, where we document common patterns in articles. I think multiple builds would be a good candidate for this. So I'm going to close the issue for now, but add the cookbook tag.

joshuayoes avatar Oct 04 '22 18:10 joshuayoes