要测试应用,可以在命令行中使用 flutter run,或者在 IDE 中使用 RunDebug 选项。

当你准备好为应用创建发布版本时(例如 发布到 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.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,请向 flutter build apkflutter build appbundle 传递 --no-shrink 标志。

启用 multidex 支持

#

当编写大型应用或使用大型插件时,如果目标 API 为 20 或更低版本,你可能会遇到 Android 的 dex 限制(64k 方法)。在使用 flutter run 运行应用的调试版本(未启用缩减)时,也可能遇到这种情况。

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

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

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 keep file 以包含:

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 级别。你的应用应在此 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 发布文档。

更新应用的版​​本号

#

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

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 可能是你唯一的选择。

什么是 fat APK?

#

一个 fat APK 是一个单独的 APK,其中嵌入了多个 ABI 的二进制文件。它的优点是单个 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 中。