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
This commit is contained in:
Martin Konicek 2016-01-07 09:32:46 -08:00 committed by facebook-github-bot-3
parent b064094687
commit abb81eb270
2 changed files with 61 additions and 3 deletions

View File

@ -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 {

View File

@ -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)
}