若要分发 .NET 多平台应用 UI (.NET MAUI) Android 应用,需要使用密钥存储中的密钥对其进行签名。
密钥存储是使用 Java 开发工具包(JDK)创建keytool的安全证书的数据库。 发布 .NET MAUI Android 应用时需要密钥存储,因为 Android 不会运行尚未签名的应用。
创建密钥存储文件
在开发过程中,适用于 Android 的 .NET 使用调试密钥存储对应用进行签名,该密钥存储允许它直接部署到模拟器或配置为运行可调试应用的设备。 但是,用于应用分发,此密钥存储未被认定为有效的密钥存储。 因此,必须创建私钥存储并用于对发布版本进行签名。 这是一个仅应执行一次的步骤,因为同一密钥将用于发布更新,并可用于对其他应用进行签名。 生成密钥存储文件后,你将在生成应用时从命令行提供其详细信息,或将项目文件配置为引用它。
执行以下步骤创建密钥存储文件:
打开终端并导航到项目的文件夹。
小窍门
如果 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小窍门
备份密钥存储和密码。 如果丢失,将无法使用相同的签名标识对应用进行签名。
查找密钥库的签名
若要列出存储在密钥存储中的密钥,请使用keytool-list选项:
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 发布版本。 |
应使用与参数值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 文件夹中创建,而不是 发布 子文件夹。
dotnet build 还默认为 Debug 配置,因此 -c 需要参数来指定 Release 配置。
在项目文件中定义生成属性
在命令行上指定生成参数的替代方法是在 <PropertyGroup> 内的项目文件中指定它们。 下表列出了一些常见的生成属性:
| 财产 | 价值 |
|---|---|
<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>
重要
env:前缀在$(AndroidPackageFormat)设置为aab时不支持。
或者,若要使用位于 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)。 有关详细信息,请参阅 将应用上传到 Play Console 在 developer.android.com 上
- APK 文件可以通过网站或服务器分发到 Android 设备。 当用户从其 Android 设备浏览到下载链接时,会下载该文件。 如果用户已配置其设置以允许从未知源安装应用,Android 会自动开始在设备上安装它。 有关如何选择启用来自未知来源的应用程序的详细信息,请参阅 developer.android.com 上的 用户选择同意未知应用程序和来源 。