跳至主要内容

构建和发布 Android 应用

要测试应用,您可以在命令行中使用 flutter run,或者使用 IDE 中的“运行”和“调试”选项。

当您准备好准备应用的发布版本时,例如发布到Google Play 商店,此页面可以提供帮助。在发布之前,您可能需要对应用进行一些最后的润色。本指南说明如何执行以下任务

添加启动器图标

#

创建新的 Flutter 应用时,它具有默认的启动器图标。要自定义此图标,您可能需要查看 flutter_launcher_icons 包。

或者,您可以手动执行以下步骤

  1. 查看有关图标设计的Material Design 产品图标指南。

  2. [project]/android/app/src/main/res/ 目录中,将您的图标文件放在使用配置限定符命名的文件夹中。默认的 mipmap- 文件夹演示了正确的命名约定。

  3. AndroidManifest.xml 中,更新application 标签的 android:icon 属性以引用上一步中的图标(例如,<application android:icon="@mipmap/ic_launcher" ...)。

  4. 要验证图标是否已替换,请运行您的应用并在启动器中检查应用图标。

启用 Material Components

#

如果您的应用使用平台视图,您可能需要按照Android 入门指南中描述的步骤启用 Material Components。

例如

  1. <my-app>/android/app/build.gradle 中添加对 Android 的 Material 的依赖项
kotlin
dependencies {
    // ...
    implementation("com.google.android.material:material:<version>")
    // ...
}

要了解最新版本,请访问Google Maven

  1. <my-app>/android/app/src/main/res/values/styles.xml 中设置亮色主题
xml
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
  1. <my-app>/android/app/src/main/res/values-night/styles.xml 中设置暗色主题
xml
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">

签名应用

#

要在 Play 商店上发布,您需要使用数字证书签署您的应用。

Android 使用两个签署密钥:上传密钥和应用签署密钥。

  • 开发者将使用上传密钥签署的 .aab.apk 文件上传到 Play 商店。
  • 最终用户下载使用应用签署密钥签署的 .apk 文件。

要创建您的应用签署密钥,请按照官方 Play 商店文档中所述使用 Play 应用签署。

要签署您的应用,请使用以下说明。

创建上传密钥库

#

如果您有现有的密钥库,请跳到下一步。如果没有,请使用以下方法之一创建一个

  1. 按照Android Studio 密钥生成步骤

  2. 在命令行中运行以下命令

    在 macOS 或 Linux 上,使用以下命令

    keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
            -keysize 2048 -validity 10000 -alias upload

    在 Windows 上,在 PowerShell 中使用以下命令

    keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks `
            -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 `
            -alias upload

    此命令将 upload-keystore.jks 文件存储在您的主目录中。如果您想将其存储在其他位置,请更改传递给 -keystore 参数的参数。**但是,请将 keystore 文件保密;不要将其检入公共源代码控制!**

从应用引用密钥库

#

创建一个名为 [project]/android/key.properties 的文件,其中包含对密钥库的引用。不要包含尖括号 (< >)。它们表示文本用作您值的占位符。

properties
storePassword=<password-from-previous-step>
keyPassword=<password-from-previous-step>
keyAlias=upload
storeFile=<keystore-file-location>

storeFile 可能位于 macOS 上的 /Users/<user name>/upload-keystore.jks 或 Windows 上的 C:\\Users\\<user name>\\upload-keystore.jks

在 Gradle 中配置签名

#

在发布模式下构建应用时,配置 gradle 以使用您的上传密钥。要配置 gradle,请编辑 <project>/android/app/build.gradle 文件。

  1. android 属性块之前定义并加载密钥库属性文件。

  2. keystoreProperties 对象设置为加载 key.properties 文件。

    [project]/android/app/build.gradle
    kotlin
    def keystoreProperties = new Properties()
    def keystorePropertiesFile = rootProject.file('key.properties')
    if (keystorePropertiesFile.exists()) {
        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    }
    
    android {
       ...
    }
  3. android 属性块内的 buildTypes 属性块之前添加签署配置。

    [project]/android/app/build.gradle
    kotlin
    android {
        // ...
    
        signingConfigs {
            release {
                keyAlias = keystoreProperties['keyAlias']
                keyPassword = keystoreProperties['keyPassword']
                storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
                storePassword = keystoreProperties['storePassword']
            }
        }
        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
                signingConfig = signingConfigs.release
            }
        }
    ...
    }

Flutter 现在签署所有发布版本。

要详细了解如何签署应用,请查看 developer.android.com 上的签署您的应用

使用 R8 缩减代码

#

R8 是 Google 的新代码压缩器。在构建发布版 APK 或 AAB 时,默认情况下启用它。要禁用 R8,请将 --no-shrink 标志传递给 flutter build apkflutter build appbundle

启用 Multidex 支持

#

在编写大型应用或使用大型插件时,在将目标 API 设置为 20 或以下时,您可能会遇到 Android 的 64k 方法限制。在使用未启用压缩的 flutter run 运行应用的调试版本时,也可能会遇到这种情况。

Flutter 工具支持轻松启用 Multidex。最简单的方法是在系统提示时选择加入 Multidex 支持。该工具检测 Multidex 构建错误并在进行更改之前询问您的 Android 项目。选择加入允许 Flutter 自动依赖于 androidx.multidex:multidex 并使用生成的 FlutterMultiDexApplication 作为项目的应用程序。

当您尝试使用 IDE 中的“运行”和“调试”选项构建和运行应用时,您的构建可能会失败并显示以下消息

Build failure because Multidex support is required

要从命令行启用 Multidex,请运行 flutter run --debug 并选择 Android 设备

Selecting an Android device with the flutter CLI.

出现提示时,输入 y。Flutter 工具启用 Multidex 支持并重试构建

The output of a successful build after adding multidex.

您也可以选择通过遵循 Android 的指南和修改项目的 Android 目录配置来手动支持 Multidex。必须指定Multidex 保留文件以包含

io/flutter/embedding/engine/loader/FlutterLoader.class
io/flutter/util/PathUtils.class

此外,还包括应用启动中使用的任何其他类。有关手动添加 Multidex 支持的更详细指南,请查看官方Android 文档

查看应用清单

#

查看默认的应用清单文件。

[project]/android/app/src/main/AndroidManifest.xml
xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:label="[project]"
        ...
    </application>
    ...
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

验证以下值

标签属性
application编辑application 标签中的 android:label 以反映应用的最终名称。
uses-permission如果您的应用需要 Internet 访问,请将 android.permission.INTERNET 权限值添加到 android:name 属性中。标准模板不包含此标签,但在开发过程中允许 Internet 访问以启用 Flutter 工具和正在运行的应用之间的通信。

查看或更改 Gradle 构建配置

#

要验证 Android 构建配置,请查看默认Gradle 构建脚本中的 android 块。默认的 Gradle 构建脚本位于 [project]/android/app/build.gradle 中。您可以更改任何这些属性的值。

[project]/android/app/build.gradle
kotlin
android {
    namespace = "com.example.[project]"
    // Any value starting with "flutter." gets its value from
    // the Flutter Gradle plugin.
    // To change from these defaults, make your changes in this file.
    compileSdk = flutter.compileSdkVersion
    ndkVersion = flutter.ndkVersion

    ...

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com.cn/studio/build/application-id.html).
        applicationId = "com.example.[project]"
        // You can update the following values to match your application needs.
        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion
        // These two properties use values defined elsewhere in this file.
        // You can set these values in the property declaration
        // or use a variable.
        versionCode = flutterVersionCode.toInteger()
        versionName = flutterVersionName
    }

    buildTypes {
        ...
    }
}

需要在 build.gradle 中调整的属性

#
属性用途默认值
compileSdk编译应用所依据的 Android API 级别。这应该是可用的最高版本。如果您将此属性设置为 31,则可以在运行 API 30 或更低版本的设备上运行您的应用,只要您的应用不使用特定于 31 的任何 API 即可。
defaultConfig
.applicationId标识您的应用的最终唯一应用 ID
.minSdk您设计应用以运行的最低 Android API 级别flutter.minSdkVersion
.targetSdk您测试应用以运行的 Android API 级别。您的应用应该在所有 Android API 级别上运行,直到此级别。flutter.targetSdkVersion
.versionCode一个正整数,用于设置内部版本号。此数字仅确定哪个版本比另一个版本更新。较大的数字表示较新的版本。应用用户永远不会看到此值。
.versionName您的应用显示为其版本号的字符串。将此属性设置为原始字符串或对字符串资源的引用。
.buildToolsVersionGradle 插件指定项目使用的 Android 构建工具的默认版本。要指定不同版本的构建工具,请更改此值。

要了解有关 Gradle 的更多信息,请查看 Gradle 构建文件 中的模块级构建部分。

构建应用以供发布

#

发布到 Play 商店时,您有两种可能的发布格式。

  • 应用包 (推荐)
  • APK

构建应用包

#

本节介绍如何构建发布应用包。如果您已完成签名步骤,则应用包将被签名。此时,您可能需要考虑 混淆您的 Dart 代码 以使其更难以反向工程。混淆代码涉及向构建命令添加几个标志,以及维护其他文件以反混淆堆栈跟踪。

从命令行

  1. 输入 cd [project]
  2. 运行 flutter build appbundle
    (运行 flutter build 默认使用发布构建。)

应用的发布包创建在 [project]/build/app/outputs/bundle/release/app.aab 中。

默认情况下,应用包包含您的 Dart 代码和为 armeabi-v7a(ARM 32 位)、arm64-v8a(ARM 64 位)和 x86-64(x86 64 位)编译的 Flutter 运行时。

测试应用包

#

应用包可以通过多种方式进行测试。本节介绍两种。

离线使用 bundletool

#
  1. 如果您尚未这样做,请从 GitHub 存储库 下载 bundletool
  2. 从您的应用包 生成一组 APK
  3. 将 APK 部署 到已连接的设备。

在线使用 Google Play

#
  1. 将您的应用包上传到 Google Play 进行测试。您可以在发布到生产环境之前,使用内部测试轨道或 Alpha 或 Beta 渠道来测试应用包。
  2. 按照 这些步骤将您的应用包上传 到 Play 商店。

构建 APK

#

尽管应用包优于 APK,但有些商店尚未支持应用包。在这种情况下,为每个目标 ABI(应用程序二进制接口)构建一个发布 APK。

如果您已完成签名步骤,则 APK 将被签名。此时,您可能需要考虑 混淆您的 Dart 代码 以使其更难以反向工程。混淆代码涉及向构建命令添加几个标志。

从命令行

  1. 输入 cd [project]

  2. 运行 flutter build apk --split-per-abi。(flutter build 命令默认为 --release。)

此命令将生成三个 APK 文件

  • [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 编译的代码的完整 APK。此类 APK 的大小大于其拆分后的对应文件,导致用户下载与其设备架构不相关的原生二进制文件。

在设备上安装 APK

#

按照以下步骤将 APK 安装到已连接的 Android 设备上。

从命令行

  1. 使用 USB 线缆将您的 Android 设备连接到计算机。
  2. 输入 cd [project]
  3. 运行 flutter install

发布到 Google Play 商店

#

有关将您的应用发布到 Google Play 商店的详细说明,请查看 Google Play 发布 文档。

更新应用的版本号

#

应用的默认版本号为 1.0.0。要更新它,请导航到 pubspec.yaml 文件并更新以下行

version: 1.0.0+1

版本号由三个用点分隔的数字组成,例如上面示例中的 1.0.0,后跟一个可选的构建号,例如上面示例中的 1,用 + 分隔。

版本和构建号都可以在 Flutter 的构建中通过分别指定 --build-name--build-number 来覆盖。

在 Android 中,build-name 用作 versionName,而 build-number 用作 versionCode。有关更多信息,请查看 Android 文档中的 为您的应用设置版本

当您为 Android 重新构建应用时,来自 pubspec 文件的版本号中的任何更新都将更新 local.properties 文件中的 versionNameversionCode

Android 发布常见问题

#

以下是一些关于 Android 应用部署的常见问题。

何时应该构建应用包而不是 APK?

#

Google Play 商店建议您部署应用包而不是 APK,因为它们可以更有效地将应用程序交付给您的用户。但是,如果您通过 Play 商店以外的方式分发应用程序,则 APK 可能是您的唯一选择。

什么是胖 APK?

#

一个 完整 APK 是一个包含多个 ABI 的二进制文件的单个 APK。这样做的好处是单个 APK 可以运行在多种架构上,从而具有更广泛的兼容性,但缺点是其文件大小更大,导致用户在安装应用程序时下载和存储更多字节。在构建 APK 而不是应用包时,强烈建议构建拆分 APK,如 构建 APK 中使用 --split-per-abi 标志所述。

支持哪些目标架构?

#

在发布模式下构建应用程序时,Flutter 应用可以编译为 armeabi-v7a(ARM 32 位)、arm64-v8a(ARM 64 位)和 x86-64(x86 64 位)。

如何签名 flutter build appbundle 创建的应用包?

#

请参阅 签名应用

如何在 Android Studio 中构建发布版本?

#

在 Android Studio 中,打开应用文件夹下的现有 android/ 文件夹。然后,在项目面板中选择build.gradle (Module: app)

The Gradle build script menu in Android Studio.

接下来,选择构建变体。单击主菜单中的构建 > 选择构建变体。在构建变体面板中选择任何变体(调试是默认值)

The build variant menu in Android Studio with Release selected.

生成的应用包或 APK 文件位于应用文件夹内的 build/app/outputs 中。