打包发布

Android 要求所有应用都有一个数字签名才会被允许安装在用户手机上,所以在把应用发布到应用市场之前,你需要先生成一个签名的 AAB 或 APK 包(Google Play 现在要求 AAB 格式,而国内的应用市场目前仅支持 APK 格式。但无论哪种格式,下面的签名步骤是一样的)。Android 开发者官网上的如何给你的应用签名文档描述了签名的细节。本指南旨在提供一个简化的签名和打包的操作步骤,不会涉及太多理论。

生成一个签名密钥#

你可以用keytool命令生成一个私有密钥。在 Windows 上keytool命令放在 JDK 的 bin 目录中(比如C:\Program Files\Java\jdkx.x.x_x\bin),你可能需要在命令行中先进入那个目录才能执行此命令。

$ keytool -genkeypair -v -storetype PKCS12 -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 1000

这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息。最后它会生成一个叫做my-release-key.keystore的密钥库文件。

在运行上面这条语句之后,密钥库里应该已经生成了一个单独的密钥,有效期为 10000 天。--alias 参数后面的别名是你将来为应用签名时所需要用到的,所以记得记录这个别名。

注意:请记得妥善地保管好你的密钥库文件,一般不要上传到版本库或者其它的地方。

设置 gradle 变量#

  1. my-release-key.keystore文件放到你工程中的android/app文件夹下。
  2. 编辑~/.gradle/gradle.properties(全局配置,对所有项目有效)或是项目目录/android/gradle.properties(项目配置,只对所在项目有效)。如果没有gradle.properties文件你就自己创建一个,添加如下的代码(注意把其中的****替换为相应密码)

注意:~符号表示用户目录,比如 windows 上可能是C:\Users\用户名,而 mac 上可能是/Users/用户名

MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****

上面的这些会作为 gradle 的变量,在后面的步骤中可以用来给应用签名。

关于密钥库的注意事项::如果你不想以明文方式保存密码,同时你使用的是 macOS 系统,那么你也可以把密码保存到钥匙串(Keychain)中。这样一来你就可以省略掉上面配置中的后两行(即 MYAPP_RELEASE_STORE_PASSWORD 和 MYAPP_RELEASE_KEY_PASSWORD)。

把签名配置加入到项目的 gradle 配置中#

编辑你项目目录下的android/app/build.gradle,添加如下的签名配置:

...
android {
...
defaultConfig { ... }
signingConfigs {
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
...

生成发行 APK 包#

只需在终端中运行以下命令:

$ cd android
$ ./gradlew assembleRelease

译注:cd android表示进入 android 目录(如果你已经在 android 目录中了那就不用输入了)。./gradlew assembleRelease在 macOS、Linux 或是 windows 的 PowerShell 环境中表示执行当前目录下的名为 gradlew 的脚本文件,且其运行参数为 assembleRelease,注意这个./不可省略;而在 windows 的传统 CMD 命令行下则需要去掉./

Gradle 的assembleRelease参数会把所有用到的 JavaScript 代码都打包到一起,然后内置到 APK 包中。如果你想调整下这个行为(比如 js 代码以及静态资源打包的默认文件名或是目录结构等),可以看看android/app/build.gradle文件,然后琢磨下应该怎么修改以满足你的需求。

注意:请确保 gradle.properties 中没有包含_org.gradle.configureondemand=true_,否则会跳过 js 打包的步骤,导致最终生成的是一个无法运行的空壳。

生成的 APK 文件位于android/app/build/outputs/apk/release/app-release.apk,它已经可以用来发布了。

测试应用的发行版本#

在把发行版本提交到 Play Store 之前,你应该做一次最终测试。输入以下命令可以在设备上安装发行版本:

$ npx react-native run-android --variant=release

注意--variant=release参数只能在你完成了上面的签名配置之后才可以使用。你现在可以关掉运行中的 packager 了,因为你所有的代码和框架依赖已经都被打包到 apk 包中,可以离线运行了。

注意:在 debug 和 release 版本间来回切换安装时可能会报错签名不匹配,此时需要先卸载前一个版本再尝试安装。

针对不同的 CPU 架构生成 APK 以减小 APK 文件的大小#

默认情况下,生成的 APK 会同时包含针对于多种 CPU 架构的原生代码。这样可以让我们更方便的向其他人分享这个 APK,因为它几乎可以运行在所有的 Android 设备上。但是,这会导致所有设备上都有一些根本不会运行的代码,白白占据了空间。目前安卓设备绝大多数是 ARM 架构,因此对于大部分应用来说可以考虑去掉 x86 架构的支持(但是请注意模拟器大部分是 x86 架构,因此去掉 x86 架构后将无法在模拟器上运行)。

你可以在android/app/build.gradle中修改如下代码(false 改为 true)来生成多个针对不同 CPU 架构的 APK。

- ndk {
- abiFilters "armeabi-v7a", "x86"
- }
- def enableSeparateBuildPerCPUArchitecture = false
+ def enableSeparateBuildPerCPUArchitecture = true

你可以把这上面打包生成的多个 APK 都上传到支持对用户设备 CPU 架构定位的应用程序商店,例如 Google Play 和 Amazon AppStore,用户将自动获得相应的 APK。如果您想上传到其他市场,例如 APKFiles(不支持一个应用有多个 APK 文件),可以修改下面的代码,来额外生成一个适用不同 CPU 架构的通用 APK。

- universalApk false
+ universalApk true // 额外生成一个适用不同CPU架构的通用APK

启用 Proguard 来减少 apk 的大小(可选)#

Proguard 是一个 Java 字节码混淆压缩工具,它可以移除掉 React Native Java(和它的依赖库中)中没有被使用到的部分,最终有效的减少 APK 的大小。

重要:启用 Proguard 之后,你必须再次全面地测试你的应用。Proguard 有时候需要为你引入的每个原生库做一些额外的配置。参见app/proguard-rules.pro文件。

要启用 Proguard,修改android/app/build.gradle文件:

/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = true

生成发行 AAB 包#

在命令行中运行下列命令:

cd android
./gradlew bundleRelease

Gradle 的bundleRelease参数会把所有用到的 JavaScript 代码都打包到一起,然后内置到 AAB 包(Android App Bundle)中。如果你想调整下这个行为(比如 js 代码以及静态资源打包的默认文件名或是目录结构等),可以看看android/app/build.gradle文件,然后琢磨下应该怎么修改以满足你的需求。

注意:请确保 gradle.properties 中没有包含_org.gradle.configureondemand=true_,否则会跳过 js 打包的步骤,导致最终生成的是一个无法运行的空壳。

生成的 AAB 文件位于android/app/build/outputs/bundle/release/app-release.aab,它已经可以用来上传到 Google Play 市场了。

In order for Google Play to accept AAB format the App Signing by Google Play needs to be configured for your application on the Google Play Console. If you are updating an existing app that doesn't use App Signing by Google Play, please check our migration section to learn how to perform that configuration change.