visual-studioxamarin.androidgoogle-playkeytoolapksigner

Visual Studio's AndroidApkSigner does not find key in keystore


I am getting this error when creating an APK within Visual Studio:

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

I am a longtime ASP.NET developer who is familiar with Visual Studio but this is my first Xamarin project. (I am not using Android Studio.) I am trying to deploy the Android build to Google Play. I have never uploaded an APK to Google Play so I cannot use Visual Studio's automatic deployment; I must perform a manual deployment first per Google's and Microsoft's instructions.

I am running Visual Studio 2017 15.7.5 (latest) with JDK 1.8. My project is using NETStandard.Library 2.0.3, Xamarin.Forms 3.1.0, and Microsoft.EntityFrameworkCore 2.1.1.

This question is similar to this question that has no answers but I am getting the error from within Visual Studio. If this is a duplicate, I apologize but I am unable to add additional details on that question.

I am using Google Play App Signing. I have created a key through Google Play. I downloaded the certificate in .der format. I have used keytool (from c:\Program Files\Java\jdk1.8.0_172\bin) to convert the .der file to .keystore with the following command:

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

I have re-run this utility a few times changing the options thinking perhaps that there might be a problem with case sensitivity on the alias or special characters in the password that keytool prompts for. In this instance, the alias is all alpha, all lowercase, and the password is alpha-numeric all lowercase. keytool asks to trust this certificate and I press "y".

This results in a file named .keystore. I renamed this to googleplay.keystore and I moved it to a more appropriate place.

I can double-check that the googleplay alias is present in the keystore file by running this command:

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
]

The "googleplay" alias most definitely exists! The certificate fingerprints match the keys that Google gave me (redacted).

In Visual Studio, I set the solution configuration to Release mode, I cleaned my entire solution (successful), rebuilt my entire solution (successful), and then right-clicked my Android project and clicked Archive... per these instructions.

As a side-note, that Microsoft article is extremely frustrating because it does not mention signing or this issue, and their articles on signing do not match how Google Play operates and seem to assume you have a correct APK uploaded to Google Play already (bypassing the chicken-or-egg Catch-22).

At first all I got was The archiving process has failed. Please see the Errors section for more details. The Error List panel is empty. The Output panel just says "java.exe" exited with code 2. I went to Tools -> Options -> Projects and Solutions -> Build and Run and changed MSBuild project build output verbosity from Minimal to Diagnostic and repeated the last few steps (clean, rebuild, archive). Now, the Output panel (slightly redacted) says:

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\27.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\27.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.

From the above output you can see what the (redacted) values are in my project's property's Android Package Signing tab. Through trial and error I discovered that the Keystore Password, Alias, and Alias Password are all required. I set the Keystore Password and Alias Password to be the same, since there is only one password associated with this keystore. As mentioned above, the password is lower-alpha-numeric (no special characters following the advice from another SO question).

Why is AndroidApkSigner failing to find the key in the keystore for the provided alias when keytool finds the key without problem?

And, I can't be the only one with this problem? Deploying from Visual Studio to Google Play should be a fairly common workflow, but I am not finding anybody else (besides this other unanswered SO question) who is experiencing this issue. What am I doing wrong?


Solution

  • I have discovered the answer to my question. The documentation on the Android Developer site will not work with Visual Studio. The ApkSigner that comes with Xamarin does not know what to do with it. Instead, use this to create your own release key:

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

    Note the -storetype pkcs12 at the end. This command is also modified to (1) write the file somewhere besides Program Files, (2) uses .keystore extension which Visual Studio likes, and (3) avoids special characters in the alias, which Visual Studio does not like, from what I've read. (Avoid special characters in the password, too.)

    Note, keytool is located in c:\Program Files\Java\jdk[version]\bin.

    The Clue

    When I followed the instructions on the documentation, I got a warning from 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.

    I also got this warning when verifying the key is correct:

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

    If you have an existing key and need to convert it, follow the command in the warning.

    Thank you:

    I want to thank Nick for explaining the reasoning behind signing and differentiating between all the keys.

    And thank you, Jon, for pointing me toward how to create my own private key.