Google In-App Billing 实现(内含Unity 实现经验)
实现内购计费
傻逼目录
- Adding the AIDL file
- Updating Your Manifest
- Creating a ServiceConnection
- Making In-app Billing Requests
- Querying Items Available for Purchase
- Purchasing an Item
- Querying Purchased Items
- Consuming a Purchase
- Implementing Subscriptions
- Securing Your App
二逼参考
- In-app Billing Reference (V3)
根本无法执行的例子
- Sample Application (V3)
也看
- Selling In-app Products
Google Play 的 In-app Billing 提供了一种直(hui)观(se)简(nan)单(dong)的接口, 提供向GooglePlay发送内购请求和管理GooglePlay内购交易的功能。这都基于V3版本的API
测试你的程序的教程,参见 Selling In-app Products 训练课程. 教程提供了完整的内购示例。
包含方便的类库,用于从google play设置你的连接,发送账单,购买响应,以及管理后台线程让你可以在主线程调用内购。
在此之前,确保你阅读了 In-app Billing Overview 以了解内购的基本概念,让你更容易实现内购。
实现内购,你需要
- IInAppBillingService库文件植入你的项目
- AndroidManifest.xml 文件
- ServiceConnection 并绑定到
IInAppBillingService
. - 添加 AIDL 文件到你的工程
是一个
Android Interface Definition Language (AIDL) 文件他定义了V3版内购服务的接口,你可以使用这些接口,通过IPC方法的方式调用函式,创建账单请求
获取ADIL:
- Android SDK Manager.
- Extras 段
- 选择Google Play Billing Library.
- 点击Install packages 完成下载
sdk/extras/google/play_billing/
.
具体来说:
- 首先,下载 Google Play Billing Library到你的安卓工程
- Tools > Android > SDK Manager.(2.0版AS-File->Settings)
- SDK Tools 子页下载下一步,拷贝
文件到你的工
- 原文都是垃圾,直接创建src/com/android/vending/billing/
- 把文件考进去,拉倒。
- 原文说需要Gradle编译,没有也一样,直接打个APK试试,对应文件就会自己生成!
编译你的工程.编译出
IInAppBillingService.java
需要用gradle编译一下,但是已经编好的也可以直接拿过来用(别听他的!)。(重要的事情说3遍,Unity用户请不要用AS,用Eclipse)X3。
- SDK Tools 子页下载下一步,拷贝
更新你的 App的 Manifest
更新你的 App的 Manifest
不翻译了,废话那么多,直接加上这句拉倒
<uses-permissionandroid:name="com.android.vending.BILLING"/>
创建一个 ServiceConnection
创建一个 ServiceConnection
你的APP必须有一个 ServiceConnection
来协助你的APP和GooglePlay之间的消息传递,至少你应该:
IInAppBillingService
.- 向 IInAppBillingService 发送账单
为了和GooglePlay上的内购服务建立连接,你需要实现一个 ServiceConnection
并把你的Activity绑定到IInAppBillingService
.
重写onServiceDisconnected
和 onServiceConnected
方法,在建立连接后获得IInAppBillingService
实例的引用
IInAppBillingService mService;
ServiceConnection mServiceConn =newServiceConnection(){
@Override
publicvoid onServiceDisconnected(ComponentName name){
=null;
}
@Override
publicvoid onServiceConnected(ComponentName name,
IBinder service){
=IInAppBillingService.Stub.asInterface(service);
}
};
onCreate
方法中,调用 bindService
方法绑定. 把 Intent
传给方法,他代表内购服务。再传入一个你刚刚创建的 ServiceConnection
的实例,并且显式的设定你的Intent的包名为 使用如下所示的
setPackage()
方法时刻确保显示的设置intent的目标包名为@Override
publicvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
(R.layout.activity_main);
Intent serviceIntent =
newIntent("com.android.vending.billing.InAppBillingService.BIND");
.setPackage("com.android.vending");
(serviceIntent, mServiceConn,Context.BIND_AUTO_CREATE);
}
现在你可以使用mService的引用去和GooglePlay Service通信了。
重要: 当你的Activity嗝屁的时候记住对你的mService解绑。不然他会让你的(其实是用户的,不关你屁事)设备变慢。如何解绑看下面:
@Override
publicvoid onDestroy(){
super.onDestroy();
if(mService !=null){
(mServiceConn);
}
}
(没让你看JJ,看上面的代码块)
全套实现Selling In-app Products 训练课程,和附件例子。
创建In-app Billing请求
创建In-app Billing请求
一旦你的应用程序连接到 Google Play, 你就可以初始化内购商品了。 GooglePlay提供了校验接口,使用户可以进入他们的支付方法,所以你的应用程序不必自己处理支付事务。
当一个物品被购买,GooglePlay会识别这个用户对那个物品的所有权,并且防止他购买相同id的产品,直到这个物件被消费掉。
你可以在你的APP里面控制物品如何被消耗掉(通常买了就应该马上消耗掉,这样客户才能再买),并通知GooglePlay,那个商品可以被再次购买。
你也可以快速的向GooglePlay查询为用户建立的物品购买清单。这很有用,例如,当你的用户启动APP时,你可能需要为他恢复购买。
为购买查询可购买商品
为购买查询可购买商品
在你的APP里,你可以利用V3内购API向GooglePlay查询商品的细节。你需要把一个请求发给In-app Billing 服务。
首先创建一个Bundle
他包含一个记录商品ID的,键值为"ITEM_ID_LIST"的字符串 ArrayList列表
, 每一个ID都是一个可购买商品。
ArrayList<String> skuList =newArrayList<String>();
.add("premiumUpgrade");
.add("gas");
Bundle querySkus =newBundle();
.putStringArrayList(“ITEM_ID_LIST”, skuList);
getSkuDetails
方法,
getPackageName()
Bundle skuDetails = mService.getSkuDetails(3,
(),"inapp", querySkus);
如果请求成功,返回的bundle将会有返回值代码 BILLING_RESPONSE_RESULT_OK
(0).
方法. 调用这个方法会触发一个网络请求并阻塞主线程。
getSkuDetails
作为替代,创建一个单独线程,并在其中调用getSkuDetails
。(不会Java,你倒是说说怎么创建线程)
如果你想指定所有的可能的返回代码的意义,去看 In-app Billing Reference.(我不知道,也不想知道!)
查询结果被存在一个key为DETAILS_LIST的字符串ArrayList中。购买信息以字符串形式存于JSON格式中。
想要获取返回的产品细节信息,参照 In-app Billing Reference.
在这个例子中,你从前面代码块里创建的skuDetails 这个bundle里面,取得你的内购商品价格。
int response = skuDetails.getInt("RESPONSE_CODE");
if(response ==0){
ArrayList<String> responseList
= skuDetails.getStringArrayList("DETAILS_LIST");
for(String thisResponse : responseList){
JSONObjectobject=newJSONObject(thisResponse);
String sku =object.getString("productId");
String price =object.getString("price");
if(sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price;
elseif(sku.equals("gas")) mGasPrice = price;
}
}
PS:估计你得自己搞一张CSV表,或其他什么的,存放你的商品,然后对应返回信息,来更新UI,显示给玩家。客户端有而服务器不存在的商品,或被下架的商品,是不应该显示给玩家的。
购买一个商品
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
,"inapp","bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
会有返回值代码
BundleBILLING_RESPONSE_RESULT_OK
(0)
和一个 PendingIntent
(这又是啥逼玩意啊!)你可以用他们启动一个购买流程。
BUY_INTENT从返回的Bundle
提取 PendingIntent
.
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
想要完成购买事务,需要调用 startIntentSenderForResult
方法,并使用之前创建的 PendingIntent
。在这个栗子里面,你使用一个随意的值1001作为请求码。
startIntentSenderForResult(pendingIntent.getIntentSender(),
1001,newIntent(),Integer.valueOf(0),Integer.valueOf(0),
Integer.valueOf(0));
PendingIntent 到你的APP的 onActivityResult
方法中。 onActivityResult
方法会得到一个返回值为Activity.RESULT_OK
(1) 或Intent
中全部返回订单 的信息,访问 In-app Billing Reference.
INAPP_PURCHASE_DATA 键值,在返回 Intent中
,举个栗子:
'{
"opaque-token-up-to-1000-characters"
}'
此令牌是一个不可读的字符序列,最长1000个字符. 将这个令牌整个传入其他方法,比如当你想消耗购买时,正如 Consume a Purchase. 中提到的。不要省略或者改变令牌的大小写,你需要保存整个令牌。
Intent的签名。
@Override
protectedvoid onActivityResult(int requestCode,int resultCode,Intent data){
if(requestCode ==1001){
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 =newJSONObject(purchaseData);
String sku = jo.getString("productId");
("You have bought the "+ sku +". Excellent choice,
);
}
catch(JSONException e){
("Failed to parse purchase data.");
.printStackTrace();
}
}
}
}
developerPayload中,你可以随机的生成一个字符串令牌。
当你从GooglePlay获取购买响应,确保验证返回数据的前面,orderId和developerPayload
字符串。
附加的安全性:你应该在你自己的安全服务器上,检测这些东西。
确保你的orderId是一个你之前没用过的唯一值。并且developerPayload
字符串和你之前随购买请求发送的令牌相互匹配。
查询已购商品
getPurchases
方法。参数传入版号3,包名和“inapp”类别(订阅为“subs”)Bundle ownedItems = mService.getPurchases(3, getPackageName(),"inapp",null);
Bundle 返回代码0.
Bundle 同时也包含一个产品IDs列表,标记每一个产品的细节和签名。
getPurchase 调用顺序为基准。
Bundle 会返回INAPP_CONTINUATION_TOKEN
暗示还有更多的商品可以获得。你可以用这个token作为参数,进行后续的getPurchases
请求。
int response = ownedItems.getInt("RESPONSE_CODE");
if(response ==0){
ArrayList<String> ownedSkus =
.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
ArrayList<String> purchaseDataList =
.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
ArrayList<String> signatureList =
.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
String continuationToken =
.getString("INAPP_CONTINUATION_TOKEN");
for(int i =0; i < purchaseDataList.size();++i){
String purchaseData = purchaseDataList.get(i);
String signature = signatureList.get(i);
String sku = ownedSkus.get(i);
}
}
消耗一个购买
service 并且将标记将要被移除的购买的
purchaseToken
作为参数传入。
INAPP_PURCHASE_DATA 返回的字符串包含了这次要用的purchaseToken
,他在token变量里面,这就是为什么上面的说明要求你自己记录token。
int response = mService.consumePurchase(3, getPackageName(), token);
警告: 别在主线程调用这个方法,建立独立的子线程干这个事。否则他会阻塞你的主线程。
实现订阅
MY_SKU,"subs", developerPayload);
PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
if(bundle.getInt(RESPONSE_CODE)== BILLING_RESPONSE_RESULT_OK){ (pendingIntent, RC_BUY,newIntent(),
Integer.valueOf(0),Integer.valueOf(0),Integer.valueOf(0));
}
Bundle activeSubs = mService.getPurchases(3,"com.example.myapp",
"subs", continueToken);
保护你的APP
在 Developer Console,打开你的application's details,然后点击Your
License Key for This Application.
由狗狗Play生成的 Base64-encoded RSA 公钥使用二进制编码, X.509 subjectPublicKeyInfo DER SEQUENCE 格式. 他与狗狗Play的许可是同一级别的。
Google In-App Billing 实现(内含Unity 实现经验)的更多相关文章
- unity 3D + Google Play In-app Billing (IAB)(转) 热度 3
最近由于工作需要,研究unity如何接入Google Play以实现游戏内购买.目前IAB的实现,prime31做的插件比较好,各平台的IAB均有,但费用相对过高(几乎都是70刀左右,可怜穷小子).在 ...
- How to enable Google Play App Signing
how to enable google play app signing ------------------------------------------------------------- ...
- 第9期Unity User Group Beijing图文报道:《Unity实战经验分享》
时间来到了金秋九月,北京UUG活动也来到了第九期.本次活动的主题为<Unity实战经验分享>,为此我们邀请了3位资深的行业大神.这次我们仍然在北京市海淀区丹棱街5号微软大厦举行活动,在这里 ...
- Android Google Play app signing 最终完美解决方式
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/105561341 本文出自[赵彦军的博客] 在 GooglePlay 创建 App ...
- 背景虚化 Google Camera App Nokia Refocus HTC One M8 的 Duo景深相机
背景虚化是单反中一种比较常见的拍照形式,参看 http://www.techbang.com/posts/%2017842 https://refocus.nokia.com/
- google pay app权限使用说明
android.permission.CAMERA. 个人中心使用头像时需要使用该权限. android.permission.READ_PHONE.获取用户DeviceId,作为用户单点登录唯一值.
- [转]如何通过 App Store 审核(iOS 开发者经验分享)
CocoaChina交流社区曾经发起一个主题讨论,关于iOS开发者遇到审核失败的原因及解决办法的,有价值的回复内容如下: wubo9935 App中设计的图标与Apple原生图标类似,Apple原生图 ...
- 凤凰新闻APP的增长黑客流程步骤经验:3.5星|《我不是产品经理》
“ 我问了他三个问题.●你是AI科学家或者算法工程师吗?答:不是.●你想天天坐在电脑旁点鼠标或者打电话吗?答:不想.●你愿意每天盯着数据仪表盘定策略并与生产者做运营沟通吗?答:不愿意.我回答他:你别去 ...
- APP数据接口开发的一些经验
刚接到这样的任务时,没有感觉到任何压力,不就是给移动端应用提供数据吗?那边发来参数,这边处理数据,返回JSON.做网站开发时经常使用ajax请求后台数据,不就是这么回事吗.于是,在确认完需求后就开始干 ...
随机推荐
- Java深度复制List内容。
最近在工作的时候,有一个小需求,需要复制List的内容,然后会改变其中的数据,但是试了几种复制的方法,都是将原有的数据和复制后的数据都改变了,都没有达到我想要的效果. 其中涉及到了 "浅复制 ...
- IdentityServer4揭秘---Consent(同意页面)
授权同意页面与登录一样首先要分析页面的需要什么模型元素后建立相关的模型类 界面的话就 记住选择 .按钮.RuturnUrl.以及选择的资源Scope /// <summary> /// ...
- Hive(四)Hive的3种连接方式与DbVisualizer连接Hive
一.CLI连接 进入到 bin 目录下,直接输入命令: [root@node21 ~]# hive SLF4J: Class path contains multiple SLF4J bindings ...
- 【LOJ】#2443. 「NOI2011」智能车比赛
题解 显然是个\(n^2\)的dp 我们要找每个点不穿过非赛道区域能到达哪些区域的交点 可以通过控制两条向量负责最靠下的上边界,和最靠上的下边界,检查当前点在不在这两条向量之间即可,对于每个点可以\( ...
- 易普优APS混流排序算法助力汽车整车厂的均衡生产
一.汽车整车厂生产排序的难点 “ 冲压-焊接-涂装-总装”是汽车整车生产的四大工艺类型,它们存在上下游关联关系,每个车间都有自己的优化排序目标,汽车混流生产模式使得生产过程更加复杂,从而生产管控的难度 ...
- 常用的PHP排序算法以及应用场景
更多php排序算法应用常景:http://www.bf361.com/algorithm/algorithm-php 1.冒泡排序 冒泡排序:冒泡排序(Bubble Sort),是一种计算机科学领域 ...
- C++ 基础 杂类
1.set: 基本上跟map是相同(只有一个键),set是key-value 放在一起,map 是分开的,既然都加key ,所以set<> 的内容不可能有重复的情况出现 example: ...
- CSUOJ 1011 Counting Pixels
Description Did you know that if you draw a circle that fills the screen on your 1080p high definiti ...
- 三、redis系列之事务
1. 绪言 Redis也提供了事务机制,可以一次执行多个命令,本质是一组命令的集合.一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞.但Redis对事务的支持是部分支持 ...
- 浅谈Comparable与Comparator的区别
平时进行自定义排序一直使用实现Comparable接口,一段时间后操作的时候居然发现有了个Comparator接口 上网差了些资料,总结笔记一下. 基本原理就是比较,底层是二叉树 比如是3,6,5,1 ...