We just had the same problem with one of our apps on the Amazon appstore. In our case we realized the problem only happened if these three conditions were true:
- Kindle Fire HD
- Facebook App installed and user logged in
- User also logged into facebook via Settings -> My Account -> Manage Social Accounts
That may explain why in your case it only happens in 5% of the cases.
As far as we could tell, Amazon resigns the .apk, which breaks the Facebook Android App Key Hash check.
The solution involved:
- Obtaining the Amazon .apk of our app (not the one we submitted, but the one distributed by the Amazon appstore)
- Extract the signing certificate from the .apk file
- Base64 encode the SHA digest of the encoded certificate
- Add the resulting Base64 key hash to our Facebook App settings
This fixed the problem.
Getting the .apk proved tricky. Applications reside in the /data/app folder of the device's filesystem. However, this directory is protected to prevent listing it, so unless you know the name of the file you're looking for, you're out of luck. You can of course, root the device. Alternatively you can try your blind luck by doing adb pull /data/app/<app-id><suffix>.apk where suffix is either an empty string or -1, -2, etc, until you succeed. E.g.:
$ adb pull /data/app/com.example.game.apk
remote object '/data/app/com.example.game.apk' does not exist
$ adb pull /data/app/com.example.game-1.apk
remote object '/data/app/com.example.game-1.apk' does not exist
$ adb pull /data/app/com.example.game-2.apk
3658 KB/s (1085140 bytes in 0.289s)
If this approach fails, rooting might be the only option.
Once you have the .apk file, you can use the code below to obtain the key hash. Save as Main.java, compile with javac Main.java and run with java Main <APK>, e.g.:
$ javac Main.java
$ java Main com.example.game-1.apk
com.example.game-1.apk: 478uEnKQV+fMQT8Dy4AKvHkYibo=
Adding 478uEnKQV+fMQT8Dy4AKvHkYibo= to the key hashes of our Facebook App settings then fixes the problem. I'm curious if other people find the same hash we got (which would mean all Amazon games are resigned with the same key). In our case, the hash started with wwYPegrz....
Here's the code:
import java.security.MessageDigest;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import sun.misc.BASE64Encoder;
public class Main {
public static void main(String[] args) throws Exception {
for (String jarFilename : args)
extractHash(jarFilename);
}
private static void extractHash(String jarFilename) throws Exception {
BASE64Encoder base64 = new BASE64Encoder();
MessageDigest sha1 = MessageDigest.getInstance("SHA");
Set<Certificate> certificates = new HashSet<Certificate>();
JarFile jarFile = new JarFile(jarFilename);
for (JarEntry jarEntry : Collections.list(jarFile.entries())) {
jarFile.getInputStream(jarEntry).skip(Long.MAX_VALUE);
Certificate[] certs = jarEntry.getCertificates();
if (certs == null)
continue;
certificates.addAll(Arrays.asList(certs));
}
System.out.printf("%s:", jarFilename);
for (Certificate cert : certificates) {
byte[] digest = sha1.digest(cert.getEncoded());
System.out.printf(" %s", base64.encode(digest));
}
if (certificates.isEmpty())
System.out.printf(" NOT SIGNED!");
System.out.println();
jarFile.close();
}
}