我从崩溃报告中得到了以下异常信息:
java.lang.RuntimeException: Unable to start service com.problemio.BillingService@4132b868 with Intent { act=com.android.vending.billing.PURCHASE_STATE_CHANGED cmp=com.problemio/.BillingService (has extras) }: java.lang.IllegalArgumentException: utils.Base64DecoderException: single trailing character at offset 19
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2376)
at android.app.ActivityThread.access$1900(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: utils.Base64DecoderException: single trailing character at offset 19
at utils.Security.generatePublicKey(Security.java:199)
at utils.Security.verifyPurchase(Security.java:118)
at com.problemio.BillingService.purchaseStateChanged(BillingService.java:545)
at com.problemio.BillingService.handleCommand(BillingService.java:421)
at com.problemio.BillingService.onStart(BillingService.java:398)
at android.app.Service.onStartCommand(Service.java:438)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
... 10 more
Caused by: utils.Base64DecoderException: single trailing character at offset 19
at utils.Base64.decode(Base64.java:529)
at utils.Base64.decode(Base64.java:444)
at utils.Base64.decode(Base64.java:390)
at utils.Security.generatePublicKey(Security.java:189)
... 16 more
java.lang.IllegalArgumentException: utils.Base64DecoderException: single trailing character at offset 19
at utils.Security.generatePublicKey(Security.java:199)
at utils.Security.verifyPurchase(Security.java:118)
at com.problemio.BillingService.purchaseStateChanged(BillingService.java:545)
at com.problemio.BillingService.handleCommand(BillingService.java:421)
at com.problemio.BillingService.onStart(BillingService.java:398)
at android.app.Service.onStartCommand(Service.java:438)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
at android.app.ActivityThread.access$1900(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: utils.Base64DecoderException: single trailing character at offset 19
at utils.Base64.decode(Base64.java:529)
at utils.Base64.decode(Base64.java:444)
at utils.Base64.decode(Base64.java:390)
at utils.Security.generatePublicKey(Security.java:189)
... 16 more
utils.Base64DecoderException: single trailing character at offset 19
at utils.Base64.decode(Base64.java:529)
at utils.Base64.decode(Base64.java:444)
at utils.Base64.decode(Base64.java:390)
at utils.Security.generatePublicKey(Security.java:189)
at utils.Security.verifyPurchase(Security.java:118)
at com.problemio.BillingService.purchaseStateChanged(BillingService.java:545)
at com.problemio.BillingService.handleCommand(BillingService.java:421)
at com.problemio.BillingService.onStart(BillingService.java:398)
at android.app.Service.onStartCommand(Service.java:438)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
at android.app.ActivityThread.access$1900(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
但我不太明白问题出在哪里。有什么建议吗?
它指向这个方法:
/**
* Decodes Base64 content using the supplied decodabet and returns
* the decoded byte array.
*
* @param source the Base64 encoded data
* @param off the offset of where to begin decoding
* @param len the length of characters to decode
* @param decodabet the decodabet for decoding Base64 content
* @return decoded data
*/
public static byte[] decode(byte[] source, int off, int len, byte[] decodabet)
throws Base64DecoderException {
int len34 = len * 3 / 4;
byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output
int outBuffPosn = 0;
byte[] b4 = new byte[4];
int b4Posn = 0;
int i = 0;
byte sbiCrop = 0;
byte sbiDecode = 0;
for (i = 0; i < len; i++) {
sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits
sbiDecode = decodabet[sbiCrop];
if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better
if (sbiDecode >= EQUALS_SIGN_ENC) {
// An equals sign (for padding) must not occur at position 0 or 1
// and must be the last byte[s] in the encoded value
if (sbiCrop == EQUALS_SIGN) {
int bytesLeft = len - i;
byte lastByte = (byte) (source[len - 1 + off] & 0x7f);
if (b4Posn == 0 || b4Posn == 1) {
throw new Base64DecoderException(
"invalid padding byte '=' at byte offset " + i);
} else if ((b4Posn == 3 && bytesLeft > 2)
|| (b4Posn == 4 && bytesLeft > 1)) {
throw new Base64DecoderException(
"padding byte '=' falsely signals end of encoded value "
+ "at offset " + i);
} else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) {
throw new Base64DecoderException(
"encoded value has invalid trailing byte");
}
break;
}
b4[b4Posn++] = sbiCrop;
if (b4Posn == 4) {
outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet);
b4Posn = 0;
}
}
} else {
throw new Base64DecoderException("Bad Base64 input character at " + i
+ ": " + source[i + off] + "(decimal)");
}
}
// Because web safe encoding allows non padding base64 encodes, we
// need to pad the rest of the b4 buffer with equal signs when
// b4Posn != 0. There can be at most 2 equal signs at the end of
// four characters, so the b4 buffer must have two or three
// characters. This also catches the case where the input is
// padded with EQUALS_SIGN
if (b4Posn != 0) {
if (b4Posn == 1) {
throw new Base64DecoderException("single trailing character at offset "
+ (len - 1));
}
b4[b4Posn++] = EQUALS_SIGN;
outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet);
}
byte[] out = new byte[outBuffPosn];
System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
return out;
}
错误似乎指向我的BillingService.java文件中的这些行。
at com.problemio.BillingService.purchaseStateChanged(BillingService.java:585)
at com.problemio.BillingService.handleCommand(BillingService.java:461)
at com.problemio.BillingService.onStart(BillingService.java:438)
585上的这条线是一条直线。
purchases = Security.verifyPurchase(signedData, signature);
在这种方法中:
private void purchaseStateChanged(int startId, String signedData, String signature) {
ArrayList<Security.VerifiedPurchase> purchases;
purchases = Security.verifyPurchase(signedData, signature);
if (purchases == null) {
return;
}
而第461行是这一行:
purchaseStateChanged(startId, signedData, signature);
在这种方法中:
public void handleCommand(Intent intent, int startId) {
String action = intent.getAction();
if (Consts.DEBUG) {
Log.i(TAG, "handleCommand() action: " + action);
}
if (Consts.ACTION_CONFIRM_NOTIFICATION.equals(action)) {
String[] notifyIds = intent.getStringArrayExtra(Consts.NOTIFICATION_ID);
confirmNotifications(startId, notifyIds);
} else if (Consts.ACTION_GET_PURCHASE_INFORMATION.equals(action)) {
String notifyId = intent.getStringExtra(Consts.NOTIFICATION_ID);
getPurchaseInformation(startId, new String[] { notifyId });
} else if (Consts.ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
String signedData = intent.getStringExtra(Consts.INAPP_SIGNED_DATA);
String signature = intent.getStringExtra(Consts.INAPP_SIGNATURE);
purchaseStateChanged(startId, signedData, signature);
} else if (Consts.ACTION_RESPONSE_CODE.equals(action)) {
long requestId = intent.getLongExtra(Consts.INAPP_REQUEST_ID, -1);
int responseCodeIndex = intent.getIntExtra(Consts.INAPP_RESPONSE_CODE,
ResponseCode.RESULT_ERROR.ordinal());
ResponseCode responseCode = ResponseCode.valueOf(responseCodeIndex);
checkResponseCode(requestId, responseCode);
}
}
第438行是这一行:
handleCommand(intent, startId);
在这种方法中:
@Override
public void onStart(Intent intent, int startId) {
handleCommand(intent, startId);
}
谢谢!
generatePublicKey
的是哪个公钥? - Michael Petrottautils.Security.verifyPurchase
示例代码将Base64字符串传递给Security.generatePublicKey
。如果这与您的操作相匹配,那么您肯定需要在将其放入类之前对PK进行Base64编码。 - Michael Petrotta