打包并发布 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 这个 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:

  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 [project]/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.

启用 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:

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

  1. <my-app>/android/app/src/main/res/values/styles.xml 文件中设置主题:

    Set the theme in <my-app>/android/app/src/main/res/values/styles.xml:

-<style name="LaunchTheme" parent="Theme.AppCompat">
+<style name="LaunchTheme" parent="Theme.MaterialComponents.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.

创建一个用于上传的密钥库

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 the keystore 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.

  1. Add the keystore information from your properties file before the android block:android 代码块之前将你 properties 文件的密钥库信息添加进去:

       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 the keystoreProperties object.

  2. Replace the buildTypes block:

  3. buildTypes 代码块之前添加:

       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 keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
               storePassword keystoreProperties['storePassword']
           }
       }
       buildTypes {
           release {
               signingConfig signingConfigs.release
           }
       }
    
  4. </ol>

    现在我们 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 apkflutter 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.

    检查 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.

    检查构建配置

    Reviewing the build configuration

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

    Review the default Gradle build file, build.gradle, located in [project]/android/app and verify the values are correct, especially the following values in the defaultConfig block:

    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.

    minSdkVersioncompilesdkVersiontargetSdkVersion
    指定应用运行所需要的最低 API 级别 minSdkVersion、编译 API 级别 compilesdkVersion 以及目标 API 级别 targetSdkVersion。具体可以参考 Android 开发者网站上关于 版本的文档 中的 API 版本的部分。

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

    buildToolsVersion
    指定应用所需的 Android SDK 构建工具的版本,或者你可以在 Android Studio 里使用 [Android Gradle 插件 (AGP)][Android Gradle Plugin],它可以自动设置导入你应用所需的构建工具版本,这样就无需过多操心这个属性啦。

    buildToolsVersion
    Specify the version of Android SDK Build Tools that your app uses. Alternatively, you can use the [Android Gradle Plugin][] in Android Studio, which will automatically import the minimum required Build Tools for your app without the need for this property.

    为发布构建应用程序

    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:

  1. 运行 cd [project]

    Enter cd [project]

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

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

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

  2. 从你的 app bundle 生成 APKs

    Generate a set of APKs from your app bundle.

  3. 将这 APKs 部署到 已连接的设备

    Deploy the APKs to connected devices.

在线使用 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. 按照 这些步骤把你的 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. 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:

  1. 输入命令 cd [project]

    Enter cd [project]

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

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

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

  2. 输入命令 cd [project]

    Enter cd [project].

  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.

当你创建了应用之后,你可以通过 Google Ads 吸引更多用户, Google Ads 平台可以通过机器学习帮助你以非常高的性价比吸引到更多用户。

Now that you’ve created your app, attract more users with Google Ads. App campaigns use machine learning to drive more installs and make the most of your budget.

通过以下几步创建一个广告宣传:

Get your campaign running in a few steps

  1. 创建广告—我们会根据您的应用信息帮您制作广告。另外,您还可以添加图片和视频。

    Create your ad—we’ll help create your ad from your app information

  2. 决定推广预算—对于以提高应用安装量为主要目标的广告系列,您需要为其设置应用安装出价,也就是“目标每次安装费用”,同时设置每日推广支出预算。

    Choose your budget—set your target cost-per-install (tCPI) and daily budget cap

  3. 选择目标地区—让我们知道你希望触达哪些区域的用户。

    Select your location—let us know where you’d like your ads to run

  4. 设定用户行动—决定你希望用户要做什么,比如安装,应用内操作或者目标广告支出回报率 (ROAS)。

    Decide what action you want users to take—choose installs, in-app actions, or target return on ad spend (ROAS)

[获取 75 美元的赠金(当你消费 25 美金后)][Get $75 app advertising credit when you spend $25.]

[Get $75 app advertising credit when you spend $25.][]

更新应用版本号

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 被用作 versionCodebuild-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 文件中的 versionNameversionCode,之后它会在你构建 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 签名?

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.