It seems that if an Android phone is not logged in to Google Play, a checkAccess-call will throw a NullPointerException and eventually crash the application:
// user not logged in to Google Play
LicenseChecker licenseChecker = new LicenseChecker(...);
licenseChecker.checkAccess(...) // throws a nullpointer exception and crasches the app
The NullPointerException happens deep inside the Android framework in a separate thread:
FATAL EXCEPTION: background thread
java.lang.NullPointerException
com.google.android.vending.licensing.LicenseValidator.verify()
hence there seems no way for the application to catch it and avoid the crash.
Any ideas how to avoid this crash? (t should be a legal situation not to be logged into Google Play)
The only way I can think of is to check Google Play login status prior to invoking checkAccess.
If you are simply trying to run your code on an android emulator, you can alternatively open and sign into the Google Play Store, which will update Google Play Services and fix the problem
I'm downvoting @Ben Lee's answer.
Building upon the recommendation that @jssingh made above, I went with the following solution:
public void verify(PublicKey publicKey, int responseCode, String signedData, String signature) {
String userId = null;
// Skip signature check for unsuccessful requests
ResponseData data = null;
if (signedData != null && (responseCode == LICENSED || responseCode == NOT_LICENSED ||
responseCode == LICENSED_OLD_KEY)) {
// Verify signature.
try {
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
....
}
}
........
if (signedData == null) {
Crashlytics.logException(new Exception("Licensing signedData is null - responseCode=" + responseCode));
}
switch (responseCode) {
case LICENSED:
case LICENSED_OLD_KEY:
int limiterResponse = mDeviceLimiter.isDeviceAllowed(userId);
handleResponse(limiterResponse, data);
break;
.....
}
I leveraged Crashlytics logging to validate the claim that you CANNOT just assume NOT_LICENSED when signedData is null.
As a matter of fact, this is the condition I see my code taking with this additional check in place:
case ERROR_CONTACTING_SERVER:
Log.w(TAG, "Error contacting licensing server.");
handleResponse(Policy.RETRY, data);
break;
Seems legit :)
I modified the method LicenseValidator.verify(), adding a protection check at the begining:
public void verify(PublicKey publicKey, int responseCode, String signedData, String signature) {
if (signedData==null){
handleInvalidResponse();
return;
}
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With