我有一种游戏类型的应用程序。我经历了很多冲浪,但我没有得到任何满意的解决方案。在这里,用户可以多次购买硬币包。我的代码中存在一些问题,因此用户只能购买一次。我已阅读documentation about consumable IAP(在App App中),但问题仍然存在。如果我进行consumablePurchase()调用,它会给出BILLING_RESPONSE_RESULT_DEVELOPER_ERROR(ResponseCode 5)。
步骤:
1)致电purchasePackage(“android.test.iap.500coins”)
public void purchasePackage(String product_id) {
try {
Log.i(TAG, "product name : " + product_id);
package_name = product_id;
Bundle buyIntentBundle = mService
.getBuyIntent(3, getPackageName(), product_id, "inapp",
"C890B68423F8EA57F3ED38C3DCC816D7E389F4Cdc4961C23540dadC866B8CFFC5");
Log.i(TAG,
"buy intent response : "
+ buyIntentBundle
.getInt("BILLING_RESPONSE_RESULT_OK"));
if (buyIntentBundle.getInt("BILLING_RESPONSE_RESULT_OK") == 0) {
Log.i(TAG, "buyIntentBundle created");
PendingIntent pendingIntent = buyIntentBundle
.getParcelable("BUY_INTENT");
Log.i(TAG, "pendingIntent created");
startIntentSenderForResult(pendingIntent.getIntentSender(),
1101, new Intent(), Integer.valueOf(0),
Integer.valueOf(0), Integer.valueOf(0));
Log.i(TAG, "startIntentSenderForResult started");
} else
Log.i(TAG, "getBuyIntent response not ok");
} catch (RemoteException e) {
// TODO: handle exception
Log.e(TAG, "RemoteException : " + e.getMessage());
} catch (Exception e) {
// TODO: handle exception
Log.e(TAG, "Error in buyStructure : " + e.getMessage());
}
}
2)获取onActivityResult(int requestCode,int resultCode,Intent data)中的响应,并在获得purchasePackage()的响应后生成consumablePurchase()
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
Log.i(TAG, "requestCode : " + requestCode + " :resultCode : "
+ resultCode);
if (data != null && requestCode == 1101) {
int responseCode = data.getIntExtra("RESPONSE_CODE", -1);
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
Log.i(TAG, "responseCode : " + responseCode);
if (resultCode == RESULT_OK) {
try {
switch (responseCode) {
case 0:
/*new Thread() {
@Override
public void run() {
mHandler.sendEmptyMessage(purchaseStart);
StartupSync purchaseSync = new StartupSync(
InAppActivity.this, mHandler);
purchaseSync.purchasePackage(package_name);
mHandler.sendEmptyMessage(purchaseComplete);
}
}.start(); */
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString("productId");
String purchaseToken = jo.getString("purchaseToken");
Log.i(TAG, "You have bought the " + sku
+ ". Excellent choice,adventurer!");
int coins = Integer.parseInt(db.selectSettingsValue("coins"));
Log.i(TAG, "coins " + coins);
coins = coins + intIncCoins;
Log.i(TAG, "coins " + coins);
db.updateSettings("coins", coins + "");
Toast.makeText(
InAppActivity.this,
"Thank You !",
Toast.LENGTH_SHORT).show();
finish();
int response = mService.consumePurchase(3, sku, purchaseToken);
Toast.makeText(
InAppActivity.this,
"Response : " + response ,
Toast.LENGTH_LONG).show();
break;
case 1:
Log.i(TAG, "BILLING_RESPONSE_RESULT_USER_CANCELED");
Toast.makeText(InAppActivity.this,
"User pressed back or canceled a dialog",
Toast.LENGTH_SHORT).show();
break;
case 3:
Log.i(TAG,
"BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE");
Toast.makeText(
InAppActivity.this,
"Billing API version is not supported for the type requested",
Toast.LENGTH_SHORT).show();
break;
case 4:
Log.i(TAG, "BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE");
Toast.makeText(
InAppActivity.this,
"Requested product is not available for purchase",
Toast.LENGTH_SHORT).show();
break;
case 5:
Log.i(TAG, "BILLING_RESPONSE_RESULT_DEVELOPER_ERROR");
Toast.makeText(
InAppActivity.this,
"Invalid arguments provided to the API. This error can also indicate that the application was not correctly signed or properly set up for In-app Billing in Google Play, or does not have the necessary permissions in its manifest",
Toast.LENGTH_SHORT).show();
break;
case 6:
Log.i(TAG, "BILLING_RESPONSE_RESULT_ERROR");
Toast.makeText(InAppActivity.this,
"Fatal error during the API action",
Toast.LENGTH_SHORT).show();
break;
case 7:
Log.i(TAG, "BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED");
Toast.makeText(
InAppActivity.this,
"Failure to purchase since item is already owned",
Toast.LENGTH_SHORT).show();
break;
case 8:
Log.i(TAG, "BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED");
Toast.makeText(InAppActivity.this,
"Failure to consume since item is not owned",
Toast.LENGTH_SHORT).show();
break;
}
} catch (JSONException e) {
Log.i(TAG, "Failed to parse purchase data.");
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(InAppActivity.this, "Purchase Failded",
Toast.LENGTH_SHORT).show();
}
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(InAppActivity.this, "Purchase Canceled",
Toast.LENGTH_SHORT).show();
}
super.onActivityResult(requestCode, resultCode, data);
}
即使我尝试了另一种方法,例如获取所有购买的IAP阵列并使其成为可消耗品。我在splash活动中编写了代码。打印日志为here。
为什么一次又一次地给出同样的错误?这是谷歌自己在2013年3月解决的一个错误。
任何建议/建议均可接受!
答案 0 :(得分:3)
发生这种情况是因为你没有正确添加Consume监听器,首先让我们知道为什么需要消费完成监听器(和queryInventoryAsync),当你的商品被购买时,Google Play商店注册了你的商品被成功购买,以便谷歌播放允许用户下次从同一个谷歌帐户购买相同的产品。
确保您已将所有此方法正确地放入您的活动中:
开始设置
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
return;
}
// Hooray, IAB is fully set up. Now, let's get an inventory of
// stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
活动结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + ","
+ data);
if (mHelper == null)
return;
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
查询广告资源完成监听器
// 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) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// // Check for gas delivery -- if we own gas, we should fill up the
// tank immediately
Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
Log.d(TAG, "We have gas. Consuming it.");
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
mConsumeFinishedListener);
return;
}
// update UI
// updateUi();
// setWaitScreen(false);
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
消费完成listerner
// Called when consumption is complete
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
Log.d(TAG, "Consumption finished. Purchase: " + purchase
+ ", result: " + result);
// We know this is the "gas" sku because it's the only one we
// consume,
// so we don't check which sku was consumed. If you have more than
// one
// sku, you probably should check...
if (result.isSuccess()) {
// successfully consumed, so we apply the effects of the item in
// our
// game world's logic, which in our case means filling the gas
// tank a bit
Log.d(TAG, "Consumption successful. Provisioning.");
mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
// saveData();
alert("You filled 1/4 tank. Your tank is now "
+ String.valueOf(mTank) + "/4 full!");
} else {
complain("Error while consuming: " + result);
}
// updateUi();
// setWaitScreen(false);
Log.d(TAG, "End consumption flow.");
}
};
关于购买完成侦听器
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: "
+ purchase);
if(mHelper == null)
return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
// setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
// setWaitScreen(false);
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// bought 1/4 tank of gas. So consume it.
Log.d(TAG, "Purchase is gas. Starting gas consumption.");
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
}
};
修改强>
同时确保您也遵循了这些链接,
希望它会对你有所帮助。
答案 1 :(得分:0)