(原文地址:http://blog.csdn.net/yupu56/article/details/49452107)
Google Play 内购 In-App-Billing在Android项目或者Cocos2dx/Unity项目中的集成.
最近在做一个游戏的海外版,需要加内购,碰到一些坑,这里记录下来,希望能对大家有个帮助。
参考教程:
Google Play In-app Billing官方教程 Google Play In-app Billing 踩过的那些坑 StackOverflow 论坛 Google Play 内购In-app-billing 总结~
开发者需要做的准备:
1.翻墙Android手机和电脑。
2.Google play 后台应用,并且把内购项目创建好并发布成功。能够得到内购产品的SKU即ProductID,和项目64位的秘钥。
3.内购产品的说明:
a.产品的id是唯一的字符串定义,比如com.engine.produce01,后台添加产品后需要激活。
b.In-app Billing 的 API 有个 v2 版本和 v3 版本,v2 版本已经不支持了,直接整 v3 版本的吧,Google Play 没有可重 复 购买商品这个概念,所有的“商品/充值档”用户成功购买过一次之后就不允许再次购买了。所以为了实现像应用内支付充 值这种可重复购买的“商品/充值档”,Google Play 提供了一个“消耗”借口(Consuming In-app Products) 。用户购买完 商品后,调一下“消耗”接口,这样用户下次就可以继续购买了。
使用IAB的流程:
1.首先确定你的SKU和Request值(随便填)
<pre name= "code" class = "java" > static final String SKU_PACKAGE1 = "android.test.purchased" ; static final String SKU_PACKAGE2 = "cinderella_product02" ; static final String SKU_PACKAGE3 = "cinderella_infinite" ;
static final int RC_REQUEST = 10001 ;
2.IabHelper类初始化方法,这里的base64EncodedPublicKey是googleplay后台的发布产品的时候生成提供的
mHelper= new IabHelper( this , base64EncodedPublicKey);
3.startSetup 的操作是检查是否有权限和连接到Google Billing service是否成功.
这里回调的操作是如果成功,调用queryInventoryAsync查看产品id是否可以使用,查询完成后会调用IabHelper.QueryInventoryFinishedListener 这个回调接口进行通知,在这个接口中可以获取商品的详细信息SkuDetails和Purchase信息。
mHelper.startSetup( new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { Log.d(TAG, "Setup finished." ); if (!result.isSuccess()) { complain("Problem setting up in-app billing: " + result); return ; } if (mHelper == null ) return ; Log.d(TAG, "Setup successful. Querying inventory." ); mHelper.queryInventoryAsync(mGotInventoryListener); } });
4.点击购买按钮调用方法,主要是mHelper.launchPurchaseFlow()方法
public void onBuyGasButtonClicked(View arg0) { Log.d(TAG, "Buy gas button clicked." ); setWaitScreen(true ); Log.d(TAG, "Launching purchase flow for gas." ); String payload = "" ; mHelper.launchPurchaseFlow(this , SKU_PACKAGE1, RC_REQUEST, mPurchaseFinishedListener, payload); }
5.verifyDeveloperPayload方法用来在服务器做验证的,起到确认订单的作用,小游戏就免了吧!
boolean verifyDeveloperPayload(Purchase p) { String payload = p.getDeveloperPayload(); return true ; }
6.下面是执行完购买后的监听方法
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_PACKAGE1)) { Log.d(TAG, "Purchase1 is gas. Starting gas consumption." ); mHelper.consumeAsync(purchase, mConsumeFinishedListener); } else if (purchase.getSku().equals(SKU_PACKAGE2)) { Log.d(TAG, "Purchase2 is premium upgrade. Congratulating user." ); mHelper.consumeAsync(purchase, mConsumeFinishedListener); } else if (purchase.getSku().equals(SKU_PACKAGE3)) { Log.d(TAG, "Purchase3 is premium upgrade. Congratulating user." ); } } };
7.执行完购买回调后,消耗型商品需要调用消耗方法
IabHelper.OnConsumeFinishedListener
mConsumeFinishedListener
=
new
IabHelper.OnConsumeFinishedListener()
这句的意思就是消耗掉你刚买的商品,消耗是指在googleplay上的消耗,为什么呢?因为GooglePlay 的In-app-Billing V3.0版本,已经没有管理,非管理的商品,或者像苹果iOS 那边消耗性和非消耗性的商品了,在后台新建商品的时候,你会发现全部是受管理的商品,所以在我们购买了消耗型的商品后,在代码中执行 mHelper .consumeAsync( purchase , mConsumeFinishedListener );就行了,代表这个商品被消耗了,你还可以购买。下面是 消耗后的回调方法:
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() { public void onConsumeFinished(Purchase purchase, IabResult result) { Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result); if (mHelper == null ) return ; if (result.isSuccess()) { Log.d(TAG, "Consumption successful. Provisioning." ); } else { complain("Error while consuming: " + result); } updateUi(); setWaitScreen(false ); Log.d(TAG, "End consumption flow." ); } };
8.最后补充一点,官方例子的方法设计非常合理,一些辅助方法的书写和使用,很经典,值得我们的借鉴。
public void updateUi() { } void setWaitScreen( boolean set) { findViewById(R.id.screen_main).setVisibility(set ? View.GONE : View.VISIBLE); findViewById(R.id.screen_wait).setVisibility(set ? View.VISIBLE : View.GONE); } void complain(String message) { Log.e(TAG, "**** TrivialDrive Error: " + message); alert("Error: " + message); } void alert(String message) { AlertDialog.Builder bld = new AlertDialog.Builder( this ); bld.setMessage(message); bld.setNeutralButton("OK" , null ); Log.d(TAG, "Showing alert dialog: " + message); bld.create().show();
}