构建和发布为 Android 应用
添加启动图标
Adding a launcher icon
启用 Material 组件
Enabling Material Components
为 app 签名
Signing the app
使用 R8 压缩你的代码
Shrinking your code with R8
启用 multidex 支持
Enabling multidex support
检查 app manifest 文件
Reviewing the app manifest
检查 Gradle 构建配置
Reviewing the Gradle build configuration
构建生产版本应用程序
Building the app for release
发布到 Google Play Store
Publishing to the Google Play Store
更新应用版本号
Updating the app’s version number
Android发布常见问题
Android release FAQ
我应该什么时候构建 app bundles 而不是 APKs?
When should I build app bundles versus APKs?
什么是 fat APK?
What is a fat APK?
哪些目标架构是被支持的?
What are the supported target architectures?
如何为一个使用 flutter build appbundle 创建的 app bundle 签名?
How do I sign the app bundle created by flutter build appbundle?
如何使用 Android Studio 构建一个发布?
How do I build a release from within Android Studio?
在一般的开发过程中,我们可以使用 flutter run
命令,或者 IntelliJ 工具栏中的 Run 和 Debug 来测试 app。这时候,Flutter 默认会为我们构建 app 的调试版本。
During a typical development cycle,
you test an app using flutter run
at the command line,
or by using the Run and Debug
options in your IDE. By default,
Flutter builds a debug version of your app.
当想要发布 app 时,比如 发布到 Google Play Store,可以按照以下步骤来准备 Android 平台的 发布 版本。本页面的内容包含如下主题:
When you’re ready to prepare a release version of your app, for example to publish to the Google Play Store, this page can help. Before publishing, you might want to put some finishing touches on your app. This page covers the following topics:
添加启动图标
Adding a launcher icon
当我们创建一个新的 Flutter app 的时候,它会有一个默认的启动图标。要自定义这个图标,可以参考使用 flutter_launcher_icons 这个 package。
When a new Flutter app is created, it has a default launcher icon. To customize this icon, you might want to check out the flutter_launcher_icons package.
或者,如果我们想手动操作,可以参考以下方法:
Alternatively, you can do it manually using the following steps:
-
查看 Material Design Product Icons 指南中图标设计部分。
Review the Material Design product icons guidelines for icon design.
-
在
<app dir>/android/app/src/main/res/
目录下,把我们的图标文件放在以 配置限定符 命名的文件夹中。类似默认的mipmap-
文件夹这样的命名方式。In the
[project]/android/app/src/main/res/
directory, place your icon files in folders named using configuration qualifiers. The defaultmipmap-
folders demonstrate the correct naming convention. -
在
AndroidManifest.xml
中,更新application
标签中的android:icon
属性来引用上一步骤中我们自己的图标文件 (例如,<application android:icon="@mipmap/ic_launcher" ...
)。In
AndroidManifest.xml
, update theapplication
tag’sandroid:icon
attribute to reference icons from the previous step (for example,<application android:icon="@mipmap/ic_launcher" ...
). -
用
flutter run
运行 app,检查启动程序中的 app 图标是否已经替换成我们自己的图标文件。To verify that the icon has been replaced, run your app and inspect the app icon in the Launcher.
启用 Material 组件
Enabling Material Components
如果你的应用使用了 平台视图 (Platform Views),你可能要通过 Android 平台的入门指南文档 中的步骤使用 Material 组件:
If your app uses Platform Views, you may want to enable Material Components by following the steps described in the Getting Started guide for Android.
举个例子:
For example:
-
在
<my-app>/android/app/build.gradle
文件中添加 Android Material 组件依赖:Add the dependency on Android’s Material in
<my-app>/android/app/build.gradle
:
dependencies {
// ...
implementation 'com.google.android.material:material:<version>'
// ...
}
查看最新的版本,请访问 Google Maven 仓库。
To find out the latest version, visit Google Maven.
-
在
<my-app>/android/app/src/main/res/values/styles.xml
文件中设置亮色主题:Set the light theme in
<my-app>/android/app/src/main/res/values/styles.xml
:
-<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
+<style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
- Set the dark theme in
<my-app>/android/app/src/main/res/values-night/styles.xml
-<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
+<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
为 app 签名
Signing the app
要想把 app 发布到 Play store,还需要给 app 一个数字签名。我们可以采用以下步骤来为 app 签名:
To publish on the Play Store, you need to give your app a digital signature. Use the following instructions to sign your app.
Android 中有两种签名密钥: 部署和上传。终端用户下载到的 .apk 文件是被部署密钥签名过的文件,上传密钥用于验证开发者上载到 Play 商店的 .aab 或 .apk 文件。上传密钥是给予部署密钥重新签名的密钥,上载 Play 商店时候需要用到。
On Android, there are two signing keys: deployment and upload. The end-users download the .apk signed with the ‘deployment key’. An ‘upload key’ is used to authenticate the .aab / .apk uploaded by developers onto the Play Store and is re-signed with the deployment key once in the Play Store.
-
严重推荐你选择云托管的方式来管理部署密钥,更多相关信息,请参阅官方文档 使用 Play 应用签名功能。
It’s highly recommended to use the automatic cloud managed signing for the deployment key. For more information, see the official Play Store documentation.
创建一个用于上传的密钥库
Create an upload keystore
如果你已经有一个密钥库了,可以直接跳到下一步,如果还没有,需要参考下面的方式创建一个:
If you have an existing keystore, skip to the next step. If not, create one by either:
-
参考文档 在 Android Studio 上为你的应用签名。
Following the Android Studio key generation steps
-
在命令行窗口运行如下的命令:
Running the following at the command line:
在 macOS 或者 Linux 系统上,执行下面的代码:
On Mac/Linux, use the following command:
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
在 Windows 系统上,执行下述代码:
On Windows, use the following command:
keytool -genkey -v -keystore c:\Users\USER_NAME\upload-keystore.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias upload
该命令将会把
upload-keystore.jks
文件储存在你的主文件夹中。如果你想要储存在其他地方,请通过指定-keystore
传入参数。 注意,请保证这个文件的私有性,不要将它提交到公共的代码管理空间。This command stores the
upload-keystore.jks
file in your home directory. If you want to store it elsewhere, change the argument you pass to the-keystore
parameter. However, keep thekeystore
file private; don’t check it into public source control!
从 app 中引用密钥库
Reference the keystore from the app
创建一个名为 [project]/android/key.properties
的文件,它包含了密钥库位置的定义:
Create a file named [project]/android/key.properties
that contains a reference to your keystore:
storePassword=<上一步骤中的密码>
keyPassword=<上一步骤中的密码>
keyAlias=upload
storeFile=<密钥库的位置,e.g. /Users/<用户名>/upload-keystore.jks>
在 gradle 中配置签名
Configure signing in gradle
在以 release 模式下构建你的应用时,修改 [project]/android/app/build.gradle
文件,以通过 gradle 配置你的上传密钥。
Configure gradle to use your upload key when building your app in release mode
by editing the [project]/android/app/build.gradle
file.
-
在
android
代码块之前将你 properties 文件的密钥库信息添加进去:Add the keystore information from your properties file before the
android
block:def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } android { ... }
将
key.properties
文件加载到keystoreProperties
对象中。Load the
key.properties
file into thekeystoreProperties
object. -
找到
buildTypes
代码块:Find the
buildTypes
block:buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, // so `flutter run --release` works. signingConfig signingConfigs.debug } }
将其替换为我们的配置内容:
And replace it with the following signing configuration info:
signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release } }
现在我们 app 的发布版本就会被自动签名了。
Release builds of your app will now be signed automatically.
有关应用签名的更多信息,请查看 developer.android.com 的 为您的应用设置签名。
For more information on signing your app, see Sign your app on developer.android.com.
使用 R8 压缩你的代码
Shrinking your code with R8
R8 是谷歌推出的最新代码压缩器,当你打包 release 版本的 APK 或者 AAB 时会默认开启。要关闭 R8,请运行 flutter build apk
或
flutter build appbundle
时加上 --no-shrink
参数。
R8 is the new code shrinker from Google, and it’s enabled by default
when you build a release APK or AAB. To disable R8, pass the --no-shrink
flag to flutter build apk
or flutter build appbundle
.
启用 multidex 支持
Enabling multidex support
当你在编写较大的应用或使用体量较大的插件时,你可能会在最低的 API 目标版本低于 20 时,遇到 Android 的 dex 的 64k 方法数限制问题。当 flutter run
以调试模式运行应用时,由于缩减机制没有运行,该问题也有可能发生。
When writing large apps or making use of large plugins, you may encounter
Android’s dex limit of 64k methods when targeting a minimum API of 20 or
below. This may also be encountered when running debug versions of your app
via flutter run
that does not have shrinking enabled.
Flutter 工具支持以便捷的方式启用 multidex 支持。当工具提示你需要支持时,跟随工具的指示进行调整,是最快的方式。
Flutter 工具会检测 multidex 的构建错误,并提示你是否要更改 Android 项目。在同意的情况下,项目会自动依赖 androidx.multidex:multidex
,并且让项目的 Application
继承于 FlutterMultiDexApplication
。
Flutter tool supports easily enabling multidex. The simplest way is to
opt into multidex support when prompted. The tool detects multidex build errors
and will ask before making changes to your Android project. Opting in allows
Flutter to automatically depend on androidx.multidex:multidex
and use a
generated FlutterMultiDexApplication
as the project’s application.
你也可以根据 Android 的指南,手动配置你的 Android 项目以支持 multidex。请务必指定 multidex keep 文件 以包含以下内容:
You might also choose to manually support multidex by following Android’s guides and modifying your project’s Android directory configuration. A multidex keep file must be specified to include:
io/flutter/embedding/engine/loader/FlutterLoader.class
io/flutter/util/PathUtils.class
同时也要包含所有在应用启动时加载的其他类。参考 multidex 文档 了解更详细的手动适配指南。
Also, include any other classes used in app startup. See the official Android documentation for more detailed guidance on adding multidex support manually.
检查 app manifest 文件
Reviewing the app manifest
检查位于 <app dir>/android/app/src/main
的默认 App Manifest
文件 AndroidManifest.xml
,并确认各个值都设置正确,特别是:
Review the default App Manifest file,
AndroidManifest.xml
,
located in [project]/android/app/src/main
and verify that the values
are correct, especially the following:
application
编辑 application
标签中的 android:label
来设置 app 的最终名字。
application
Edit the android:label
in the
application
tag to reflect
the final name of the app.
uses-permission
:
如果你的代码需要互联网交互,请加入 android.permission.INTERNET
权限标签。标准开发模版里并未加入这个权限(但是 Flutter debug 模版加入了这个权限),加入这个权限是为了允许 Flutter 工具和正在运行的 app 之间的通信。
uses-permission
Add the android.permission.INTERNET
permission if your application code needs Internet
access. The standard template does not include this tag but allows
Internet access during development to enable communication between
Flutter tools and a running app.
检查 Gradle 构建配置
Reviewing the Gradle build configuration
检查位于 [project]/android/app
的默认 Gradle 构建文件 (build.gradle
)
并确认各个值都设置正确:
Review the default Gradle build file (build.gradle
) located in
[project]/android/app
to verify the values are correct:
defaultConfig
配置中
在
defaultConfig
block
Under the applicationId
指定唯一的 应用 ID。
applicationId
Specify the final, unique application ID
minSdkVersion
指定应用适配的最低 SDK 版本。默认为 flutter.minSdkVersion
。
minSdkVersion
Specify the minimum API level on which the app is designed to run.
Defaults to flutter.minSdkVersion
.
targetSdkVersion
指定应用适配的目标 SDK 版本。默认为 flutter.targetSdkVersion
。
targetSdkVersion
Specify the target API level on which the app is designed to run.
Defaults to flutter.targetSdkVersion
.
versionCode
用于内部版本号的正整数。该数字仅用于比较两个版本间数字较大的为更新版本。该版本不会对用户展示。
versionCode
A positive integer used as an internal version number. This number
is used only to determine whether one version is more recent than
another, with higher numbers indicating more recent versions.
This version isn’t shown to users.
versionName
向用户展示的版本号。该字段必须设置为原始字符串或字符串资源的引用。
versionName
A string used as the version number shown to users. This setting
be specified as a raw string or as a reference to a string resource.
buildToolsVersion
If you’re using Android plugin for Gradle 3.0.0 or higher, your project
automatically uses the default version of the build tools that the
plugin specifies. Alternatively, you can specify a version of the build tools.
buildToolsVersion
如果你正在使用高于 3.0.0 版本的 Android Gradle Plugin,你的项目会自动使用 AGP 默认指定的构建工具版本。你也可以手动指定构建工具的版本。
buildToolsVersion
If you’re using Android plugin for Gradle 3.0.0 or higher, your project
automatically uses the default version of the build tools that the
plugin specifies. Alternatively, you can specify a version of the build tools.
android
配置中
在
android
block
Under the compileSdkVersion
指定 Gradle 用于编译应用的 API 版本。默认为 flutter.compileSdkVersion
。
compileSdkVersion
Specify the API level Gradle should use to compile your app.
Defaults to flutter.compileSdkVersion
.
更多信息可以参考 Gradle 构建文件 文档中模块级构建的部分。
For more information, see the module-level build section in the Gradle build file.
构建生产版本应用程序
Building the app for release
当要发布到 Play Store 时,你有两种发布方式的选择:
You have two possible release formats when publishing to the Play Store.
-
App bundle (推荐)
App bundle (preferred)
-
APK
构建一个 app bundle
Build an app bundle
这个部分描述了如何构建一个发布的 app bundle。如果在前面的部分已经完成了签名步骤,发布的 bundle 会被签名。这时你也许想要 混淆你的 Dart 代码 以加大反编译难度。混淆你的代码需要在 build 的时候添加一些标志,并维护其他文件以消除反编译的堆栈跟踪。
This section describes how to build a release app bundle. If you completed the signing steps, the app bundle will be signed. At this point, you might consider obfuscating your Dart code to make it more difficult to reverse engineer. Obfuscating your code involves adding a couple flags to your build command, and maintaining additional files to de-obfuscate stack traces.
使用如下命令:
From the command line:
-
运行
cd [project]
。Enter
cd [project]
-
运行
flutter build appbundle
。 (运行flutter build
默认构建一个发布版本。)Run
flutter build appbundle
(Runningflutter build
defaults to a release build.)
你的应用的 release bundle 会被创建到
<app dir>/build/app/outputs/bundle/release/app.aab
.
The release bundle for your app is created at
[project]/build/app/outputs/bundle/release/app.aab
.
此 app bundle 会默认地包含为 armeabi-v7a (ARM 32-bit)、arm64-v8a (ARM 64-bit) 以及 x86-64 (x86 64-bit) 编译的 Dart 和 Fluter 运行时代码。
By default, the app bundle contains your Dart code and the Flutter runtime compiled for armeabi-v7a (ARM 32-bit), arm64-v8a (ARM 64-bit), and x86-64 (x86 64-bit).
测试 app bundle
Test the app bundle
一个 app bundle 可以用多种方法测试,这里介绍两种。
An app bundle can be tested in multiple ways—this section describes two.
离线使用 bundle tool
Offline using the bundle tool
-
如果你还没准备好,可以从 GitHub 仓库 下载
bundletool
。If you haven’t done so already, download
bundletool
from the GitHub repository. -
从你的 app bundle 生成 APKs。
Generate a set of APKs from your app bundle.
-
将这 APKs 部署到 已连接的设备。
Deploy the APKs to connected devices.
在线使用 Google Play
Online using Google Play
-
上传你的 bundle 到 Google Play 去测试它。或者在正式发布之前用 alpha 或 beta 频道去测试。
Upload your bundle to Google Play to test it. You can use the internal test track, or the alpha or beta channels to test the bundle before releasing it in production.
-
按照 这些步骤把你的 bundle 上传到 Play Store。
Follow these steps to upload your bundle to the Play Store.
构建一个 APK
Build an APK
虽然 app bundle 比 APKs 更被推荐使用,但是有一些 Store 目前还不支持 app bundle方式。这种情况下,要为各种目标 ABI (Application Binary Interface) 分别构建发布的 APK 文件。
Although app bundles are preferred over APKs, there are stores that don’t yet support app bundles. In this case, build a release APK for each target ABI (Application Binary Interface).
如果你完成签名步骤,APK 就被签名了。这时你也许想要 混淆你的 Dart 代码 以加大反编译难度。混淆你的代码需要在构建时添加一些参数。
If you completed the signing steps, the APK will be signed. At this point, you might consider obfuscating your Dart code to make it more difficult to reverse engineer. Obfuscating your code involves adding a couple flags to your build command.
使用如下命令:
From the command line:
-
输入命令
cd [project]
Enter
cd [project]
-
运行
flutter build apk --split-per-abi
(flutter build
默认带有--release
参数。)Run
flutter build apk --split-per-abi
(Theflutter build
command defaults to--release
.)
这个命令会生成如下三个 APK 文件
This command results in three APK files:
[project]/build/app/outputs/apk/release/app-armeabi-v7a-release.apk
[project]/build/app/outputs/apk/release/app-arm64-v8a-release.apk
[project]/build/app/outputs/apk/release/app-x86_64-release.apk
如果移除 --split-per-abi
将会生成一个包含 所有 目标 ABI 的 fat APK 文件。这种 APK 文件将会在比单独构建的 APK 文件尺寸要大,会导致用户下载一些不适用于其设备架构的二进制文件。
Removing the --split-per-abi
flag results in a fat APK that contains
your code compiled for all the target ABIs. Such APKs are larger in
size than their split counterparts, causing the user to download
native binaries that are not applicable to their device’s architecture.
在设备上安装 APK 文件
Install an APK on a device
按照如下这些步骤,将前一步中构建出来的 APK 安装到 Android 设备上。
Follow these steps to install the APK on a connected Android device.
使用如下命令:
From the command line:
-
用 USB 线将 Android 设备连接到电脑上;
Connect your Android device to your computer with a USB cable.
-
输入命令
cd [project]
;Enter
cd [project]
. -
运行
flutter install
。Run
flutter install
.
发布到 Google Play Store
Publishing to the Google Play Store
要了解如何发布一个 app 到 Google Play Store,可以参考 Google Play 发布文档。
For detailed instructions on publishing your app to the Google Play Store, see the Google Play launch documentation.
更新应用版本号
Updating the app’s version number
每个应用默认的初始版本号是 1.0.0
。若要更新它,请转到 pubspec.yaml
文件并更新以下内容:
The default version number of the app is 1.0.0
.
To update it, navigate to the pubspec.yaml
file
and update the following line:
version: 1.0.0+1
版本号由三个点分隔的数字组成,例如上面样例中的 1.0.0
。然后是可选的构建号,例如上面样例中的 1
,以 +
分隔。
The version number is three numbers separated by dots,
such as 1.0.0
in the example above, followed by an optional
build number such as 1
in the example above, separated by a +
.
版本号与构建号都可以在 Flutter 打包时分别使用
--build-name
和 --build-number
重新指定。
Both the version and the build number may be overridden in Flutter’s
build by specifying --build-name
and --build-number
, respectively.
在 Android 中,build-number
被用作 versionCode
,
build-name
将作为 versionName
使用。更多信息请参考 Android 文档中的 为你的应用添加版本。
In Android, build-name
is used as versionName
while
build-number
used as versionCode
. For more information,
see Version your app in the Android documentation.
在更新完 pubspec 文件中的版本号之后,在项目根目录下运行 flutter pub get
,或者使用 IDE 中的 Pub get 按钮。这将会更新 local.properties
文件中的 versionName
和 versionCode
,之后它会在你构建 Flutter 应用的时候更新 build.gradle
。
After updating the version number in the pubspec file,
run flutter pub get
from the top of the project, or
use the Pub get button in your IDE. This updates
the versionName
and versionCode
in the local.properties
file,
which are later updated in the build.gradle
file when you
rebuild the Flutter app.
Android发布常见问题
Android release FAQ
这里是一些关于安卓应用程序发布的常见问题。
Here are some commonly asked questions about deployment for Android apps.
我应该什么时候构建 app bundles 而不是 APKs?
When should I build app bundles versus APKs?
Google Play Store 相对于 APKs 更建议你发布 app bundles,因为那样应用程序会更有效率地交付给你的用户。但是,如果你想将应用程序发布到其他的应用商店,APK可能是唯一选项。
The Google Play Store recommends that you deploy app bundles over APKs because they allow a more efficient delivery of the application to your users. However, if you’re distributing your application by means other than the Play Store, an APK may be your only option.
什么是 fat APK?
What is a fat APK?
一个 fat APK 是一个包含了支持多个 ABI 架构的 APK 文件。这样做的好处是单个 APK 可以运行在多个架构上,因此具有更广泛的兼容性。但同时缺点就是文件体积会比较大,导致用户在安装你的应用程序时会下载和储存更多的字节。当构建 APK 而不是 app bundles 时强烈建议分开构建 APK,如 build an APK 所描述的那样,使用 --split-per-abi
指令。
A fat APK is a single APK that contains binaries for multiple
ABIs embedded within it. This has the benefit that the single APK
runs on multiple architectures and thus has wider compatibility,
but it has the drawback that its file size is much larger,
causing users to download and store more bytes when installing
your application. When building APKs instead of app bundles,
it is strongly recommended to build split APKs,
as described in build an APK using the
--split-per-abi
.
哪些目标架构是被支持的?
What are the supported target architectures?
当使用 release 模式构建你的应用程序时, Flutter app 可以基于 armeabi-v7a (ARM 32 位)、 arm64-v8a (ARM 64 位) 以及 x86-64 (x86 64 位) 被编译。 Flutter 目前不支持 x86 Android (参考 Issue 9253).
When building your application in release mode, Flutter apps can be compiled for armeabi-v7a (ARM 32-bit), arm64-v8a (ARM 64-bit), and x86-64 (x86 64-bit). Flutter does not currently support building for x86 Android (See Issue 9253).
flutter build appbundle
创建的 app bundle 签名?
如何为一个使用
flutter build appbundle
?
How do I sign the app bundle created by See Signing the app.
如何使用 Android Studio 构建一个发布?
How do I build a release from within Android Studio?
在Android Studio中, 打开你的 app 文件夹下的 android/
文件夹. 然后在项目面板中选择 build.gradle (Module: app) :
In Android Studio, open the existing android/
folder under your app’s folder. Then,
select build.gradle (Module: app) in the project panel:
接下来,选择构建变体。在主菜单中点击 Build > Select Build Variant。从 Build Variants 面板中选择任意一个变体(默认是 debug)。
Next, select the build variant. Click Build > Select Build Variant in the main menu. Select any of the variants in the Build Variants panel (debug is the default):
生成的 app bundle 或 APK 文件会在你的 app 所在文件夹下的 build/app/outputs
文件夹下。
The resulting app bundle or APK files are located in
build/app/outputs
within your app’s folder.