当我尝试获取订阅时,我遇到以下错误:
签名验证失败。 签名与数据不匹配。 应用内结算警告:购买签名验证 FAILED 。不添加项目。
我的代码是:
String base64EncodedPublicKey = MY_KEY;
// compute your public key and store it in base64EncodedPublicKey
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh noes, there was a problem.
MyDialogFragment alertDialog_generalError = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_general));
alertDialog_generalError.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
} //End if
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
//*************************************************
//Get App price
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
// handle error
MyDialogFragment alertDialog_generalError = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_general));
alertDialog_generalError.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
return;
}//End if
String premiumPrice = inventory.getSkuDetails(SKU_PREMIUM).getPrice();
btnPrice.setText(getResources().getString(R.string.btn_suscription) + " " + premiumPrice);
myProfile.setPriceApp(premiumPrice);
}
};
// //************************************
@Override
public void inapp() {
//myProfile.getGUID()
//mHelper.launchPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener, myProfile.getGUID() );
mHelper.launchSubscriptionPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener, myProfile.getGUID() );
}
//************************************
@Override
public void getPrice(Button btnPrice) {
Log.i(LOGTAG, "getPrice");
this.btnPrice = btnPrice;
List additionalSkuList = new ArrayList();
additionalSkuList.add(SKU_PREMIUM);
mHelper.queryInventoryAsync(true, additionalSkuList, mQueryFinishedListener);
}
//************************************************
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
if (result.getResponse() != -1005){
MyDialogFragment alertDialog_errorInApp = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_inApp));
alertDialog_errorInApp.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
}
return;
}
if (!verifyDeveloperPayload(purchase)) {
MyDialogFragment alertDialog_errorInApp = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_inApp));
alertDialog_errorInApp.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
return;
}
myProfile.setIsPremium(1);
loginPrefsEditor.putInt("IsPremium", 1);
}
};
//**********************************
//User PREMIUM or NOT PREMIUM
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
// Have we been disposed of in the meantime? If so, quit.
Log.i(LOGTAG, result.getMessage());
//if (mHelper == null) return;
//Is it a failure?
if (result.isFailure()) {
MyDialogFragment alertDialog_generalError = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_general));
alertDialog_generalError.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
return;
}
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// Do we have the premium upgrade?
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
if (mIsPremium == true){
myProfile.setIsPremium(1);
loginPrefsEditor.putInt("IsPremium", 1);
}else{
loginPrefsEditor.putInt("IsPremium", 0);
myProfile.setIsPremium(0);
}//End if-else
}
};
//****************************************
/** Verifies the developer payload of a purchase. */
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
if (!payload.equals(myProfile.getGUID())){
return false;
}else{
return true;
}//End if-else
}
我从控制台开发人员那里获得了base64EncodedPublicKey,并使用导出向导签署了我的项目。
答案 0 :(得分:5)
如果您使用其中一个测试SKU(android.test.purchased
...)完成了购买流程,则会发生此错误。这些购买不是真实的,因此它们没有签名,但是当您尝试使用IAB执行任何操作(如查询库存)时,它们是返回结果的一部分。不幸的是,一旦结果中的某些内容无法验证这些虚假购买会做什么,IAB就会退出。
有两种解决方法。首先,使验证始终通过测试。最安全的方法是更改verifyPurchase
中的IABUtils>Security
以仅在调试版本上返回true。
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
if (BuildConfig.DEBUG) {
return true;
}
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
TextUtils.isEmpty(signature)) {
Log.e(TAG, "Purchase verification failed: missing data.");
return false;
}
PublicKey key = Security.generatePublicKey(base64PublicKey);
return Security.verify(key, signedData, signature);
}
第二种方法是不对这些假购买进行验证。更好的是:只在调试版本上执行此操作。一种方法是更改verifyPurchase
的签名以接受SKU并将其用作检查的一部分。然后,您必须更改IabHelper才能使用此额外参数。
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature, String sku) {
if (BuildConfig.DEBUG) {
if (skuMatchesTestingSku(sku)) {
return true;
}
}
...
}
private static boolean skuMatchesTestingSku(String sku) {
return sku.equals("android.test.purchased") ||
sku.equals("android.test.canceled") ||
sku.equals("android.test.refunded") ||
sku.equals("android.test.item_unavailable");
}
这非常混乱,但多亏了应用程序结算的实施方式,我们无法做得更好。
答案 1 :(得分:0)
在我的情况下,base64EncodedPublicKey
是错误的。
答案 2 :(得分:-2)
将返回值设置为true在
中public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
return true;
}
测试后撤消更改