使用命令行发布 Android 应用

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

创建密钥存储文件

在开发过程中,.NET for 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> 内的项目文件中指定它们。 下表列出了一些常见的生成属性:

属性
<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 上的用户选择使用未知应用和源

另请参阅