Skip to main content

构建和发布 Android 应用

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

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

添加启动器图标

#

创建新的 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 组件

#

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

例如:

  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 方法 dex 限制。在使用未启用缩减的 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 | 如果您的应用需要访问互联网,请将 android.permission.INTERNET 权限 值添加到 android:name 属性中。标准模板不包含此标签,但在开发过程中允许访问互联网,以启用 Flutter 工具和正在运行的应用之间的通信。 |

查看或更改 Gradle 构建配置

#

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

[project]/android/app/build.gradle
kotlin
android {
    namespace = "com.example.[project]"
    // 任何以 "flutter." 开头的值都从 Flutter Gradle 插件获取其值。
    // 要更改这些默认值,请在此文件中进行更改。
    compileSdk = flutter.compileSdkVersion
    ndkVersion = flutter.ndkVersion

    ...

    defaultConfig {
        // TODO: 指定您自己唯一的应用程序 ID (https://developer.android.com/studio/build/application-id.html)。
        applicationId = "com.example.[project]"
        // 您可以更新以下值以匹配您的应用程序需求。
        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion
        // 这两个属性使用在此文件中其他位置定义的值。
        // 您可以在属性声明中设置这些值,或者使用变量。
        versionCode = flutterVersionCode.toInteger()
        versionName = flutterVersionName
    }

    buildTypes {
        ...
    }
}

build.gradle 中需要调整的属性

#
属性目的默认值
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 运行时。

测试应用包

#

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

使用 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

#

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

在命令行中:

  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)

Android Studio 中的 Gradle 构建脚本菜单。

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

Android Studio 中的构建变体菜单,已选择 Release。

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