若要将 .NET 多平台应用 UI (.NET MAUI) Android 应用分发,需要使用密钥存储中的密钥对其进行签名。 密钥存储 是使用 keytool Java 开发工具包 (JDK) 创建的安全证书数据库。 发布 .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 ,提供以下参数:

    尝试发布 .NET MAUI 解决方案将导致 dotnet publish 命令尝试单独发布解决方案中的每个项目,这可能会导致将其他项目类型添加到解决方案时出现问题。 因此,命令 dotnet publish 的范围应限定为 .NET MAUI 应用项目。

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

    -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 适用于发布版本。

    应使用与 和 AndroidSigningStorePass 参数的值AndroidSigningKeyPass相同的密码。

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

    无需在命令行上提供这些参数的值。 还可以在项目文件中提供它们。 在命令行和项目文件中提供参数时,命令行参数优先。 有关在项目文件中提供生成属性的详细信息,请参阅 在项目文件中定义生成属性

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

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

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

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

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

    dotnet publish -f net7.0-android -c Release -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 net7.0-android -c Release -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\net7.0-android\publish 文件夹。 有两个 AAB 文件 - 一个未签名文件,另一个已签名文件。 带符号的变体在文件名中具有 -signed

    有关命令的详细信息 dotnet publish ,请参阅 dotnet publish

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

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

    <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>添加条件检查,以防止处理这些设置,除非条件检查通过。 条件检查查找两项内容:

  • 目标框架设置为包含文本 -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>
    

    当 设置为 aab$(AndroidPackageFormat),不支持 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 App Bundle (AAB) 提交。 有关详细信息,请参阅在 developer.android.com 上将应用上传到 Play Console
  • APK 文件可以通过网站或服务器分发到 Android 设备。 当用户从 Android 设备浏览到下载链接时,会下载该文件。 Android 将自动开始在设备上安装它,前提是用户已配置其设置以允许安装来自未知来源的应用。 有关选择允许来自未知源的应用的详细信息,请参阅 用户选择加入 developer.android.com 上的未知应用和源
  • 关于 developer.android.com 上的 Android 应用程序包
  •