Visual Studio 的 AndroidApkSigner 在密钥库中找不到密钥

Visual Studio's AndroidApkSigner does not find key in keystore

我在 Visual Studio 中创建 APK 时遇到此错误:

Failed to load signer "signer #1": C:\...\googleplay.keystore entry "googleplay" does not contain a key

我是一名长期 ASP.NET 的开发人员,熟悉 Visual Studio 但这是我的第一个 Xamarin 项目。 (我没有使用 Android Studio。)我正在尝试将 Android 构建部署到 Google Play。我从未将 APK 上传到 Google Play,所以我无法使用 Visual Studio 的自动部署;我必须先按照 Google 和 Microsoft 的说明执行手动部署。

我是 运行ning Visual Studio 2017 15.7.5(最新),JDK 1.8。我的项目正在使用 NETStandard.Library 2.0.3、Xamarin.Forms 3.1.0 和 Microsoft.EntityFrameworkCore 2.1.1.

这个问题与 this question that has no answers 类似,但我从 Visual Studio 中得到错误。如果这是重复的,我深表歉意,但我无法添加有关该问题的更多详细信息。

我正在使用 Google Play App Signing。我通过 Google Play 创建了一个密钥。我下载了 .der 格式的证书。我使用 keytool(来自 c:\Program Files\Java\jdk1.8.0_172\bin)通过以下命令将 .der 文件转换为 .keystore:

keytool -importcert -alias googleplay -file "C:\...\deployment_cert.der"

我已经重新运行这个实用程序几次更改选项,我想可能是 keytool 提示的密码中的别名或特殊字符区分大小写有问题。在本例中,别名全是字母,全是小写,密码是全小写的字母数字。 keytool 要求信任此证书,然后我按 "y"。

这会生成一个名为 .keystore 的文件。我将其重命名为 googleplay.keystore 并将其移动到更合适的位置。

我可以通过 运行 执行以下命令仔细检查 googleplay 别名是否存在于密钥库文件中:

C:\Program Files\Java\jdk1.8.0_172\bin>keytool -v -list -keystore "C:\...\googleplay.keystore" -alias googleplay
Enter keystore password:
Alias name: googleplay
Creation date: Jul 23, 2018
Entry type: trustedCertEntry

Owner: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Issuer: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Serial number: e8************************************8a
Valid from: Thu Jul 19 14:18:56 EDT 2018 until: Sun Jul 19 14:18:56 EDT 2048
Certificate fingerprints:
         MD5:  0D:**:**:**:**:**:**:**:**:**:**:**:**:**:**:C8
         SHA1: 11:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:CD
         SHA256: D0:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**:74
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

"googleplay" 别名绝对存在!证书指纹与 Google 给我的密钥相匹配(编辑)。

在Visual Studio中,我将解决方案配置设置为发布模式,我清理了我的整个解决方案(成功),重建了我的整个解决方案(成功),然后右键单击我的Android项目并点击 Archive...these instructions

作为旁注,微软的那篇文章非常令人沮丧,因为它没有提到签名或这个问题,而且他们的 articles on signing 与 Google Play 的运作方式不符,并且似乎假设你已将正确的 APK 上传到 Google 已经播放(绕过先有鸡还是先有蛋的第 22 条军规)。

起初我得到的只是The archiving process has failed. Please see the Errors section for more details.错误列表面板是空的。输出面板只显示 "java.exe" exited with code 2. 我去了 Tools -> Options -> Projects and Solutions -> Build and Run 并将 MSBuild project build output verbosityMinimal 更改为 Diagnostic 并重复了最后几个步骤(清理、重建、归档) .现在,输出面板(略有编辑)显示:

Using "AndroidApkSigner" task from assembly "C:\...\MSBuild\Xamarin\Android\Xamarin.Android.Build.Tasks.dll".
Task "AndroidApkSigner"
AndroidApkSigner:
  ApkSignerJar: C:\Program Files (x86)\Android\android-sdk\build-tools.0.3\lib\apksigner.jar
  ApkToSign: bin\Release\com.mycompany.myproject.apk
  ManifestFile: obj\Release\android\AndroidManifest.xml
  AdditionalArguments: 
C:\Program Files\Java\jdk1.8.0_172\bin\java.exe -jar "C:\Program Files (x86)\Android\android-sdk\build-tools.0.3\lib\apksigner.jar" sign --ks "C:\...\googleplay.keystore" --ks-pass pass:******** --ks-key-alias googleplay --key-pass pass:******** --min-sdk-version 19 --max-sdk-version 27  C:\...\myproject.Android\bin\Release\com.mycompany.myproject.apk 
Failed to load signer "signer #1": C:\...\googleplay.keystore entry "googleplay" does not contain a key
"java.exe" exited with code 2.
Done executing task "AndroidApkSigner" -- FAILED.
Done building target "_Sign" in project "myproject.Android.csproj" -- FAILED.
Done building project "myproject.Android.csproj" -- FAILED.
Build FAILED.

从上面的输出中,您可以看到我的项目 属性 的 Android 包签名选项卡中的(编辑)值是什么。通过反复试验,我发现 Keystore Password、Alias 和 Alias Password 都是必需的。我将密钥库密码和别名密码设置为相同,因为只有一个密码与此密钥库关联。如上所述,密码是小写字母数字(根据另一个 SO 问题的建议没有特殊字符)。

为什么当 keytool 可以毫无问题地找到密钥时,AndroidApkSigner 无法在提供的别名的密钥库中找到密钥?

而且,我不是唯一遇到这个问题的人吗?从 Visual Studio 部署到 Google Play 应该是一个相当常见的工作流程,但我没有找到其他人(除了 this other unanswered SO question)遇到这个问题。我做错了什么?

您遗漏的重要事实:

Google Play 永远不会给你一个用于签名的密钥。它只会给你证书来验证。

我将从您可能知道的基础知识开始。在 public 密钥密码学中,有一个私钥和一个 public 密钥。只有签名的人才有私钥。否则任何人都可以签名。 public 密钥任何人都可以拥有。他们可以用它来检查签名是否有效。

upload_cert.der 下载 仅包含 public 密钥。之所以Google Play让你下载验证。您可以离线验证您的签名是否符合 Play 商店的预期。您可能永远不需要这样做。

为什么 Google 不给你签名密钥?

Google Play 不向您提供上传证书的私钥有两个原因。

  1. Google 没有您上传密钥的私有部分!当您注册 Google Play 应用签名时,您创建了上传密钥的私钥部分。你从来没有把它给 Google。 Google 只有 public 关键部分。
  2. 如果Google确实给了你,那钥匙就没有价值了。上传密钥的全部意义在于,即使黑客侵入了您的 Play 管理中心帐户,他们仍然无法上传您应用的新版本。他们也需要上传密钥。上传密钥意味着 Google Play 知道该应用来自您。如果他们让您从您的帐户下载签名密钥,那么黑客也可以下载它。那就一文不值了

如何获取签名所需的上传密钥?

那么现在您可能遇到的问题是 "how do I get the public key I need for signing?"。答案是"you create it"。当您第一次上传您的 APK 时,该 APK 是用密钥签名的(Google 坚持这样做)。它可能存储在您的 Visual Studio 中。该密钥将成为您的上传密钥。找到你保存它的地方。

万一丢了怎么办?

现在您可能不知道您最初使用的密钥在哪里。这就是 Google Play App Signing 的伟大之处。如果您自己签署您的应用程序并丢失了签名密钥,您将被卡住,您必须创建一个新的应用程序。但是使用 Google Play App Signing,您可以联系 Play Console 支持,他们可以帮助您。 The process is on the help page.

查看标题为 "Create a new upload key" 的部分。请注意,第 1 步是 您创建密钥 。 Google 仍然没有。

我找到了问题的答案。 documentation on the Android Developer site 不适用于 Visual Studio。 Xamarin自带的ApkSigner不知道拿它干什么。相反,使用它来创建您自己的发布密钥:

keytool -v -list -keystore c:\temp\myreleasekey.keystore -alias myalias -storetype pkcs12

注意最后的-storetype pkcs12。此命令也被修改为 (1) 将文件写入 Program Files 之外的某个地方,(2) 使用 Visual Studio 喜欢的 .keystore 扩展名,以及 (3) 避免别名中的特殊字符,[=41] =] 不喜欢,从我读过的。 (密码中也要避免使用特殊字符。)

注意,keytool 位于 c:\Program Files\Java\jdk[version]\bin

线索

当我按照 the documentation 上的说明进行操作时,我收到了来自 keytool 的警告:

Warning: The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using keytool -importkeystore -srckeystore c:\temp\myreleasekey.jks -destkeystore c:\temp\myreleasekey.jks -deststoretype pkcs12.

我在验证密钥是否正确时也收到此警告:

keytool -v -list -keystore c:\temp\myreleasekey.jks -alias myalias

如果您已有密钥并需要转换它,请按照警告中的命令进行操作。

谢谢:

感谢 Nick 解释了签名和区分所有密钥的原因。

乔恩,谢谢你指导我如何创建我自己的私钥。

禁用选项“使用以下密钥库详细信息签署 .APK 文件。

你会得到这个选项

右键单击 android 项目 select 属性 转到 Android 包签名.

对我来说,问题与 packaging/signing 屏幕有关。我最终从签名屏幕上删除了所有内容,然后构建了存档。

构建完成后,我点击存档并点击分发。此时它要求我提供密钥库和密码。我输入了它们并签署了apk。我用那个来旁加载应用程序,效果很好。