官方文档
发布app到海外市场,内购不免要使用Google支付,然后发现集成Google支付有些流程和注意事项比起国内的支付宝、微信要复杂一些,在此记录一下.
(1)FQ工具是必须的.
(2)Google支付还要求手机安装Google三件套,如果没有安装,如下:
(3)准备开发者账号 Google开发者管理中心
(4)创建应用和提交测试版本(一般为Beta测试版),创建完后,要为应用添加商品,在添加测试人员账号,点击生成的链接即可,记录密匙
(5)关联google API 和 后台配置客户端
这2个有问题会出现
"reason": "projectNotLinked",
"message": "The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console."
受管理商品和不受管理商品:
1.受管理商品即不可重复购买的,例如:解锁关卡,激活游戏等(需要消耗,没有消耗就会出现卡单情况)。
2.不受管理商品即可重复购买的,例如:购买金币,购买药水,等消耗品。
3.订阅商品,由于项目中没有涉及到,如有需要的可以翻阅一下Google Billing文档。
(1)(2)初始化
mHelper = new IabHelper(this, key);
mHelper.enableDebugLogging(true);
(3)(4)(5)拉起支付弹窗
//SKU_GAS:商品id,需要与控制台设置的应用内商品id一致
//RC_REQUEST:返回值
//order:订单号
try {
mHelper.launchPurchaseFlow(this, SKU_GAS, RC_REQUEST,
mPurchaseFinishedListener, order);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error launching purchase flow. Another async operation in progress.");
}
(6)支付完成的回调, 如果是受管理的商品在此回调中直接可以将道具给用户
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() == -1003||result.getResponse() == 7) {//严正声明失败,
if (purchase.getSku().equals(SKU_GAS)) {
try
{
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
} catch (IabAsyncInProgressException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return;
}
if (purchase.getSku().equals(SKU_GAS)) {
try {
//消耗商品
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
//(7)通知本地服务器 游戏购买商品成功
String info = purchase.getOriginalJson();
googleVerify(info);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error consuming gas. Another async operation in progress.");
return;
}
}
}
};
// Called when consumption is complete 消耗完成的回调,商品被成功消耗进入此回调,此时将不受管理的商品给用户
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (mHelper == null)
return;
if (result.isSuccess()) {
// successfully consumed, so we apply the effects of the item in
// game world's logic, which in our case means filling the gas
// tank a bit
// saveData();
} else {
complain("Error while consuming: " + result);
}
// updateUi();
// setWaitScreen(false);
}
};
//RestoreOrder卡单和补单的时候用 当我们完成查询我们拥有的项目的订阅,订单有订单支付完成 但是道具没有给用户掉单(一般发生在支付后与本地服务器验证时网络波动或者(5)到(6)之间程序闪退,没有验证成功)
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null)
return;
// Is it a failure?
if (result.isFailure()) {
//卡单处理: 失败的订单 需要消耗掉 不然无法进行下次支付
String faString =PreSharedManager.getString("failPurchaseData", ZeroPayActivity.this);
String sign=PreSharedManager.getString("failSignature", context);
if (!TextUtils.isEmpty(faString) && !TextUtils.isEmpty(sign)) {
try {
Purchase p = new Purchase("ITEM_TYPE_INAPP",faString, sign);
mHelper.consumeAsync(p, mConsumeFinishedListener);
} catch (Exception e) {
e.printStackTrace();
}
} else {
//向本地服务器请求订单号
googleProcess();
}
return;
}
//查询是否有未未完成订单或者掉单发生 消耗产品 与 通知本地服务器用户已购买商品 出现掉单后,再次点击同个商品id的商品支付按钮,即可补单成功.
if (inventory.hasPurchase(SKU_GAS)) {
try {
//掉单处理
Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
String info = gasPurchase.getOriginalJson();
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
mConsumeFinishedListener);
googleVerify(info);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error consuming. Another async operation in progress.");
}
return;
}else {
//普通支付流程
googleProcess();
}
}
};
//获取失败的订单信息 打开IabHelper.java
int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException {
// Query purchases
logDebug("Querying owned items, item type: " + itemType);
logDebug("Package name: " + mContext.getPackageName());
boolean verificationFailed = false;
String continueToken = null;
do {
logDebug("Calling getPurchases with continuation token: " + continueToken);
Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(),
itemType, continueToken);
int response = getResponseCodeFromBundle(ownedItems);
logDebug("Owned items response: " + String.valueOf(response));
if (response != BILLING_RESPONSE_RESULT_OK) {
logDebug("getPurchases() failed: " + getResponseDesc(response));
return response;
}
if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST)
|| !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST)
|| !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) {
logError("Bundle returned from getPurchases() doesn't contain required fields.");
return IABHELPER_BAD_RESPONSE;
}
ArrayList ownedSkus = ownedItems.getStringArrayList(
RESPONSE_INAPP_ITEM_LIST);
ArrayList purchaseDataList = ownedItems.getStringArrayList(
RESPONSE_INAPP_PURCHASE_DATA_LIST);
ArrayList signatureList = ownedItems.getStringArrayList(
RESPONSE_INAPP_SIGNATURE_LIST);
for (int i = 0; i < purchaseDataList.size(); ++i) {
String purchaseData = purchaseDataList.get(i);
String signature = signatureList.get(i);
String sku = ownedSkus.get(i);
if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) {
logDebug("Sku is owned: " + sku);
Purchase purchase = new Purchase(itemType, purchaseData, signature);
if (TextUtils.isEmpty(purchase.getToken())) {
logWarn("BUG: empty/null token!");
logDebug("Purchase data: " + purchaseData);
}
// Record ownership and token
inv.addPurchase(purchase);
}
else {
//查询失败时 获取当前失败的订单信息
failPurchaseData = purchaseData;
failSignature = signature;
PreSharedManager.setString("failPurchaseData", purchaseData, mContext);
PreSharedManager.setString("failSignature", signature, mContext);
logWarn("Purchase signature verification **FAILED**. Not adding item.");
logDebug(" Purchase data: " + purchaseData);
logDebug(" Signature: " + signature);
verificationFailed = true;
}
}
之前是google那边流程没有走完出现的掉单,如果google已经支付.在第(6)步,上报我们服务器发货的流程出现问题也会出现掉单.
IabHelper.OnIabPurchaseFinishedListener是google支付完成的回调,在这里获取订单数据purchase.getOriginalJson()并保存.
如果发货成功就可以删除保存的订单数据,发货流程出现问题,可以再登录时调用googleVerify(info)再次上报直到所有订单都成功发货.