Pytorch not compatible with React-native library

Arun_Kumar1: <p>I’ve been using react native for one of my module.Recently we started using Pytorch . Pytorch along with react native is crashing.<br>
Below is the error</p>
<p>java.lang.UnsatisfiedLinkError: couldn’t find DSO to load: libpytorch_jni.so caused by: dlopen failed: cannot locate symbol “_ZN8facebook3jni10JByteOrder11nativeOrderEv” referenced by “/data/app/*****-4ZGDZJcLItKdhIsz3hj2rQ==/lib/arm64/libpytorch_jni.so”.</p>
<p>Please help me.I am in great urgency.</p>

IvanKobzarev: <p>Hello, <a class="mention" href="/u/arun_kumar1">@Arun_Kumar1</a></p>
<p>Could you please share your build setup: gradle files, CMakeLists.txt ( if you have it)?</p>
<p>Both react native and pytorch android use fbjni library, while “_ZN8facebook3jni10JByteOrder11nativeOrderEv” was added for pytorch android, it looks like system loads first react native libfbjni.so that does not have JByteOrder::nativeOrder method which is needed for libpytorch_jni.so</p>

Arun_Kumar1: <p>Hi <a class="mention" href="/u/ivankobzarev">@IvanKobzarev</a>,</p>
<p>Please check the below build.gradle file content.I don’t have CMakeLists.txt.</p>
<p>apply plugin: “com.android.application”</p>
<p>import com.android.build.OutputFile</p>
<p>/**</p>
<ul>
<li>The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets</li>
<li>and bundleReleaseJsAndAssets).</li>
<li>These basically call <code>react-native bundle</code> with the correct arguments during the Android build</li>
<li>cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the</li>
<li>bundle directly from the development server. Below you can see all the possible configurations</li>
<li>and their defaults. If you decide to add a configuration block, make sure to add it before the</li>
<li>
<code>apply from: "../../node_modules/react-native/react.gradle"</code> line.</li>
<li>
</li>
<li>project.ext.react = [</li>
<li>// the name of the generated asset file containing your JS bundle</li>
<li>bundleAssetName: “index.android.bundle”,</li>
<li>
</li>
<li>// the entry file for bundle generation</li>
<li>entryFile: “index.android.js”,</li>
<li>
</li>
<li>// whether to bundle JS and assets in debug mode</li>
<li>bundleInDebug: false,</li>
<li>
</li>
<li>// whether to bundle JS and assets in release mode</li>
<li>bundleInRelease: true,</li>
<li>
</li>
<li>// whether to bundle JS and assets in another build variant (if configured).</li>
<li>// See <a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants" rel="nofollow noopener">http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants</a>
</li>
<li>// The configuration property can be in the following formats</li>
<li>//         ‘bundleIn${productFlavor}${buildType}’</li>
<li>//         ‘bundleIn${buildType}’</li>
<li>// bundleInFreeDebug: true,</li>
<li>// bundleInPaidRelease: true,</li>
<li>// bundleInBeta: true,</li>
<li>
</li>
<li>// whether to disable dev mode in custom build variants (by default only disabled in release)</li>
<li>// for example: to disable dev mode in the staging build type (if configured)</li>
<li>devDisabledInStaging: true,</li>
<li>// The configuration property can be in the following formats</li>
<li>//         ‘devDisabledIn${productFlavor}${buildType}’</li>
<li>//         ‘devDisabledIn${buildType}’</li>
<li>
</li>
<li>// the root of your project, i.e. where “package.json” lives</li>
<li>root: “…/…/”,</li>
<li>
</li>
<li>// where to put the JS bundle asset in debug mode</li>
<li>jsBundleDirDebug: “$buildDir/intermediates/assets/debug”,</li>
<li>
</li>
<li>// where to put the JS bundle asset in release mode</li>
<li>jsBundleDirRelease: “$buildDir/intermediates/assets/release”,</li>
<li>
</li>
<li>// where to put drawable resources / React Native assets, e.g. the ones you use via</li>
<li>// require(’./image.png’)), in debug mode</li>
<li>resourcesDirDebug: “$buildDir/intermediates/res/merged/debug”,</li>
<li>
</li>
<li>// where to put drawable resources / React Native assets, e.g. the ones you use via</li>
<li>// require(’./image.png’)), in release mode</li>
<li>resourcesDirRelease: “$buildDir/intermediates/res/merged/release”,</li>
<li>
</li>
<li>// by default the gradle tasks are skipped if none of the JS files or assets change; this means</li>
<li>// that we don’t look at files in android/ or ios/ to determine whether the tasks are up to</li>
<li>// date; if you have any other folders that you want to ignore for performance reasons (gradle</li>
<li>// indexes the entire tree), add them here. Alternatively, if you have JS files in android/</li>
<li>// for example, you might want to remove it from here.</li>
<li>inputExcludes: [“android/<strong>", "ios/</strong>”],</li>
<li>
</li>
<li>// override which node gets called and with what additional arguments</li>
<li>nodeExecutableAndArgs: [“node”],</li>
<li>
</li>
<li>// supply additional arguments to the packager</li>
<li>extraPackagerArgs: []</li>
<li>]<br>
*/</li>
</ul>
<p>project.ext.react = [<br>
entryFile: “index.js”,<br>
enableHermes: true,  // HERE!<br>
]</p>
<p>apply from: “…/…/node_modules/react-native/react.gradle”</p>
<p>/**</p>
<ul>
<li>Set this to true to create two separate APKs instead of one:</li>
<li>
<ul>
<li>An APK that only works on ARM devices</li>
</ul>
</li>
<li>
<ul>
<li>An APK that only works on x86 devices</li>
</ul>
</li>
<li>The advantage is the size of the APK is reduced by about 4MB.</li>
<li>Upload all the APKs to the Play Store and people will download</li>
<li>the correct one based on the CPU architecture of their device.<br>
*/<br>
def enableSeparateBuildPerCPUArchitecture = false</li>
</ul>
<p>/**</p>
<ul>
<li>Run Proguard to shrink the Java bytecode in release builds.<br>
*/<br>
def enableProguardInReleaseBuilds = false</li>
</ul>
<p>android {<br>
compileSdkVersion rootProject.ext.compileSdkVersion<br>
buildToolsVersion ‘28.0.3’</p>
<pre><code>defaultConfig {
    applicationId "com.progressreport"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode 1
    versionName "1.0"
    ndk {
        abiFilters 'x86','armeabi-v7a','arm64-v8a','x86_64'
    }
}

packagingOptions {
    pickFirst "**/libfbjni.so"

}
splits {

    // Configures multiple APKs based on screen density.
    splits {
        abi {
            enable true
            reset()
            include 'armeabi-v7a'
            universalApk false
        }
    }
}
buildTypes {
    release {
        minifyEnabled enableProguardInReleaseBuilds
        proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
    }
}
compileOptions {
    sourceCompatibility 1.8
    targetCompatibility 1.8
}
packagingOptions {
    pickFirst '/armeabi-v7a/libc++_shared.so'
    pickFirst '/x86/libc++_shared.so'
    pickFirst '/arm64-v8a/libc++_shared.so'
    pickFirst '/x86_64/libc++_shared.so'
    pickFirst '/x86/libjsc.so'
    pickFirst '/armeabi-v7a/libjsc.so'
    pickFirst '/arm64-v8a/libpytorch_jni.so'
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant -&gt;
    variant.outputs.each { output -&gt;
        // For each separate APK per architecture, set a unique version code as described here:
        // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
        def versionCodes = [ "x86":1,"x86_64":2,"armeabi-v7a":3,"arm64-v8a":2]
        def abi = output.getFilter(OutputFile.ABI)
        if (abi != null) {  // null for the universal-debug, universal-release variants
            output.versionCodeOverride =
                    versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
        }
    }
}
</code></pre>
<p>}</p>
<p>dependencies {<br>
implementation project(’:react-native-svg’)<br>
implementation project(’:lottie-react-native’)<br>
implementation project(’:react-native-localization’)<br>
implementation project(’:react-native-linear-gradient’)<br>
implementation project(’:react-native-vector-icons’)<br>
implementation project(’:react-native-gesture-handler’){}<br>
implementation fileTree(dir: “libs”, include: ["*.jar"])</p>
<pre><code>implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation ("com.facebook.react:react-native:+" ){
    exclude  module: 'fbjni-java-only'
} // From node_modules
def jscFlavor = 'org.webkit:android-jsc:+'
def enableHermes = project.ext.react.get("enableHermes", false);
if (enableHermes) {
    // for RN 0.61+
    def hermesPath = "$rootDir/../node_modules/hermes-engine/android/";
    debugImplementation files(hermesPath + "hermes-debug.aar")
    releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
    implementation jscFlavor
}
def useIntlJsc = false
if (useIntlJsc) {
    implementation ('org.webkit:android-jsc-intl:+')
} else {
    implementation ('org.webkit:android-jsc:+')
            {
                exclude group:'com.facebook.fbjni',module:  "fbjni-java-only-0.0.3"
            } // From node_modules/ From node_modules

}
implementation(name:'pytorch_android-1.5.0-SNAPSHOT', ext:'aar')
implementation(name:'pytorch_android_fbjni-1.5.0-SNAPSHOT', ext:'aar')
implementation 'com.facebook.soloader:nativeloader:0.8.0'


implementation "androidx.multidex:multidex:2.0.1"
</code></pre>
<p>}</p>
<p>// Run this once to be able to run the application with BUCK<br>
// puts all compile dependencies into folder libs for BUCK to use<br>
task copyDownloadableDepsToLibs(type: Copy) {<br>
from configurations.compile<br>
into ‘libs’<br>
}</p>

IvanKobzarev: <p>Hi <a class="mention" href="/u/arun_kumar1">@Arun_Kumar1</a>,<br>
I have reproduced your problem. We have contacted react-native team to align our libfbjni.so’s. It might take some time and updating to react-native master.</p>
<p>If you desperately need to unblock yourself you could try hacky way to use libfbjni.so from pytorch-android in react-native.</p>
<ol>
<li>Downloading nightly build of pytorch android that contains libfbjni.so inside,</li>
</ol>
<pre><code class="lang-auto">wget -O pa.aar https://oss.sonatype.org/service/local/repositories/snapshots/content/org/pytorch/pytorch_android/1.5.0-SNAPSHOT/pytorch_android-1.5.0-20200324.090131-79.aar

# We will need absolute path to downloaded file
PA_AAR_ABSOLUTE_PATH=$(pwd)/pa.aar
</code></pre>
<ol start="2">
<li>Edit <code>node_modules/react-native/ReactAndroid/build.gradle</code>  (<a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle#L368" rel="nofollow noopener">https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle#L368</a>) changing <code>task extractJNIFiles</code> which is at the moment is used only for fbjni</li>
</ol>
<pre><code class="lang-auto">copy {
    from zipTree(file)
    into "$projectDir/src/main/jni/first-party/$packageName/"
    include "jni/**/*"
}
</code></pre>
<p>to</p>
<pre><code class="lang-auto">copy {
    from zipTree(new File("${PA_AAR_ABSOLUTE_PATH}"))
    into "$projectDir/src/main/jni/first-party/$packageName/"
    include "jni/**/libfbjni.so"
}
</code></pre>
<p>where new File(…) argument is absolute path to pa.aar that was downloaded on step 1.<br>
It worked for me.<br>
(The main idea of this hack - to use libfbjni.so from pytorch-android)</p>
<p>I will reply here when react-native and pytorch-android libfbjni will be aligned.<br>
Sorry for inconvenience.</p>

Arun_Kumar1: <p>Thanks <a class="mention" href="/u/ivankobzarev">@IvanKobzarev</a> for quick followup.<br>
Will follow the same steps as mentioned to unblock ourselves for now.</p>

HugoGresse: <p>Hi, is there an update on the .so alignment between RN &amp; PyTorch? Or an issue to follow?<br>
I wanted to use PyTorch from RN but I’m blocked and don’t really want to force a fbjni that may cause issue in production for RN.</p>

HugoGresse: <p>After some more investigation, using the release 1.5.0 android, I was able to get the app to compile but not run the PyTorch. So I got almost the same issue but with a slightly different error message:</p>
<pre><code class="lang-auto">E/SoLoader: couldn't find DSO to load: libpytorch_jni.so caused by: dlopen failed: 
cannot locate symbol "_ZN8facebook3jni11JByteBuffer5orderENS0_9alias_refINS0_10JByteOrderEEE" 
referenced by "/data/app/com.offline-EWIa3xVhdQYckXATRsmgrw==/lib/arm64/libpytorch_jni.so"... result: 0
</code></pre>
<p>The symbol of <code>_ZN8facebook3jni11JByteBuffer5orderENS0_9alias_refINS0_10JByteOrderEEE</code> differ from <code>_ZN8facebook3jni10JByteOrder11nativeOrderEv</code> of the original question.</p>
<p>When trying the proposed solution (which is to get the fbjni from PyTorch rather than RN one, it produced the same error</p>

Arun_Kumar1: <p><a class="mention" href="/u/hugogresse">@HugoGresse</a> Please upgrade RN to latest version.If you are using custom build Pytorch library.<br>
Please do the following.</p>
<p>implementation(“com.facebook.react:react-native:0.62.2”){<br>
exclude  module: ‘fbjni-java-only’<br>
}</p>

duclh3: <p><a class="mention" href="/u/arun_kumar1">@Arun_Kumar1</a><br>
I make an upgrading to RN 0.62.2, but I still have the same error as <a class="mention" href="/u/hugogresse">@HugoGresse</a> mentioned.<br>
Do you have another way to fix this bug ?<br>
Sorry for my bad English!</p>

Sxela: <p>Guys, importing pytorch like that seems to work for me:</p>
<pre><code class="lang-auto">    implementation ('org.pytorch:pytorch_android:1.5.0'){
     exclude module: 'fbjni-java-only'
}
    implementation ('org.pytorch:pytorch_android_torchvision:1.5.0'){
     exclude module: 'fbjni-java-only'
}
    implementation ('org.pytorch:pytorch_android_fbjni:1.5.0'){
     exclude module: 'fbjni-java-only'
}
    implementation('com.facebook.react:react-native:+'){
     exclude module: 'fbjni-java-only'
}

</code></pre>
<p>I also have</p>
<pre><code class="lang-auto">android {
        packagingOptions {
	pickFirst '**/*.so'
}
}
</code></pre>
<p>so that it won’t go crazy over those multiple <code>libfbjni.so</code> I’m getting for some reason. Hope that helps!</p>

CodeSammich: <p>This worked for me! Thank you!!!</p>