Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Add support for split build per architecture #5160

Closed
wants to merge 1 commit into from
Closed

[Android] Add support for split build per architecture #5160

wants to merge 1 commit into from

Conversation

mkonicek
Copy link
Contributor

@mkonicek mkonicek commented Jan 6, 2016

This allows everyone to deploy significantly smaller APKs to the 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)

Test Plan:

Created a sample project, set enableSeparateBuildPerCPUArchitecture = true:

cd android
./gradlew assembleDebug

Three APKs were created, unzipped each: one has only x86 binaries,
one has ARM binaries, one has both.

./gradlew assembleRelease

In each APK the JS bundle is correctly present in 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 enableSeparateBuildPerCPUArchitecture = false the behavior is exactly the same as before,
only one universal APK is built.

Checked that version codes are set correctly as decribed 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

aapt l -a app-universal-debug.apk | grep android:version
    A: android:versionCode(0x0101021b)=(type 0x10)0x1

aapt l -a app-armeabi-v7a-debug.apk | grep android:version
    A: android:versionCode(0x0101021b)=(type 0x10)0x100001

aapt l -a app-x86-debug.apk | grep android:version
    A: android:versionCode(0x0101021b)=(type 0x10)0x200001

@facebook-github-bot
Copy link
Contributor

By analyzing the blame information on this pull request, we identified @foghina, @mkonicek and @tdzl2003 to be potential reviewers.

@facebook-github-bot facebook-github-bot added GH Review: review-needed CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. labels Jan 6, 2016
@mkonicek
Copy link
Contributor Author

mkonicek commented Jan 6, 2016

@foghina, @kmagiera Does this look fine to you?

@mkonicek
Copy link
Contributor Author

mkonicek commented Jan 6, 2016

cc @satya164, @brentvatne Who I think asked about this before the holidays.

@satya164
Copy link
Contributor

satya164 commented Jan 7, 2016

@mkonicek This is so cool. Will test this ASAP.

splits {
abi {
enable true
reset()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this do and do we really need it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reset(): reset the list of ABIs to be included to an empty string (this allows, in conjunctions with include, to indicate which one to use rather than which ones to ignore)

From http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be we should add a comment there, with the link?

@satya164
Copy link
Contributor

satya164 commented Jan 7, 2016

Just tested this. Working fine. Reduced APK size to 8.4 MB (arm) and 9.5 MB (x86) from 11.6 MB for me (without proguard) :)

@foghina
Copy link
Contributor

foghina commented Jan 7, 2016

@mkonicek perhaps we should also turn on proguard by default for release builds. If people are only writing JS they are not going to be affected, and people writing code probably already have it on. That would probably be a separate PR, though.

@satya164
Copy link
Contributor

satya164 commented Jan 7, 2016

I could never get proguard working though, facing the following issues,

:app:generateReleaseSources
:app:processReleaseJavaRes UP-TO-DATE
:app:compileReleaseJavaWithJavac
:app:compileReleaseNdk UP-TO-DATE
:app:proguardRelease
Warning: com.facebook.react.bridge.CatalystInstance$1: can't find referenced method 'void access$200(com.facebook.react.bridge.CatalystInstance,com.facebook.react.bridge.JavaScriptExecutor,com.facebook.react.bridge.JavaScriptModulesConfig)' in program class com.facebook.react.bridge.CatalystInstance
Warning: com.facebook.react.bridge.CatalystInstance$1: can't find enclosing method 'CatalystInstance(com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec,com.facebook.react.bridge.JavaScriptExecutor,com.facebook.react.bridge.NativeModuleRegistry,com.facebook.react.bridge.JavaScriptModulesConfig,com.facebook.react.bridge.JSBundleLoader,com.facebook.react.bridge.NativeModuleCallExceptionHandler)' in program class com.facebook.react.bridge.CatalystInstance
Warning: com.facebook.react.bridge.queue.MessageQueueThread$1: can't find enclosing method 'com.facebook.react.bridge.queue.MessageQueueThread startNewBackgroundThread(java.lang.String,com.facebook.react.bridge.queue.QueueThreadExceptionHandler)' in program class com.facebook.react.bridge.queue.MessageQueueThread
Warning: com.facebook.react.devsupport.DevServerHelper$3$1: can't find enclosing method 'void onFailure(com.squareup.okhttp.Request,java.io.IOException)' in program class com.facebook.react.devsupport.DevServerHelper$3
Warning: com.facebook.react.modules.storage.AsyncStorageModule$7: can't find referenced method 'boolean access$100(com.facebook.react.modules.storage.AsyncStorageModule)' in program class com.facebook.react.modules.storage.AsyncStorageModule
Warning: com.facebook.react.modules.storage.AsyncStorageModule$7: can't find referenced method 'com.facebook.react.modules.storage.ReactDatabaseSupplier access$000(com.facebook.react.modules.storage.AsyncStorageModule)' in program class com.facebook.react.modules.storage.AsyncStorageModule
Warning: com.facebook.react.uimanager.UIManagerModule$2: can't find referenced method 'com.facebook.react.uimanager.NativeViewHierarchyManager access$200(com.facebook.react.uimanager.UIManagerModule)' in program class com.facebook.react.uimanager.UIManagerModule
Warning: there were 7 unresolved references to program class members.
         Your input classes appear to be inconsistent.
         You may need to recompile the code.
         (http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
Exception while processing task 
java.io.IOException: Please correct the above warnings first.
    at proguard.Initializer.execute(Initializer.java:473)
    at proguard.ProGuard.initialize(ProGuard.java:233)
    at proguard.ProGuard.execute(ProGuard.java:98)
    at proguard.gradle.ProGuardTask.proguard(ProGuardTask.java:1074)
    at com.android.build.gradle.tasks.AndroidProGuardTask.doMinification(AndroidProGuardTask.java:139)
    at com.android.build.gradle.tasks.AndroidProGuardTask$1.run(AndroidProGuardTask.java:115)
    at com.android.builder.tasks.Job.runTask(Job.java:48)
    at com.android.build.gradle.tasks.SimpleWorkQueue$EmptyThreadContext.runTask(SimpleWorkQueue.java:41)
    at com.android.builder.tasks.WorkQueue.run(WorkQueue.java:227)
    at java.lang.Thread.run(Thread.java:745)
:app:dexRelease
:app:validateReleaseSigning
:app:packageArmeabi-v7aRelease FAILED

@mkonicek
Copy link
Contributor Author

mkonicek commented Jan 7, 2016

@satya164 Hopefully this fixes Proguard: #5146

@facebook-github-bot
Copy link
Contributor

@mkonicek updated the pull request.

3 similar comments
@facebook-github-bot
Copy link
Contributor

@mkonicek updated the pull request.

@facebook-github-bot
Copy link
Contributor

@mkonicek updated the pull request.

@facebook-github-bot
Copy link
Contributor

@mkonicek updated the pull request.

This allows everyone to deploy significantly smaller APKs
by building separate APKs for ARM, x86 architectures.

For a simple app, Both ARM, x86 APKs are about 4MB which is
about 50% reduction compared to the universal APK.

Test Plan:

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
(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 decribed 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

    aapt l -a ../android/app/build/outputs/apk/app-armeabi-v7a-debug.apk | grep android:version
        A: android:versionCode(0x0101021b)=(type 0x10)0x100001
        A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")

    aapt l -a ../android/app/build/outputs/apk/app-x86-debug.apk | grep android:version
        A: android:versionCode(0x0101021b)=(type 0x10)0x200001
        A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")

    aapt l -a ../android/app/build/outputs/apk/app-universal-debug.apk | grep android:version
        A: android:versionCode(0x0101021b)=(type 0x10)0x1
        A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
@facebook-github-bot
Copy link
Contributor

@mkonicek updated the pull request.

@mkonicek
Copy link
Contributor Author

mkonicek commented Jan 7, 2016

@facebook-github-bot shipit

@facebook-github-bot
Copy link
Contributor

Thanks for importing. If you are an FB employee go to https://our.intern.facebook.com/intern/opensource/github/pull_request/937315382983788/int_phab to review.

@mkonicek mkonicek closed this in abb81eb Jan 7, 2016
@satya164
Copy link
Contributor

satya164 commented Jan 8, 2016

@mkonicek Thanks. Proguard works after applying that fix (further reduced APK size about 1MB).

mkonicek pushed a commit that referenced this pull request Jan 18, 2016
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 #5160

Reviewed By: svcscm

Differential Revision: D2811443

Pulled By: mkonicek

fb-gh-sync-id: 97b22b9cd567e53b8adac36669b90768458b7a55
@antoinerousseau
Copy link
Contributor

@satya164 proguard already runs after this fix or you modified something for it?

@antoinerousseau
Copy link
Contributor

antoinerousseau commented Jun 28, 2016

Note for users getting "This app is incompatible with your device." on the Play Store after uploading their two working APKs (with enableSeparateBuildPerCPUArchitecture = true): in the Console, in the APK section, you must Switch to Advanced Mode (button in the top right corner) to be able to have your two APKs enabled at the same time (Move to Alpha/Beta/Prod in Other APKs).

You should see a message saying Some devices are eligible to run multiple APKs. In such a scenario, the device will receive the APK with the higher version code.

@satya164
Copy link
Contributor

@antoinerousseau Proguard runs fine without any customizations in latest release.

grabbou pushed a commit to react-native-community/cli that referenced this pull request Sep 26, 2018
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 facebook/react-native#5160

Reviewed By: svcscm

Differential Revision: D2811443

Pulled By: mkonicek

fb-gh-sync-id: 97b22b9cd567e53b8adac36669b90768458b7a55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants