2

当我尝试获取订阅时,出现以下错误:

签名认证失败。签名与数据不匹配。应用内计费警告:购买签名验证失败。不添加项目。

我的代码是:

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,并使用导出向导签署了我的项目。

4

3 回答 3

5

如果您曾经使用其中一个测试 SKU ( android.test.purchased...) 完成购买流程,则可能会发生此错误。这些购买不是真实的,因此它们没有签名,但它们是您尝试对 IAB 执行任何操作(例如查询库存)时返回的结果的一部分。不幸的是,一旦结果中的某些内容无法验证这些虚假购买会做什么,IAB 就会退出。

有两种方法可以解决这个问题。首先,让验证在测试中总是通过。最安全的方法是更改​​为仅verifyPurchaseIABUtils>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");
}

这是非常混乱的,但由于应用内计费的实施方式,我们能做的不多。

于 2016-02-24T11:45:00.860 回答
0

就我而言,这base64EncodedPublicKey是错误的。

于 2018-08-07T21:20:35.443 回答
-2

将返回值设置为 true

public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
    return true;
}

测试后撤消更改

于 2015-01-22T06:32:32.810 回答