要测试应用,您可以在命令行中使用 flutter run,或在 IDE 中使用 **Run** 和 **Debug** 选项。

当您准备好构建应用的发布版本时,例如为了发布到 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 入门指南中的步骤启用 Material Components。

例如

  1. <my-app>/android/app/build.gradle.kts 中添加 Android 的 Material 依赖项。

    groovy
    dependencies {
        // ...
        implementation("com.google.android.material:material:<version>")
        // ...
    }

    要查找最新版本,请访问 Google Maven

  2. <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">
  3. <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.kts 文件。

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

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

    [project]/android/app/build.gradle.kts
    kotlin
    import java.util.Properties
    import java.io.FileInputStream
    
    plugins {
       ...
    }
    
    val keystoreProperties = Properties()
    val keystorePropertiesFile = rootProject.file("key.properties")
    if (keystorePropertiesFile.exists()) {
        keystoreProperties.load(FileInputStream(keystorePropertiesFile))
    }
    
    android {
       ...
    }
  3. android 属性块内的 buildTypes 属性块之前添加签名配置。

    [project]/android/app/build.gradle.kts
    kotlin
    android {
        // ...
    
        signingConfigs {
            create("release") {
                keyAlias = keystoreProperties["keyAlias"] as String
                keyPassword = keystoreProperties["keyPassword"] as String
                storeFile = keystoreProperties["storeFile"]?.let { file(it) }
                storePassword = keystoreProperties["storePassword"] as String
            }
        }
        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.getByName("debug")
                signingConfig = signingConfigs.getByName("release")
            }
        }
    ...
    }

Flutter 现在将签名所有发布版本。

要了解有关签名应用的更多信息,请查看 Android 开发者文档中的签名您的应用

使用 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 中的 **Run** 和 **Debug** 选项构建和运行应用时,您的构建可能会失败并显示以下消息:

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.

您也可以选择手动支持 multidex,方法是遵循 Android 的指南并修改您项目的 Android 目录配置。必须指定一个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如果您的应用需要互联网访问,请将 android.permission.INTERNET 权限值添加到 android:name 属性。标准模板不包含此标签,但在开发期间允许互联网访问,以启用 Flutter 工具和正在运行的应用之间的通信。

查看或更改 Gradle 构建配置

#

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

[project]/android/app/build.gradle.kts
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.kts 中要调整的属性

#
属性用途默认值
compileSdk您的应用是针对哪个 Android API 级别编译的。这应该是可用的最高版本。如果您将此属性设置为 31,只要您的应用不使用 31 特有的 API,您就可以在运行 API 30 或更低版本的设备上运行您的应用。
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 运行时。

测试应用捆绑包

#

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

离线使用 bundle tool

#
  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 标志将生成一个“fat”APK,其中包含为您所有目标 ABI 编译的代码。这些 APK 比其拆分版本更大,导致用户在安装您的应用程序时下载不适用于其设备架构的原生二进制文件。

在设备上安装 APK

#

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

从命令行

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

发布到 Google Play 商店

#

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

更新应用的 versionCode

#

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

yaml
version: 1.0.0+1

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

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

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

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

Android 发布常见问题解答

#

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

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

#

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

什么是“fat”APK?

#

一个“fat”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.

接下来,选择构建变体。在主菜单中单击 **Build > Select Build Variant**。在 **Build Variants** 面板中选择任何一个变体(debug 是默认值)。

The build variant menu in Android Studio with Release selected.

生成的应用捆绑包或 APK 文件位于您应用文件夹内的 build/app/outputs