From abb81eb2702a01c103018b0d943fe5fec6c17ea3 Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Thu, 7 Jan 2016 09:32:46 -0800 Subject: [PATCH] Add support for split build per architecture Summary: This allows everyone to deploy significantly smaller APKs to they Play Store by building separate APKs for ARM, x86 architectures. For a simple app, a release APK minified with Produard: - Universal APK is **7MB** - x86 APK is **4.6MB** (34% reduction) - ARM APK is **3.7MB** (47% reduction) Created a sample project, uncommented `// include "armeabi-v7a", 'x86'`: cd android ./gradlew assembleDebug Three APKs were created, unzipped each: one has only x86 binaries, one has ARM binaries, one has both. ./gradlew assembleRelease Three APKs were created, JS bundle is correcly added to assets. react-native run-android The correct APK is installed on the emulator and the app runs fine (Gradle output: "Installing APK 'app-x86-debug.apk'"). With the line commented out the behavior is exactly the same as before, only one universal APK is built. Checked that version codes are set correctly as described in http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits http://developer.android.com/intl/ru/google/play/publishing/multiple-apks.html Closes https://github.com/facebook/react-native/pull/5160 Reviewed By: svcscm Differential Revision: D2811443 Pulled By: mkonicek fb-gh-sync-id: 97b22b9cd567e53b8adac36669b90768458b7a55 --- .../templates/src/app/build.gradle | 41 ++++++++++++++++++- .../templates/src/app/react.gradle | 23 ++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/local-cli/generator-android/templates/src/app/build.gradle b/local-cli/generator-android/templates/src/app/build.gradle index 1298bb3f4..b68fc50c5 100644 --- a/local-cli/generator-android/templates/src/app/build.gradle +++ b/local-cli/generator-android/templates/src/app/build.gradle @@ -1,5 +1,7 @@ apply plugin: "com.android.application" +import com.android.build.OutputFile + /** * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets. * These basically call `react-native bundle` with the correct arguments during the Android build @@ -49,6 +51,22 @@ apply plugin: "com.android.application" apply from: "react.gradle" +/** + * Set this to true to create three separate APKs instead of one: + * - A universal APK that works on all devices + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = true + android { compileSdkVersion 23 buildToolsVersion "23.0.1" @@ -63,12 +81,33 @@ android { abiFilters "armeabi-v7a", "x86" } } + splits { + abi { + enable enableSeparateBuildPerCPUArchitecture + universalApk true + reset() + include "armeabi-v7a", "x86" + } + } buildTypes { release { - minifyEnabled false // Set this to true to enable Proguard + 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: + // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits + def versionCodes = ["armeabi-v7a":1, "x86":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 + } + } + } } dependencies { diff --git a/local-cli/generator-android/templates/src/app/react.gradle b/local-cli/generator-android/templates/src/app/react.gradle index 1e08b00f1..f2152d1f6 100644 --- a/local-cli/generator-android/templates/src/app/react.gradle +++ b/local-cli/generator-android/templates/src/app/react.gradle @@ -74,14 +74,33 @@ task bundleReleaseJsAndAssets(type: Exec) { enabled config.bundleInRelease ?: true } +void runBefore(String dependentTaskName, Task task) { + Task dependentTask = tasks.findByPath(dependentTaskName); + if (dependentTask != null) { + dependentTask.dependsOn task + } +} + gradle.projectsEvaluated { + // hook bundleDebugJsAndAssets into the android build process + bundleDebugJsAndAssets.dependsOn mergeDebugResources bundleDebugJsAndAssets.dependsOn mergeDebugAssets - processDebugResources.dependsOn bundleDebugJsAndAssets + + runBefore('processArmeabi-v7aDebugResources', bundleDebugJsAndAssets) + runBefore('processX86DebugResources', bundleDebugJsAndAssets) + runBefore('processUniversalDebugResources', bundleDebugJsAndAssets) + runBefore('processDebugResources', bundleDebugJsAndAssets) // hook bundleReleaseJsAndAssets into the android build process + bundleReleaseJsAndAssets.dependsOn mergeReleaseResources bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets - processReleaseResources.dependsOn bundleReleaseJsAndAssets + + runBefore('processArmeabi-v7aReleaseResources', bundleReleaseJsAndAssets) + runBefore('processX86ReleaseResources', bundleReleaseJsAndAssets) + runBefore('processUniversalReleaseResources', bundleReleaseJsAndAssets) + runBefore('processReleaseResources', bundleReleaseJsAndAssets) + }