react-native: Hermes does not work when extracting apk from android app bundles (.abb)

Enabling Hermes on android builds configured to extract apk from app bundles (.abb) will freeze on app start.

React Native version: System: OS: macOS 10.14.6 CPU: (4) x64 Intel® Core™ i5-7267U CPU @ 3.10GHz Memory: 6.54 GB / 16.00 GB Shell: 5.3 - /bin/zsh Binaries: Node: 10.16.0 - ~/.nvm/versions/node/v10.16.0/bin/node Yarn: 1.17.0 - /usr/local/bin/yarn npm: 6.9.0 - ~/.nvm/versions/node/v10.16.0/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 12.4, macOS 10.14, tvOS 12.4, watchOS 5.3 Android SDK: API Levels: 23, 26, 27, 28 Build Tools: 26.0.3, 27.0.3, 28.0.2, 28.0.3 System Images: android-22 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom IDEs: Android Studio: 3.4 AI-183.6156.11.34.5692245 Xcode: 10.3/10G8 - /usr/bin/xcodebuild npmPackages: react: 16.8.6 => 16.8.6 react-native: ^0.60.4 => 0.60.4 npmGlobalPackages: create-react-native-module: 0.5.0 create-react-native-web-app: 0.1.11 react-native-cli: 2.0.1 react-native-git-upgrade: 0.2.7

Steps To Reproduce

  1. Init new RN project.
  2. Change build configuration in android studio from default apk to apk from app bundle
  3. Build app.
  4. Install extracted apk on device.
  5. Run app and it hangs on start screen.
  6. Disabling hermes works fine with same build configuration.

Describe what you expected to happen: Extracted apks should work

Snack, code example, screenshot, or link to a repository:

D/SoLoader: About to load: libjscexecutor.so
    libjscexecutor.so not found on /data/data/com.test/lib-main
D/SoLoader: libjscexecutor.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libfb.so, libreactnativejni.so, libjsc.so, libjsinspector.so, libfolly_json.so, libglog.so, libc++_shared.so, liblog.so, libc.so, libm.so, libdl.so]
D/SoLoader: About to load: libfb.so
    libfb.so not found on /data/data/com.test/lib-main
    libfb.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libc++_shared.so, liblog.so, libdl.so, libandroid.so, libc.so, libm.so]
    About to load: libc++_shared.so
D/SoLoader: libc++_shared.so not found on /data/data/com.test/lib-main
D/SoLoader: libc++_shared.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libc.so, libdl.so]
    About to load: libc.so
    libc.so not found on /data/data/com.test/lib-main
    libc.so not found on /data/data/com.test/lib-0
D/SoLoader: libc.so not found on /data/data/com.test/lib-1
    libc.so not found on /data/data/com.test/lib-2
    libc.so not found on /data/data/com.test/lib-3
    libc.so not found on /data/app/com.test-lS2rnOAKng6NlOapH7INNw==/lib/arm
    libc.so not found on /system/vendor/lib
D/SoLoader: libc.so found on /system/lib
    libc.so loaded implicitly
    Loaded: libc.so
    About to load: libdl.so
    libdl.so not found on /data/data/com.test/lib-main
    libdl.so not found on /data/data/com.test/lib-0
    libdl.so not found on /data/data/com.test/lib-1
D/SoLoader: libdl.so not found on /data/data/com.test/lib-2
    libdl.so not found on /data/data/com.test/lib-3
    libdl.so not found on /data/app/com.test-lS2rnOAKng6NlOapH7INNw==/lib/arm
    libdl.so not found on /system/vendor/lib
    libdl.so found on /system/lib
    libdl.so loaded implicitly
    Loaded: libdl.so
D/SoLoader: Loaded: libc++_shared.so
    About to load: liblog.so
D/SoLoader: liblog.so not found on /data/data/com.test/lib-main
    liblog.so not found on /data/data/com.test/lib-0
    liblog.so not found on /data/data/com.test/lib-1
    liblog.so not found on /data/data/com.test/lib-2
D/SoLoader: liblog.so not found on /data/data/com.test/lib-3
D/SoLoader: liblog.so not found on /data/app/com.test-lS2rnOAKng6NlOapH7INNw==/lib/arm
    liblog.so not found on /system/vendor/lib
    liblog.so found on /system/lib
    liblog.so loaded implicitly
    Loaded: liblog.so
    About to load: libandroid.so
    libandroid.so not found on /data/data/com.test/lib-main
D/SoLoader: libandroid.so not found on /data/data/com.test/lib-0
    libandroid.so not found on /data/data/com.test/lib-1
    libandroid.so not found on /data/data/com.test/lib-2
    libandroid.so not found on /data/data/com.test/lib-3
    libandroid.so not found on /data/app/com.test-lS2rnOAKng6NlOapH7INNw==/lib/arm
D/SoLoader: libandroid.so not found on /system/vendor/lib
    libandroid.so found on /system/lib
    libandroid.so loaded implicitly
    Loaded: libandroid.so
    About to load: libm.so
    libm.so not found on /data/data/com.test/lib-main
    libm.so not found on /data/data/com.test/lib-0
D/SoLoader: libm.so not found on /data/data/com.test/lib-1
    libm.so not found on /data/data/com.test/lib-2
    libm.so not found on /data/data/com.test/lib-3
    libm.so not found on /data/app/com.test-lS2rnOAKng6NlOapH7INNw==/lib/arm
    libm.so not found on /system/vendor/lib
    libm.so found on /system/lib
    libm.so loaded implicitly
D/SoLoader: Loaded: libm.so
D/SoLoader: About to load: libfb.so
D/SoLoader: libfb.so not found on /data/data/com.test/lib-main
    libfb.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libc++_shared.so, liblog.so, libdl.so, libandroid.so, libc.so, libm.so]
I/zygote: Thread[1,tid=10033,Native,Thread*=0xe9a7c000,peer=0x72bcc700,"main"] recursive attempt to load library "/data/user/0/com.test/lib-0/libfb.so"
D/SoLoader: Loaded: libfb.so
    Loaded: libfb.so
    About to load: libreactnativejni.so
D/SoLoader: libreactnativejni.so not found on /data/data/com.test/lib-main
    libreactnativejni.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libglog_init.so, libyoga.so, libfb.so, libjsinspector.so, libfolly_json.so, libglog.so, libc++_shared.so, libandroid.so, liblog.so, libc.so, libm.so, libdl.so]
    About to load: libglog_init.so
    libglog_init.so not found on /data/data/com.test/lib-main
D/SoLoader: libglog_init.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libglog.so, libc++_shared.so, liblog.so, libc.so, libm.so, libdl.so]
    About to load: libglog.so
D/SoLoader: libglog.so not found on /data/data/com.test/lib-main
    libglog.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libc++_shared.so, libc.so, libm.so, libdl.so]
D/SoLoader: Loaded: libglog.so
D/SoLoader: Loaded: libglog_init.so
    About to load: libyoga.so
    libyoga.so not found on /data/data/com.test/lib-main
    libyoga.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libfb.so, libc++_shared.so, libandroid.so, liblog.so, libc.so, libm.so, libdl.so]
D/SoLoader: Loaded: libyoga.so
    About to load: libjsinspector.so
    libjsinspector.so not found on /data/data/com.test/lib-main
    libjsinspector.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libc++_shared.so, libc.so, libm.so, libdl.so]
D/SoLoader: Loaded: libjsinspector.so
D/SoLoader: About to load: libfolly_json.so
    libfolly_json.so not found on /data/data/com.test/lib-main
    libfolly_json.so found on /data/data/com.test/lib-0
D/SoLoader: Loading lib dependencies: [libglog.so, libc++_shared.so, libc.so, libm.so, libdl.so]
D/SoLoader: Loaded: libfolly_json.so
D/SoLoader: Loaded: libreactnativejni.so
    About to load: libjsc.so
D/SoLoader: libjsc.so not found on /data/data/com.test/lib-main
    libjsc.so not found on /data/data/com.test/lib-0
    libjsc.so not found on /data/data/com.test/lib-1
    libjsc.so not found on /data/data/com.test/lib-2
D/SoLoader: libjsc.so not found on /data/data/com.test/lib-3
    libjsc.so not found on /data/app/com.test-lS2rnOAKng6NlOapH7INNw==/lib/arm
    libjsc.so not found on /system/vendor/lib
    libjsc.so not found on /system/lib

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 68
  • Comments: 43 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Yup, can confirm, just happened to me as well.

Same thing happened to me.

Specifically, a call to SoLoader.loadLibrary("jscexecutor") (here) call was blocking indefinitely.

In my case, jscexecutor.so was bundled, however the libjsc.so was not. Thing is, for some reason this didn’t cause the SoLoader.loadLibrary call to throw (I assume this is the expected behaviour).

Then just to test, I explicitly removed the jscexecutor.so lib from the build:

android {
  packagingOptions{
    exclude '**/libjscexecutor.so'
  }
}

This solved the problem SoLoader.loadLibrary threw an exception (as libjscexecutor couldn’t be found) and HermesExecutorFactory was used instead.

Of course this is not a real fix to the problem as libjscexecutor is added internally by the react artifact and I have no idea of what side effects this can cause, but should point to the right direction when fixing it.

Also happens to me

Same issue 👍

Adding the following packaging options to your app gradle file causes APKs generated from AABs to have the same set of .so libraries as old fashioned APKs.

// Bug with AAB generation causes JSC and Hermes debug libraries to be included
// https://github.com/facebook/react-native/issues/25927
    if (getGradle().getStartParameter().getTaskRequests().toString().toLowerCase().contains("bundle")) {
        packagingOptions {
            exclude '**/libhermes-inspector.so'
            exclude '**/libhermes-executor-debug.so'
            exclude '**/libjscexecutor.so'
        }
    }

So far our app seems happy with that change.

(Updated on 10/1/2019 to only apply the packaging options when building an app bundle)

same issue here

Still launching to only white screen when downloading from google play.

Changing the androidBuildToolVersion fix it for me. Initially, I was using 3.5.2 the build was completing but the app was getting stuck on the splash screen. So I’ve changed the build tool version to 3.4.2 now everything seems fine

Atleast true for me. You guys can try it once and see if it works for you.

A little workaround is enable:

def enableSeparateBuildPerCPUArchitecture = true

in android/app/build.gradle

and submit all generates apks to PlayStore

I managed to solve this with a little extra tweak from @AndrewJack’s solution as my project has custom product flavors. Thanks!

- def targetVariant = ".*/merged_native_libs/${targetPath}/.*"
+ def targetVariant = ".*/merged_native_libs/${variant.name.uncapitalize()}/.*"

@smacgregor worked for me 👍

Edit: take that back. This worked when I built the release aab locally using fastlane, but failed after releasing to the beta store and installing from there. No idea what would be different.

@smacgregor your solution is not working, i think we need to see other options.

@gabrielhuff You’re on to something there. include "**/libjsc*.so" in react.gradle is looking for libjscexecutor.so to delete, along with some other files.

I’ve been testing modifying the last bit of the react.gradle script.

Here’s what I have so far:

        def isRelease = targetName.toLowerCase().contains("release")
        def libDir = "$buildDir/intermediates/merged_native_libs/"
        def vmSelectionAction = {
            fileTree(libDir).matching {
                if (enableHermes) {
                    // For Hermes, delete all the libjsc* files
                    include "**/libjsc*.so"

                    if (isRelease) {
                        // Reduce size by deleting the debugger/inspector
                        include '**/libhermes-inspector.so'
                        include '**/libhermes-executor-debug.so'
                    } else {
                        // Release libs take precedence and must be removed
                        // to allow debugging
                        include '**/libhermes-executor-release.so'
                    }
                } else {
                    // For JSC, delete all the libhermes* files
                    include "**/libhermes*.so"
                }
            }.visit { details ->
                def targetVariant = ".*/merged_native_libs/${targetPath}/.*"
                def path = details.file.getAbsolutePath().replace(File.separatorChar, '/' as char)
                if (path.matches(targetVariant) && details.file.isFile()) {
                  details.file.delete()
                }
            }
        }

        def mergeNativeLibs = tasks.findByName("merge${targetName}NativeLibs")
        if (mergeNativeLibs != null) {
            mergeNativeLibs.doLast(vmSelectionAction)
        }

I’ve only tested when using app bundles & gradle plugin 3.5.0 so far.

When using app bundles the intermediates directory changes from transforms to merged_native_libs (or when using a newer gradle plugin?)