In my project I've achieved this by creating a build variant that bundles the generated RN code within the APK.
Generating the bundle.js
Using wget I grab the RN code from the Node.JS local server and save it as bundle.js
:
wget "http://127.0.0.1:8081/index.android.bundle?platform=android&dev=false" -O bundle.js
Adding bundle.js to the project
I add the bundle.js
file to assets/
dir.
Creating a build variant that points RN to the file
I don;t wanna manually change my code whenever I wanna switch between local (bundle.js) and live versions. So I've created a build variant for this case.
There is an extensive tutorial on build variants here, so I'll just go over the cruicial details only.
In my build.gradle
, under the android
node, I've added:
productFlavors {
bundled {
buildConfigField 'boolean', 'BUNDLED', 'true'
buildConfigField 'String', 'DEV_HOST', "null"
}
}
This automatically generates BuildConfig.java
(more about this here):
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "....";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "bundled";
public static final int VERSION_CODE = ...;
public static final String VERSION_NAME = ...;
// Fields from product flavor: bundled
public static final boolean BUNDLED = true;
}
Pointing RN to bundle.js
So now I fire up RN based on my build variant:
boolean bundled = BuildConfig.BUNDLED;
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("bundle.js")
.setJSMainModuleName("index.android")
.setJSBundleFile(bundled ? "assets://bundle.js" : null)
.addPackage(new MainReactPackage(false))
.addPackage(mInnerItemReactPackage)
.setUseDeveloperSupport(bundled ? false : ConfigSupplier.isDebuggable())
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
Generating the APK
I choose the correct build variant from the Build Variants screen:

And then proceed as usual by clicking Build -> Build APK.
I might add a more detailed blog post later.