Within andorid/app/build.gradle
file, define staging
build type, set bundleInStaging
to true
and produce unsigned APK by running ./gradlew assembleStaging
There are many different suggestions on how to use react-native bundle
command to produce React Native JavaScript bundle together with other resources and put them to the correct place so that ./assembleDebug
can take them and create unsigned APK.
Some of them use android/app/src
as a target location which results in having those files in an inappropriate place and in source control with React Native default .gitignore
. But they end up in the APK because this is where native Android apps put their static assets.
The rest of the suggestions, including official React Native CLI docs, put them correctly to the android/app/build
folder. But most of them do not result in JavaScript bundle being part of the APK with the latest React Native version.
The answer lies in react.gradle
file within react-native repository, where official Gradle tasks for bundling and copying reside.
bundleDebugJsAndAssets
Gradle task puts it's output by default to android/app/build/generated
directory:
- JS bundle:
android/app/build/generated/assets/react/debug/index.android.bundle
- Resources:
android/app/build/generated/res/react/debug
While this is the target location for the resources, it is not yet the final location for the bundle. It won't be picked up from here and placed to the APK.
copyDebugBundledJs
Gradle task takes care of that and copies these files to multiple locations within android/app/build/intermediates
directory:
.../intermediates/merged_assets/debug/out/index.android.bundle
.../intermediates/merged_assets/debug/mergeDebugAssets/out/index.android.bundle
.../intermediates/assets/debug/index.android.bundle
So why there are so many people trying to mimic this behavior with react-native bundle
command? Because both bundleDebugJsAndAssets
and copyDebugBundledJs
are skipped by default when running assembleDebug
task. The answer lies in the comments within android/app/build.gradle
file:
The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets and bundleReleaseJsAndAssets). These basically call
react-native bundle
with the correct arguments during the Android build cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the bundle directly from the development server.
This behavior is determined by bundleInDebug
configuration option, that is set to false by default because of the reasons mentioned above.
So where lies the solution?
Simply set bundleIn${buildType}
to true. But not for the debug build type which is used in react-native run-android
command. Define a new build type that produces unsigned APK:
andorid/app/build.gradle
file:
...
project.ext.react = [
...
bundleInStaging: true,
devDisabledInStaging: true,
]
...
android {
buildTypes {
...
staging {
signingConfig signingConfigs.debug
matchingFallbacks = ['debug']
}
...
And simply run the assemble Gradle task from the android
directory:
./gradlew assembleStaging
Now, whatever changes there will be in the future with the bundle and resource locations, you can have a restful sleep because React Native official Gradle tasks take care of that for you.
Hi, thank you for your awesome article.
I just followed your instructions. It worked well when I used this conig
But, I don't want to create new
buildType
. So, I tried with this configI just replaced
Staging
withDebug
onproject.ext.react
and I don't introduce new buildType onandroid.buildTypes
. I only use default buildTypes created by Android/ReactNative.The result is my debug app could run without development server. But, It still show development menu when I shake my device.
Do you have any idea?