使用命令行发布 Android 应用
若要分发 .NET Multi-platform App UI (.NET MAUI) Android 应用,需要使用密钥存储中的密钥对其进行签名。 密钥存储是使用 Java 开发工具包 (JDK) 中的 keytool
创建的安全证书数据库。 发布 .NET MAUI Android 应用时需要密钥存储,因为 Android 无法运行尚未签名的应用。
创建密钥存储文件
在开发期间,.NET Android 使用调试密钥存储对应用进行签名,从而使应用可直接部署到仿真器,或是配置的用于运行可调试应用的设备。 但对于分发应用而言,此密钥存储不会被识别为有效密钥存储。 因此,必须创建私钥存储并将其用于对发布版本进行签名。 此步骤应该仅执行一次,因为同一密钥将用于发布更新,并可用于对其他应用进行签名。 生成密钥存储文件后,你可在生成应用时从命令行提供其详细信息,或配置项目文件以引用该文件。
若要创建秘钥存储文件,请执行以下步骤:
打开终端并导航到项目文件夹。
提示
如果 Visual Studio 处于打开状态,请使用“视图”>“终端”菜单在解决方案或项目的位置处打开终端。 导航到项目文件夹。
使用以下参数运行 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 文件。 设置为 aab 或 apk ,以便仅生成一种格式。 aab;apk 是发布版本的默认值。 |
-p:AndroidSigningKeyAlias |
密钥存储中密钥的别名。 这是创建密钥存储时使用的 keytool -alias 值。 |
-p:AndroidSigningKeyPass |
密钥存储文件中密钥的密码。 这是在创建密钥存储文件时为 keytool 提供的值,并且需要输入密钥存储密码。 这是因为默认密钥存储类型假定密钥密码和密钥存储密码相同。 此属性还支持 env: 和 file: 前缀,它们可用于指定包含密码的环境变量或文件。 通过这些选项,可以防止密码显示在生成日志中。 |
-p:AndroidSigningKeyStore |
由 keytool 创建的密钥存储文件的文件名。 这是创建密钥存储时使用的 keytool -keystore 值。 |
-p:AndroidSigningStorePass |
密钥存储文件的密码。 这是在创建密钥存储文件时为 keytool 提供的值,并且需要输入密钥存储密码。 这是因为默认密钥存储类型假定密钥存储密码和密钥密码相同。 此属性还支持 env: 和 file: 前缀,它们可用于指定包含密码的环境变量或文件。 通过这些选项,可以防止密码显示在生成日志中。 |
-p:PublishTrimmed |
指示是否应剪裁应用的布尔值。 发布版本的默认值为 true 。 |
应使用与 AndroidSigningKeyPass
和 AndroidSigningStorePass
参数的值相同的密码。
有关生成属性的完整列表,请参阅生成属性。
重要
这些参数的值不必在命令行上提供。 它们也可以在项目文件中提供。 如果在命令行和项目文件中提供了参数,则命令行参数优先。 有关在项目文件中提供生成属性的更多信息,请参见在项目文件中定义生成属性。
使用以下参数运行 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
AndroidSigningKeyPass
和 AndroidSigningStorePass
属性均支持 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 文件。 设置为 aab 或 apk ,以便仅生成一种格式。 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>
增加一个条件检查,除非条件检查通过,否则阻止处理这些设置。 条件检查查找两个方面:
- 目标框架设置为包含
-android
文本的内容。 - 生成配置设置为
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 上的用户选择使用未知应用和源。
另请参阅
- developer.android.com 上的关于 Android 应用程序包
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈