google应用内支付 in-app billing(二)

在写《google应用内支付 in-app billing(二)》的时候我并没有写这篇文章的前传《google应用内支付 in-app billing(一)》,留到后面再写吧.......下面进入正题。

一、in-app billing 的完整接入流程如下:

1、添加 in-app billing library;

2、完善AndroidManifest.xml,添加所需权限等;

3、创建ServiceConnection,并绑定到IInAppBillingService;

4、从我们的APP发送支付request请求到IInAppBillingService;

5、从google play 获得response


二、把AIDL文件导入到项目中,为项目和google play通信做准备

获得AIDL文件的方法:

1、打开android SDK manager

2、选中extras,并选中google play billing library

3、最后点击install package按钮

4、在自己项目的src下建立包名为com.android.vending.billing的包,并把刚才下载好的IInAppBillingService.aidl文件考入改包下(IInAppBillingService.aidl在sdk/extras/google/play_billing下)

5、build一下你的project,你会发现在/gen下有一个名为IInAppBillingService.java的文件,接下来你就可以在项目中调用它


三、完善AndroidManifest.xml文件

in-app billing是依赖于google play的,google play相当于一个我们项目与google play server的通信中介。而要使用google play就必须要声明如下权限:

<uses-permission android.name="com.android.vending.BILLING"/>


四、创建ServiceConnection,并绑定到IInAppBillingService

为了实现自己的app和google play进行通信,必须实现一个ServiceConnection。主要步骤如下:

1、把自己的项目bind到IInAppBillingService;

2、以IPC的方式发送支付request;

3、处理google play返回的response

(一)把自己的项目bind到IInAppBillingService

(1)创建ServiceConnection,并获得IInAppBillingService示例

在Activity中示例化一个ServerConnection,并实现它的两个方法onServiceConnected()和onServiceDisconnectrd(),并在onServiceConnection()方法里获得IInAppBillingService。

private IInAppServiceConnection mService;

private ServiceConnection mServiceConn = new ServiceConnection(){

@Override

public void onServiceConnected(ComponentName name, IBinder service){

//获得IInAppBillingService

mService = IInAppServiceConnection.Stub.asInterface(service);

}


@Override

public void onServiceDisconnected(ComponentName name){

mService = null;

}

}

(2)在Activity的onCreate()中bindService。根据官网的解释,在bind时候要在Intent中明确要启动google play Service(即setPackage("com.android.vending")),这样能够避免request被恶意截取。详情如下:

@Override

public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Intent serviceIntent = new Intent("com.android.vending.billing.IInAppBillingService.BIND");

serviceIntent.setPackage("com.android.vending");

bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);

}

接下来你就可以使用mService与google play Service进行通信了。

注意:在退出程序的时候一定要记得unbindService,要不然会使你的设备性能降低。

@Override

public void onDestroy(){

super.onDestroy();

if(mService != null){

unbindService(mServiceConn);

}

}


五、发送支付请求

在in-app billing中,我们的app不必直接去管理每一个订单,当某一个物品被用户所购买,google play会自动识别该物品被某一用户做拥有,并阻止他重复购买该物品,除非他已经消费完了。你能做的就是在你的app中控制每一个物品的消费方式,然后通知google play,告诉它该物品是否可以再次购买。你还可以再app里向google play查询该用户都购买了什么产品 。

(一)查询商品详情(注意:此为网络请求,因此不要放在主线程中

主要做法是创建一个Bundle对象,然后Bundle里携带一个装载有商品ids的ArrayList,最后调用mService.getSkuDetails()来查询商品详情。具体如下:

ArrayList<String> skuList = new ArrayList<String>();

skuList.add("premiumUpgrade");

skuList.add("gas");

Bundle querySkus = new Bundle();

querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

接着再调用:

Bundle skuDetails = mService.getSkuDetails(3, getPackageName(), "inapp", qureySkus);//第一个参数3是指API版本号,"inapp"是指支付方式。

(二)获取商品详情

如果请求成功,则返回的id是BILLING_RESPONSE_RESULT_OK(即0),返回的商品详情是以JSON的形式放在一个ArrayList中,改ArrayList的key是DETAIL_LIST。以下是解析的代码:

int response = skuDetails.getInt("RESPONSE_CODE");

if(response == 0){

ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");

for(String thisResponse : responseList){

JSONObject object = new JSONObject(thisResponse);

String sku = object.getString("productId");

String price = object.getString("price");

if(sku.equals("premiumUpgrade")){

mPemiumUpgradePrice = price;

}else if(sku.equals("gas")){

mGasPrice = price;

}

}

}

(三)购买商品

(1)发送购买请求

Bundle buyIntentBundle = mService.getBuyIntentBundle(3, getPackageName(), sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

参数解释:3为API版本号;sku为产品id;inapp是支付方式;最后一个参数是developerpayload(我理解的是这个参数也是随机凑合的一个参数,用于验证和对比以确认购买商品的请求是否是自己发送,因为后面购买成功后也会返回一个developerpayload,google官网是这样解释的The developerPayload String is used to specify any additional arguments that you want Google Play to send back along with the purchase information.)

(2)解析请求结果

购买请求发送后google play会返回一个Bundle结果(即上面的buyIntentBundle),如果请求成功则返回BILLING_RESPONSE_RESULT_OK(0),还有一个PendingIntent(key为BUY_INTENT),获取PendingIntent的方法如下:

PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");

startIntentSenderForResult(pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));

参数解释:1001是一个随机的request code;

接着实现Activity中的onActivityResult()方法来接收google play返回的结果:

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data){

if(requestCode == 1001){//上面的随机requestCode在此用到了

int responseCode = data.getIntExtra("RESPONSE_CODE", 0);

String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");

String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");

if(resultCode == RESULT_OK){

try{

JSONObject jo = new JSONObject(purchaseData);

String sku = jo.getString("productId");

}catch(JSONException e){

e.printStackTrace();

}

}

}

}

返回结果如下所示:

'{
   "orderId":"12999763169054705758.1371079406387615",
   "packageName":"com.example.app",
   "productId":"exampleSku",
   "purchaseTime":1345678900000,
   "purchaseState":0,
   "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
   "purchaseToken":"opaque-token-up-to-1000-characters"
 }'

注意:1、google play返回的purchaseToken会在其他方法中用到(比如消费产品的时候),所以要保存起来。

   2、google上有这么一段安全方面的提示,但我不是很了解,所以摘抄如下:

Security Recommendation: When you send a purchase request, create a String token that uniquely identifies this purchase request and include this token in the developerPayload.You can use a randomly generated string as the token. When you receive the purchase response from Google Play, make sure to check the returned data signature, the orderId, and the developerPayload String. For added security, you should perform the checking on your own secure server. Make sure to verify that the orderId is a unique value that you have not previously processed, and the developerPayload String matches the token that you sent previously with the purchase request.


六、查询已购产品

根据google官网的说法,正常情况下,每一次查询最多只能查询出700个已购产品,如果要查更多则需要另外做一些处理,此处不再给出......下面是查询例子:

Bundle ownedItems = mService.getPurchase(3, getPackageName, "inapp", null);

int response = ownedItems.getInt("RESPONSE_CODE");

if(response == 0){

ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");

ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");

ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");

ArrayList<String> continuationToken = ownedItems.getStringArrayList("INAPP_CONTINUATION_TOKEN");

for(int i=0; i<purchaseDataList.size; i++){

String sku = ownedSkus.get(i);

String purchaseData = purchaseDataList.get(i);

String signature = signatureList.get(i);

}

}


七、消费已购产品

int response = mService.consumePurchase(3, getPackageName(), token);

注意:1、该请求属于网络请求,不要放在主线程之中;

    2、在你进行消费之前,你必须执行消费请求,确保返回的是有效商品


八、订阅式购买

注意:订阅式购买与其它方式不同的是其购买方式是“subs”而不是“inapp”

(一)购买

Bundle bundle = mService.getBuyIntent(3, getPackageName(), sku, "subs", developerPayload);

PendingIntent pendingIntent = bundle.getParcelable("RESPONSE_BUY_INTENT");

if(bundle.getInt("RESPONSE_CODE") == BILLING_RESPONSE_RESULT_OK){

//该方法会唤醒google play的支付Dialog

startIntentSenderForResult(pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));

}

(二)查询已订阅

Bundle activeSubs = mService.getPurchase(3, getPackageName(), "subs", token);


(九)结束语

这是第一篇真正意义上的博文,内容都是翻译至Android开发文档的,为自己的小进步贺喜一下,也希望有不足的地方大家帮忙提出改进!谢谢!!




猜你喜欢

转载自blog.csdn.net/zhangdongren/article/details/45055461