打包和发布到 Android 平台

在一般的开发过程中,我们可以使用 flutter run 命令,或者 IntelliJ 工具栏中的 RunDebug 来测试 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][]。

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:

  1. 查看 Material Design Product Icons 指南中图标设计部分。

    Review the Material Design product icons guidelines for icon design.

  2. <app dir>/android/app/src/main/res/ 目录下,把我们的图标文件放在以 配置限定符 命名的文件夹中。类似默认的 mipmap- 文件夹这样的命名方式。

    In the <app dir>/android/app/src/main/res/ directory, place your icon files in folders named using configuration qualifiers. The default mipmap- folders demonstrate the correct naming convention.

  3. AndroidManifest.xml 中,更新 application 标签中的 android:icon 属性来引用上一步骤中我们自己的图标文件 (例如,<application android:icon="@mipmap/ic_launcher" ...)。

    In AndroidManifest.xml, update the application tag’s android:icon attribute to reference icons from the previous step (for example, <application android:icon="@mipmap/ic_launcher" ...).

  4. flutter run 运行 app,检查启动程序中的 app 图标是否已经替换成我们自己的图标文件。

    To verify that the icon has been replaced, run your app and inspect the app icon in the Launcher.

为 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.

创建一个密钥库

Create a keystore

如果我们已经有一个密钥库,可以跳到下一步。如果没有,在命令行中运行以下的命令来创建一个:

If you have an existing keystore, skip to the next step. If not, create one by running the following at the command line:

在 macOS 或者 Linux 系统上,执行下面的代码

On Mac/Linux, use the following command:

```terminal
keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key

On Windows, use the following command:

keytool -genkey -v -keystore c:/Users/USER_NAME/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias key

从 app 中引用密钥库

Reference the keystore from the app

创建一个名为 <app dir>/android/key.properties 的文件,它包含了密钥库位置的定义:

Create a file named <app dir>/android/key.properties that contains a reference to your keystore:

storePassword=<上一步骤中的密码>
keyPassword=<上一步骤中的密码>
keyAlias=key
storeFile=<密钥库的位置,e.g. /Users/<用户名>/key.jks>

在 gradle 中配置签名

Configure signing in gradle

通过编辑 <app dir>/android/app/build.gradle 文件来为我们的 app 配置签名:

Configure signing for your app by editing the <app dir>/android/app/build.gradle file.

  1. 将如下内容:

       android {
    

    替换为我们的 properties 文件的密钥库信息:

    With the keystore information from your properties file:

       def keystoreProperties = new Properties()
       def keystorePropertiesFile = rootProject.file('key.properties')
       if (keystorePropertiesFile.exists()) {
           keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
       }
    
       android {
    
  2. 将如下内容:

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

    替换为我们的配置内容:

    With the signing configuration info:

       signingConfigs {
           release {
               keyAlias keystoreProperties['keyAlias']
               keyPassword keystoreProperties['keyPassword']
               storeFile file(keystoreProperties['storeFile'])
               storePassword keystoreProperties['storePassword']
           }
       }
       buildTypes {
           release {
               signingConfig signingConfigs.release
           }
       }
    

现在我们 app 的发布版本就会被自动签名了。

Release builds of your app will now be signed automatically.

启用混淆器

Enabling Proguard

默认情况下,Flutter 不会做混淆或者压缩 Android host 的工作。如果 app 使用了第三方的 Java 或者 Android 库,我们会希望减小 APK 的大小,或者保护代码不被反编译出来。

By default, Flutter does not obfuscate or minify the Android host. If you intend to use third-party Java, Kotlin, or Android libraries, you might want to reduce the size of the APK or protect that code from reverse engineering.

要了解混淆 Dart 代码的相关信息,可以参考 Flutter wiki 上的 Obfuscating Dart Code

For information on obfuscating Dart code, see Obfuscating Dart Code in the Flutter wiki.

步骤 1 - 配置 Proguard

Step 1 - Configure Proguard

创建 /android/app/proguard-rules.pro 文件并添加下面的规则:

Create a /android/app/proguard-rules.pro file and add the rules listed below.

## Flutter wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.**  { *; }
-keep class io.flutter.util.**  { *; }
-keep class io.flutter.view.**  { *; }
-keep class io.flutter.**  { *; }
-keep class io.flutter.plugins.**  { *; }
-dontwarn io.flutter.embedding.**

以上这样的配置只是对 Flutter 引擎库做保护。如果想要保护其他的库(例如,Firebase),需要为它们添加自己的规则。

This configuration only protects Flutter engine libraries. Any additional libraries (for example, Firebase) require adding their own rules.

步骤 2 - 启用混淆以及/或压缩

Step 2 - Enable obfuscation and/or minification

/android/app/build.gradle 文件找到 buildTypes 的定义。在 release 配置中设置 minifiyEnableduseProguard 为 true。另外我们必须再设置 Proguard 指向步骤 1 中我们创建的文件。

Open the /android/app/build.gradle file and locate the buildTypes definition. Inside the release configuration section, set the minifiyEnabled and useProguard flags to true. You must also point Proguard to the file you created in step 1:

android {

    ...

    buildTypes {

        release {

            signingConfig signingConfigs.release

            minifyEnabled true
            useProguard true

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }
    }
}

检查 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 <app dir>/android/app/src/main and verify that the values are correct, especially:

  • 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 之间的通信,详情见 Issue 22139

    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.

检查构建配置

Reviewing the build configuration

检查位于 <app dir>/android/app 的默认 Gradle build file,并确认各个值都设置正确,特别是:

Review the default Gradle build file file, build.gradle, located in <app dir>/android/app and verify the values are correct, especially:

  • defaultConfig:

    • applicationId:指定最终的,唯一的(Application Id)appid

      applicationId: Specify the final, unique (Application Id)appid

    • versionCode & versionName:指定 app 的内部版本号,以及用于显示的版本号,这可以通过设置 pubspec.yaml 文件中 version 属性来做。具体可以参考 版本文档 中的版本信息指南。

      versionCode & versionName: Specify the internal app version number, and the version number display string. You can do this by setting the version property in the pubspec.yaml file. Consult the version information guidance in the versions documentation.

    • minSdkVersion & targetSdkVersion:指定支持的最低 API 版本,以及我们 app 的目标 API 版本。具体可以参考 版本文档 中的 API 版本部分。

      minSdkVersion & targetSdkVersion: Specify the minimum API level, and the API level on which the app is designed to run. Consult the API level section in the versions documentation for details.

为发布构建应用程序

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 会被签名。

This section describes how to build a release app bundle. If you completed the signing steps, the app bundle will be signed.

使用如下命令:

From the command line:

  1. 运行 cd <app dir>。(将 <app dir> 替换为我们 app 的目录)。

    Enter cd <app dir>
    (Replace <app dir> with your application’s directory.)

  2. 运行 flutter build appbundle。 (运行 flutter build 默认构建一个发布版本。)

    Run flutter build appbundle
    (Running flutter 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 <app dir>/build/app/outputs/bundle/release/app.aab.

此 app bundle 会默认地包含为 armeabi-v7a (32-bit) 和 arm64-v8a (64-bit) 编译的 Dart 和 Fluter 运行时代码。

By default, the app bundle contains your Dart code and the Flutter runtime compiled for armeabi-v7a (32-bit) and arm64-v8a (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

  1. 如果你还没准备好,可以从 GitHub repository 下载 bundletool

    If you haven’t done so already, download bundletool from the GitHub repository.

  2. 从你的 app bundle Generate a set of APKs

    Generate a set of APKs from your app bundle.

  3. Deploy the APKs to connected devices.

Deploy the APKs 连接到你的设备

在线使用 Google Play

Online using Google Play

  1. 上传你的 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.

  2. 按照 these steps to upload your 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 就被签名了。

If you completed the signing steps, the APK will be signed.

使用如下命令:

From the command line:

  1. cd <app dir> (将 <app dir> 替换为我们 app 的目录)。

    Enter cd <app dir>
    (Replace <app dir> with your application’s directory.)

  2. 运行 flutter build apkflutter build 默认带有 --release 参数)。

    Run flutter build apk --split-per-abi
    (The flutter build command defaults to --release.)

这个命令会生成两个 APK 文件:

This command results in two APK files:

  • <app dir>/build/app/outputs/apk/release/app-armeabi-v7a-release.apk
  • <app dir>/build/app/outputs/apk/release/app-arm64-v8a-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:

  1. 用 USB 线将 Android 设备连接到电脑上。

    Connect your Android device to your computer with a USB cable.

  2. cd <app dir><app dir> 是我们 app 的目录。

    Enter cd <app dir> where <app dir> is your application directory.

  3. 运行 flutter install

    Run flutter install.

发布到 Google Play Store

Publishing to the Google Play Store

要了解如何发布一个 app 到 Google Play Store,可以参考 Google Play publishing documentation

For detailed instructions on publishing your app to the Google Play Store, see the Google Play launch documentation.

安卓发布常见问题

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 可以运行在多个架构上,因此具有更广泛的兼容性。但同时缺点就是文件体积会比较大,导致用户在安装你的应用程序时会下载和储存更多的字节。当构建 APKs 而不是 app bundles 时强烈建议分开构建 APKs,如 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 (32-bit) 和 arm64-v8a (64-bit)被编译。Flutter 目前不支持 x86 Android (参考 Issue 9253).

When building your application in release mode, Flutter apps can be compiled for armeabi-v7a (32-bit) and arm64-v8a (64-bit). Flutter does not currently support building for x86 Android (See Issue 9253).

如何为一个使用 flutter build appbundle 创建的 app bundle 签名?

How do I sign the app bundle created by flutter build appbundle?

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:

screenshot of gradle build script menu

接下来,选择构建变体。在主菜单中点击 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):

screenshot of build variant menu

生成的 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.