使用命令行发布 Android 应用

若要分发 .NET Multi-platform App UI (.NET MAUI) Android 应用,需要使用密钥存储中的密钥对其进行签名。 密钥存储是使用 Java 开发工具包 (JDK) 中的 keytool 创建的安全证书数据库。 发布 .NET MAUI Android 应用时需要密钥存储,因为 Android 无法运行尚未签名的应用。

创建密钥存储文件

在开发期间,.NET Android 使用调试密钥存储对应用进行签名,从而使应用可直接部署到仿真器,或是配置的用于运行可调试应用的设备。 但对于分发应用而言,此密钥存储不会被识别为有效密钥存储。 因此,必须创建私钥存储并将其用于对发布版本进行签名。 此步骤应该仅执行一次,因为同一密钥将用于发布更新,并可用于对其他应用进行签名。 生成密钥存储文件后,你可在生成应用时从命令行提供其详细信息,或配置项目文件以引用该文件。

若要创建秘钥存储文件,请执行以下步骤:

  1. 打开终端并导航到项目文件夹。

    提示

    如果 Visual Studio 处于打开状态,请使用“视图”>“终端”菜单在解决方案或项目的位置处打开终端。 导航到项目文件夹。

  2. 使用以下参数运行 keytool 工具:

    keytool -genkeypair -v -keystore {filename}.keystore -alias {keyname} -keyalg RSA -keysize 2048 -validity 10000
    

    重要

    如果计算机上安装了多个版本的 JDK,请确保从最新版本的 JDK 运行 keytool

    系统将提示你提供并确认密码、你的全名、组织单位、组织、城市或地区、州或省和国家/地区代码。 此信息不会显示在应用中,但包含在证书中。

    例如,若要在项目所在的同一文件夹中生成 myapp.keystore 文件并使用 myapp 别名,请使用以下命令:

    keytool -genkeypair -v -keystore myapp.keystore -alias myapp -keyalg RSA -keysize 2048 -validity 10000
    

    提示

    备份密钥存储和密码。 如果将其丢失,将无法使用相同的签名标识对应用进行签名。

查找密钥存储的签名

若要列出存储在密钥存储中的密钥,请通过 -list 选项使用 keytool

keytool -list -keystore {filename}.keystore

例如,若要列出名为 myapp.keystore 的密钥存储中的密钥,请使用以下命令:

keytool -list -keystore myapp.keystore

生成应用并对其进行签名

若要从命令行生成应用并使用密钥存储对其进行签名,请打开终端并导航到 .NET MAUI 应用项目的文件夹。 提供以下参数,运行 dotnet publish 命令:

参数
-f--framework 目标框架,即 net8.0-android
-c--configuration 生成配置,即 Release

警告

尝试发布 .NET MAUI 解决方案将导致 dotnet publish 命令尝试分别发布解决方案中的每个项目,如果已将其他项目类型添加到解决方案中,则可能会出现问题。 因此,dotnet publish 命令的作用域应为 .NET MAUI 应用项目。

如果项目文件的 <PropertyGroup> 中未提供其他生成参数,则可以在命令行上指定这些参数。 下表列出了一些常用参数:

参数
-p:ApplicationTitle 应用的用户可见名称。
-p:ApplicationId 应用的唯一标识符,如 com.companyname.mymauiapp
-p:ApplicationVersion 标识应用迭代的生成版本。
-p:ApplicationDisplayVersion 应用的版本号。
-p:AndroidKeyStore 指示是否应对应用签名的布尔值。 默认值为 false
-p:AndroidPackageFormats 以分号分隔的属性,指示要将应用打包为 APK 文件还是 AAB 文件。 设置为 aabapk,以便仅生成一种格式。 aab;apk 是发布版本的默认值。
-p:AndroidSigningKeyAlias 密钥存储中密钥的别名。 这是创建密钥存储时使用的 keytool -alias 值。
-p:AndroidSigningKeyPass 密钥存储文件中密钥的密码。 这是在创建密钥存储文件时为 keytool 提供的值,并且需要输入密钥存储密码。 这是因为默认密钥存储类型假定密钥密码和密钥存储密码相同。 此属性还支持 env:file: 前缀,它们可用于指定包含密码的环境变量或文件。 通过这些选项,可以防止密码显示在生成日志中。
-p:AndroidSigningKeyStore keytool 创建的密钥存储文件的文件名。 这是创建密钥存储时使用的 keytool -keystore 值。
-p:AndroidSigningStorePass 密钥存储文件的密码。 这是在创建密钥存储文件时为 keytool 提供的值,并且需要输入密钥存储密码。 这是因为默认密钥存储类型假定密钥存储密码和密钥密码相同。 此属性还支持 env:file: 前缀,它们可用于指定包含密码的环境变量或文件。 通过这些选项,可以防止密码显示在生成日志中。
-p:PublishTrimmed 指示是否应剪裁应用的布尔值。 发布版本的默认值为 true

应使用与 AndroidSigningKeyPassAndroidSigningStorePass 参数的值相同的密码。

有关生成属性的完整列表,请参阅生成属性

重要

这些参数的值不必在命令行上提供。 它们也可以在项目文件中提供。 如果在命令行和项目文件中提供了参数,则命令行参数优先。 有关在项目文件中提供生成属性的更多信息,请参见在项目文件中定义生成属性

使用以下参数运行 dotnet publish 命令来生成应用并对其签名:

dotnet publish -f net8.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore={filename}.keystore -p:AndroidSigningKeyAlias={keyname} -p:AndroidSigningKeyPass={password} -p:AndroidSigningStorePass={password}

注意

在 .NET 8 中,dotnet publish 命令默认为 Release 配置。 因此,生成配置可以从命令行中省略。

例如,使用以下命令,并使用以前创建的密钥存储生成应用并对其签名:

dotnet publish -f net8.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=myapp.keystore -p:AndroidSigningKeyAlias=myapp -p:AndroidSigningKeyPass=mypassword -p:AndroidSigningStorePass=mypassword

AndroidSigningKeyPassAndroidSigningStorePass 属性均支持 env:file: 前缀,它们可用于指定包含密码的环境变量或文件。 以这种方式指定密码可防止密码出现在生成日志中。 例如,要使用名为 AndroidSigningPassword 的环境变量:

dotnet publish -f net8.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=myapp.keystore -p:AndroidSigningKeyAlias=myapp -p:AndroidSigningKeyPass=env:AndroidSigningPassword -p:AndroidSigningStorePass=env:AndroidSigningPassword

重要

$(AndroidPackageFormat) 设置为 aab 时,不支持 env: 前缀。

要使用位于 C:\Users\user1\AndroidSigningPassword.txt 的文件:

dotnet publish -f net8.0-android -c Release -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=myapp.keystore -p:AndroidSigningKeyAlias=myapp -p:AndroidSigningKeyPass=file:C:\Users\user1\AndroidSigningPassword.txt -p:AndroidSigningStorePass=file:C:\Users\user1\AndroidSigningPassword.txt

发布生成并签署应用,然后将 AAB 和 APK 文件复制到 bin\Release\net8.0-android\publish 文件夹。 存在两个 AAB 文件:一个未签名,另一个已签名。 已签名的变体文件名中包含“-signed”

有关 dotnet publish 命令的更多信息,请参阅 dotnet publish

注意

对于 Android 应用,dotnet build 还可用于生成应用并对其签名。 但是,AAB 和 APK 文件将在 bin\Release\net8.0-android 文件夹中创建,而不是在 publish 子文件夹中创建。 此外,dotnet build 默认为 Debug 配置,因此需要 -c 参数来指定 Release 配置。

在项目文件中定义生成属性

在命令行上指定生成参数的替代方法是在 <PropertyGroup> 中的项目文件中指定它们。 下表列出了一些常见的生成属性:

属性 Value
<ApplicationTitle> 应用的用户可见名称。
<ApplicationId> 应用的唯一标识符,如 com.companyname.mymauiapp
<ApplicationVersion> 标识应用迭代的生成版本。
<ApplicationDisplayVersion> 应用的版本号。
<AndroidKeyStore> 指示是否应对应用签名的布尔值。 默认值为 false
<AndroidPackageFormats> 以分号分隔的属性,指示要将应用打包为 APK 文件还是 AAB 文件。 设置为 aabapk,以便仅生成一种格式。 aab;apk 是发布版本的默认值。
<AndroidSigningKeyAlias> 密钥存储中密钥的别名。 这是创建密钥存储时使用的 keytool -alias 值。
<AndroidSigningKeyPass> 密钥存储文件中密钥的密码。 这是在创建密钥存储文件时为 keytool 提供的值,并且需要输入密钥存储密码。 这是因为默认密钥存储类型假定密钥密码和密钥存储密码相同。 此属性还支持 env:file: 前缀,它们可用于指定包含密码的环境变量或文件。 通过这些选项,可以防止密码显示在生成日志中。
<AndroidSigningKeyStore> keytool 创建的密钥存储文件的文件名。 这是创建密钥存储时使用的 keytool -keystore 值。
<AndroidSigningStorePass> 密钥存储文件的密码。 这是在创建密钥存储文件时为 keytool 提供的值,并且需要输入密钥存储密码。 这是因为默认密钥存储类型假定密钥存储密码和密钥密码相同。 此属性还支持 env:file: 前缀,它们可用于指定包含密码的环境变量或文件。 通过这些选项,可以防止密码显示在生成日志中。
<PublishTrimmed> 布尔值,指示是否应剪裁应用。 发布版本的默认值为 true

有关生成属性的完整列表,请参阅生成属性

重要

这些生成属性的值不必在项目文件中提供。 发布应用时,还可以在命令行上提供它们。 这使你能够省略项目文件中的特定值。

以下示例显示用于生成 Android 应用和为其签名的典型属性组:

<PropertyGroup Condition="$(TargetFramework.Contains('-android')) and '$(Configuration)' == 'Release'">
    <AndroidSigningKeyStore>myapp.keystore</AndroidSigningKeyStore>
    <AndroidSigningKeyAlias>myapp</AndroidSigningKeyAlias>
</PropertyGroup>

本示例 <PropertyGroup> 增加一个条件检查,除非条件检查通过,否则阻止处理这些设置。 条件检查查找两个方面:

  1. 目标框架设置为包含 -android 文本的内容。
  2. 生成配置设置为 Release

如果其中任一条件未满足,则设置不会得到处理。 更重要的是,<AndroidSigningKeyStore><AndroidSigningKeyAlias> 不被设置,从而阻止应用进行签名。

出于安全原因,不应为项目文件中的 <AndroidSigningKeyPass><AndroidSigningStorePass> 提供值。 发布应用时,可以在命令行上提供这些值,或使用 env:file: 前缀防止密码出现在生成日志中。 例如,要使用名为 AndroidSigningPassword 的环境变量:

<PropertyGroup Condition="$(TargetFramework.Contains('-android')) and '$(Configuration)' == 'Release'">
    <AndroidSigningKeyStore>myapp.keystore</AndroidSigningKeyStore>
    <AndroidSigningKeyAlias>myapp</AndroidSigningKeyAlias>
    <AndroidSigningKeyPass>env:AndroidSigningPassword</AndroidSigningKeyPass>
    <AndroidSigningStorePass>env:AndroidSigningPassword</AndroidSigningStorePass>
</PropertyGroup>

重要

$(AndroidPackageFormat) 设置为 aab 时,不支持 env: 前缀。

或者,若要使用位于 C:\Users\user1\AndroidSigningPassword.txt 的文件:

<PropertyGroup Condition="$(TargetFramework.Contains('-android')) and '$(Configuration)' == 'Release'">
    <AndroidSigningKeyStore>myapp.keystore</AndroidSigningKeyStore>
    <AndroidSigningKeyAlias>key</AndroidSigningKeyAlias>
    <AndroidSigningKeyPass>file:C:\Users\user1\AndroidSigningPassword.txt</AndroidSigningKeyPass>
    <AndroidSigningStorePass>file:C:\Users\user1\AndroidSigningPassword.txt</AndroidSigningStorePass>
</PropertyGroup>

分发应用

可以使用以下方法之一分发已签名的 APK 或 AAB 文件:

  • 将 Android 应用分发给用户的最常见方法是通过 Google Play。 Google Play 要求将应用作为 Android 应用程序包 (AAB) 提交。 有关详细信息,请参阅 developer.android.com 上的将应用上传至 Play 管理中心
  • APK 文件可以通过网站或服务器分发到 Android 设备。 当用户从其 Android 设备浏览到下载链接时,系统会下载该文件。 如果用户已将其设置配置为允许安装来自未知来源的应用,则 Android 会自动开始在设备上安装应用。 有关选择允许来自未知源的应用的详细信息,请参阅 developer.android.com 上的用户选择使用未知应用和源

另请参阅