前言
如果要接入google登錄,可以參考我的前一篇文章Google Play登錄SDK接入
官方文檔
google應(yīng)用內(nèi)支付V3接入Android官方文檔
官方Sample
google提供的官方sample是已經(jīng)對(duì)官方api經(jīng)過(guò)封裝了的,而google官方文檔是按照最原裝的代碼進(jìn)行
描述的,所以本文將按照sample方式接入
SDK接入
- google應(yīng)用內(nèi)支付不用添加jar包喇完,不用添加依賴,只需要一個(gè)aidl文件:IInAppBillingService.aidl 可以從sample中獲得财边,并且將其放在: com.android.vending.billing包下
- 將sample中的util中的所用類(lèi)拷貝到自己的項(xiàng)目的util下着撩,這些類(lèi)是已經(jīng)對(duì)官方的api進(jìn)行二次封裝了
配置資源文件
在AndroidManifest.xml文件中,添加以下權(quán)限:
<uses-permission android:name="com.android.vending.BILLING" />
SDK中的API調(diào)用
- 初始化
//設(shè)置自己從google控制臺(tái)得到的公鑰
mHelper = new IabHelper(activity, "YOUR_PUBLIC_KEY");
//調(diào)試模式
mHelper.enableDebugLogging(true);
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
@Override
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
Log.d(TAG, "Setup fail.");
return;
}
if (mHelper == null){
Log.d(TAG, "Setup fail.");
return;
}
Log.d(TAG, "Setup success.");
}
});
- 查詢庫(kù)存
/**
* 查詢庫(kù)存
* */
private void queryInventory(){
Log.e(TAG, "Query inventory start");
try {
mHelper.queryInventoryAsync(mGotInventoryListener);
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
/**查詢庫(kù)存的回調(diào)*/
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.e(TAG, "Query inventory finished.");
if (result.isFailure()) {
Log.e(TAG, "Failed to query inventory: " + result);
return;
}
Log.e(TAG, "Query inventory was successful." + inventory.getPurchase(mPayInfo.getProductId()));
if (inventory.hasPurchase(mPayInfo.getProductId())){
//庫(kù)存存在用戶購(gòu)買(mǎi)的產(chǎn)品沈条,先去消耗
}else{
//庫(kù)存不存在
}
}
};
-
購(gòu)買(mǎi)商品
google應(yīng)用內(nèi)支付調(diào)用購(gòu)買(mǎi)接口的時(shí)候需忿,應(yīng)先確保用戶沒(méi)有存在這個(gè)商品的購(gòu)買(mǎi)(買(mǎi)了但是沒(méi)有消耗)
//在合適的地方調(diào)用購(gòu)買(mǎi)
mHelper.launchPurchaseFlow(mActivity, sku, RC_REQUEST, mPurchaseFinishedListener, extra);
購(gòu)買(mǎi)的回調(diào)
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
@Override
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
if (result.isFailure()) {
// Oh noes! pay fail
Log.d(TAG,"Error purchasing: " + result);
return;
}
Log.d(TAG, "Purchase successful.");
//模擬檢測(cè)public key
checkPk(purchase);
}
};
購(gòu)買(mǎi)成功后,應(yīng)該將購(gòu)買(mǎi)返回的信息發(fā)送到自己的服務(wù)端,自己的服務(wù)端再去利用public key去驗(yàn)簽
-
消耗商品
用戶購(gòu)買(mǎi)成功后屋厘,如果是可重復(fù)購(gòu)買(mǎi)的商品涕烧,應(yīng)該立刻將這個(gè)商品消耗掉,以及在購(gòu)買(mǎi)之前應(yīng)確保用戶不存在這個(gè)商品汗洒,如果存在就調(diào)用消耗商品的接口去將商品消耗掉
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
消耗商品的回調(diào)
private IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
@Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
Log.d(TAG, "Consumption finished. Purchase: " + purchase + ", result: " + result);
if (result.isSuccess()) {
Log.d(TAG, "Consumption successful. Provisioning.");
}
else {
Log.d(TAG,"Error while consuming: " + result);
}
}
};
安全問(wèn)題
- 由于利用官方的sample實(shí)現(xiàn)方式是在app客戶端利用公鑰進(jìn)行驗(yàn)簽议纯, 也就是將支付的回調(diào)暴露在客戶端了,這種方式不可取溢谤,可以對(duì)sample里面進(jìn)行驗(yàn)簽的部分代碼進(jìn)行改造瞻凤,取消本地驗(yàn)簽,然后將支付成功回調(diào)的信息傳輸?shù)阶约悍?wù)器世杀,在服務(wù)器驗(yàn)簽再將結(jié)果返回給客戶端
常見(jiàn)問(wèn)題
- 確保包名和google控制臺(tái)配置一致
- 確保購(gòu)買(mǎi)時(shí)候傳輸?shù)膒roductId和在google控制臺(tái)配置一致
- 確保App的version和google控制臺(tái)的version一致
- 確保keystore和上傳到google控制臺(tái)的keystore一致