Android 接入Google应用订阅与应用内支付结算笔记

公司项目是在谷歌应用商店上线发布的,最近产品经理说要给项目加个订阅的功能,按月订阅免广告的形式,对于我来说也是第一次接入谷歌应用商店的订阅,支付功能,是照着谷歌的官方文档集成边测试才做出的,下面分享下自己集成的过程和经验。
直接写关键代码在这里:

第一步:在 AndroidManifest.xml 文件中添加以下权限:

<!--谷歌商店应用内购买结算需要的权限-->
<uses-permission android:name="com.android.vending.BILLING" />

第二步:在项目src/main下New Directory命名为aidl,然后在这个目录下 New Package 命名为com.android.vending.billing,然后复制 IInAppBillingService.aidl 文件,到我们刚创建的 com.android.vending.billing 软件包中。
这里不得不吐槽下谷歌Play支付的官方中文文档是个渣 https://developer.android.com/google/play/billing/billing_integrate.html?hl=zh-cn,如果照着它的中文文档来做的话你会遇到这个问题:集成Google Play 支付,缺失 IInAppBillingService.aidl 或 Google Play Billing Library
SDK Manager中根本没有 Google Play Billing Library,正确解决这个棘手问题的方法:找到英文版说明 的示例项目:https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive

然后在分支:https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive/app/src/main/aidl/com/android/vending/billing 下

下载下来复制到我们创建的com.android.vending.billing 包中就行,最后rebuild下,就可以在下面图片中的目录下看到生成的java文件,就说明我们导入aidl文件成功了!
这里写图片描述
第三步:开始集成代码:

var mService: IInAppBillingService? = nullvar mServiceConn: ServiceConnection? = nullvar sub_monthly_price:String? = nullvar querySkus:Bundle? = null//与应用内购买结算服务建立连接mServiceConn = object : ServiceConnection {override fun onServiceDisconnected(name: ComponentName) {mService = null}override fun onServiceConnected(name: ComponentName,service: IBinder) {mService = IInAppBillingService.Stub.asInterface(service)if(mService!=null){initRn()}else{Log.e(TAG,"没走initRn()方法")}}}//onCreate 方法中,通过调用 bindService 方法执行绑定。 向方法传递引用应用内购买结算服务的 Intent 和您创建的一个 ServiceConnection 实例,// 并明确地将 Intent 的目标软件包名称设置为 com.android.vending — Google Play 应用的软件包名称。val serviceIntent = Intent("com.android.vending.billing.InAppBillingService.BIND")serviceIntent.`package` = "com.android.vending"bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE)

initRn方法

private fun initRn() {Log.e(TAG,"initRn==initRn")// 警告:请不要在主线程上调用 getSkuDetails 方法。 调用此方法会触发网络请求,进而阻塞主线程。 请创建单独的线程并从该线程内部调用 getSkuDetails 方法。Thread(Runnable {//在您的应用中,可以使用 In-app Billing Version 3 API 从 Google Play 查询商品详情。 要将请求传递至应用内购买结算服务,// 首先需要创建一个包含商品 ID 字符串 ArrayList 的 Bundle,该字符串带有键“ITEM_ID_LIST”,每个字符串是可购买商品的商品 ID。val skuList = ArrayList<String>()skuList.add("sub_monthly")querySkus = Bundle()querySkus!!.putStringArrayList("ITEM_ID_LIST", skuList)//要从 Google Play 检索此信息,请在 In-app Billing Version 3 API 上调用 getSkuDetails 方法,// 然后将 In-app Billing API 版本(“3”)、发起调用的应用的软件包名称、商品类型(“应用内”)以及您创建的 Bundle 传递给方法。var skuDetails = mService!!.getSkuDetails(3, packageName, "subs", querySkus)//查询结果将保存在带有键 DETAILS_LIST 的字符串 ArrayList 中。购买信息存储在 JSON 格式的字符串中//将从之前代码段返回的 skuDetails Bundle 中检索您的应用内商品的价格。val response = skuDetails.getInt("RESPONSE_CODE")Log.e(TAG,"response==$response")if (response == 0) {val responseList = skuDetails.getStringArrayList("DETAILS_LIST")Log.e(TAG,"responseList=="+responseList.toString())for (thisResponse in responseList) {val `object` = JSONObject(thisResponse)val sku = `object`.getString("productId")val price = `object`.getString("price")Log.e(TAG,"price=="+price)if (sku == "sub_monthly")sub_monthly_price = price
//                    else if (sku == "gas") mGasPrice = price//要从您的应用发起订阅请求,请在应用内购买结算服务上调用 getBuyIntent 方法。 将 In-app Billing API 版本(“3”)、发起调用的应用的软件包名称、要购买商品的商品 ID、// 商品类型(“应用内”或“订阅”)以及 developerPayload 字符串传递给方法。 developerPayload 字符串用于指定您想要 Google Play 随购买信息一同发送的任何其他参数。val buyIntentBundle = mService!!.getBuyIntent(3, packageName,sku, "subs", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ")//如果请求成功,返回的 Bundle 将包含响应代码 BILLING_RESPONSE_RESULT_OK (0) 和您可以用于开始购买流程的 PendingIntent。 要从 Google Play 查看所// 有可能的响应代码,请参阅应用内购买结算参考。 接下来,请使用键 BUY_INTENT 从响应 Bundle 中提取 PendingIntent。val pendingIntent = (buyIntentBundle.getParcelable("BUY_INTENT")) as PendingIntent//要完成购买交易,请调用 startIntentSenderForResult 方法并使用您创建的 PendingIntent。 这里用任意值 1001 用于请求代码。startIntentSenderForResult(pendingIntent.intentSender,1001, Intent(), Integer.valueOf(0)!!, Integer.valueOf(0)!!,Integer.valueOf(0)!!)}}else{Log.e(TAG,"response==========="+response)}}).start()}
 /*** Google Play 会将对您 PendingIntent 的响应发送至应用的 onActivityResult 方法。 onActivityResult 方法将获得结果代码 Activity.RESULT_OK (1) 或 Activity.RESULT_CANCELED (0)。要查看响应 Intent 中返回的订单类型信息,请参阅应用内购买结算参考。*订单的购买数据是 JSON 格式的字符串,将映射到响应 Intent 中的 INAPP_PURCHASE_DATA 键,例如:'{"orderId":"GPA.1234-5678-9012-34567","packageName":"com.example.app","productId":"exampleSku","purchaseTime":1345678900000,"purchaseState":0,"developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ","purchaseToken":"opaque-token-up-to-1000-characters"}'注:Google Play 会为购买生成令牌。此令牌是不透明的字符序列,最长可为 1,000 字符。 将整个令牌传递至其他方法(例如在您消耗购买时,如消耗购买中所述)。 不要省略或者截断此令牌,您必须保存并返回整个令牌。*/override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 1001) {val responseCode = data.getIntExtra("RESPONSE_CODE", 0)val purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA")val dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE")if (resultCode == RESULT_OK) {try {val jo = JSONObject(purchaseData)val sku = jo.getString("productId")Log.e(TAG,"You have bought the \" + sku + \". Excellent choice, adventurer!")alert("You have bought the " + sku + ". Excellent choice, adventurer!")}catch (e : JSONException) {Log.e(TAG,"Failed to parse purchase data")alert("Failed to parse purchase data.")e.printStackTrace()}}}else{faceBookLoginUtil!!.getCallbackManager().onActivityResult(requestCode, resultCode, data)}}//安全性建议:在您发送购买请求时,请创建一个可以对此购买请求进行唯一标识的字符串令牌并在 developerPayload 中包含此令牌。您可以将随机生成的字符串作为令牌。 从 Google Play 接收到购买响应时,请确保检查返回的数据签名、orderId 和 developerPayload 字符串。 为了增强安全性,您应在自己安全的服务器上执行检查。 请确保验证 orderId 为您之前未处理的唯一值,且 developerPayload 字符串与您之前通过购买请求发送的令牌相匹配。//重要说明:完成您的 Activity 后,请务必与应用内购买结算服务解除绑定。 如果不解除绑定,开启的服务连接会导致您的设备性能下降。// 此示例说明了如何通过重写 Activity 的 onDestroy 方法对到应用内购买结算的服务连接 mServiceConn 执行解除绑定操作。public override fun onDestroy() {super.onDestroy()if (mService != null) {unbindService(mServiceConn)}}

最后贡献一点我遇到的一点问题和解决的方案:
运行后出现异常提示:错误,此版本的应用程序未配置为通过Google Play结算。有关详情,请访问帮助中心
这里写图片描述
解决方案:我遇到的情况是在测试阶段,需要将我的谷歌测试账号添加到google play console 设置->账号详情->许可测试,然后运行就不出刚才那个提示了,可以订阅了就,运行起来是这个样子:
这里写图片描述

另外网上说的其他几方面原因我还没有遇到,但也是同类问题可以参考的解决方案,放到这里:

别的博友分享的解决方案,当你集成时出现这个问题用上面的方案也不行时,可以参考下面的:
造成这个错误的原因有两个,第一个是打包的时候,versionCode的值比提交到google play后台的版本要高。 第二个就是:打包的时候,和google play后台上的包的签名不一致。

还有一个异常:Google Play 遇到“无法购买您要买的商品?”问题,知乎上有一个贴对此总结的特别好,我这里贴下并附上原贴地址(https://www.zhihu.com/question/35295183)。
解决方案:
1 保证VersionCode, 上传的包和你测试的包一致。
2 保证Payment List, google后台的单据名和你游戏中配置的一致。
3 保证Payment Key, google后台Key和你的Key一致。
4 保证Test User, 你在测试阶段可以正常支付你的游戏。
5 保证GooglePlay商店, 这个一般来说只要弹出支付是没问题的, 但是如果商店无法使用,请检查Vpn。
6 保证Package Name, 包名一致。
7 上传到后台和测试的包签名要一致 (不一致传不上去)。
8 想要用其他谷歌账号测试游戏, 需要让应用主账号发送给其他账号测试邀请连接, 并让其他账号手动确认加入,才可以测试.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/64915.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Google play谷歌应用商店 APP上包上架的一些策略和技巧

1.服务端接口&#xff1a;服务器对应的IP、域名&#xff0c;只用在一个App内。尤其是做马甲包的&#xff0c;经常是一套服务器环境用遍所有包&#xff0c;基本就是团灭。所以合理的隔离服务端接口&#xff0c;一定会延长app的在线时间。 这里有小技巧&#xff1a;比如做一些便…

关于如何在Google Play Store 购买付费APP

今天要测试项目的应用内支付功能,发现不好测试,在大陆无法付费。 想办法搞一张美国的SIM卡 () 按这个 http://noirbright.com/?p=530 上面的教程,试了一下,模拟T_Mobile 运营商成功了! 电子市场里的应用可以正常下载。(有一个自己开发的APP,原来不能在国内下载的,…

集成Google应用内 支付 或者 订阅

要集成Google应用内支付 先要了解文档 集成文档: https://developer.android.google.cn/google/play/billing/integrate 1.创建Google应用 Google play 应用平台: https://play.google.com/console/u/0/developers/6529195851168790505/app-list 创建完应用后 进入应用详情 …

谷歌也搞收费?将在其Android App Store中开始

这是缓解谷歌在Android上的薪酬主导地位的重大举措。 Google 简化了 Play 商店中的第三方应用付款 谷歌周三表示&#xff0c;它将允许一些开发人员在其Android操作系统上运行的应用程序中提供第三方支付选项&#xff0c;这是这家搜索巨头多年来一直抵制的举动。 在给开发者的…

Qt窗口设置无边框不能移动,鼠标穿透后不能响应点击事件

思路实现 最近在做一个迷你小工具&#xff0c;准备干点不可描述的事情&#xff0c;想要短小强悍&#xff0c;始终在最顶层显示&#xff0c;同时不要自带的关闭按钮和边框&#xff0c;百度一下&#xff0c;发现是需要设置如下两个属性&#xff1a; setWindowFlags(Qt::WindowSt…

华为董事长:已攻克!

上一篇&#xff1a;阿里P8高级技术专家自述被裁员&#xff0c;疑似给市长写信&#xff0c;房贷月供3w&#xff0c;压力很大&#xff0c;出门面试找工作很难&#xff01; 近日&#xff0c;华为传出大消息&#xff0c; 已攻克部分自主替代关键环节&#xff01; 日前&#xff0c;华…

全网最详细中英文ChatGPT-GPT-4示例文档-智能多功能学习机从0到1快速入门——官网推荐的48种最佳应用场景(附python/node.js/curl命令源代码,小白也能学)

从0到1快速入门智能多功能学习机应用场景 Introduce 简介setting 设置Prompt 提示Sample response 回复样本API request 接口请求python接口请求示例node.js接口请求示例curl命令示例json格式示例 其它资料下载 ChatGPT是目前最先进的AI聊天机器人&#xff0c;它能够理解图片和…

小娜再见!微软8年语音助手被判死刑,Windows Copilot本月开始预览

丰色 发自 凹非寺量子位 | 公众号 QbitAI 在时代巨轮ChatGPT的碾压之下&#xff1a; 微软Windows系统已诞生八年的语音助手“小娜”要化作一缕尘埃了。 就在这两天&#xff0c;官方宣布&#xff1a; 到今年年底&#xff0c;Windows系统将不再支持Cortana程序&#xff08;即“小…

阿里系-淘宝接口抓取及相关问题

阿里系-淘宝接口抓取 一、安装charlse抓包工具 官方下载地址 安装证书 二、安装xposed hook框架 Xponsed简介 具体安装步骤 三、安装模块 关闭阿里系ssl验证 开启http模式 支持支付宝、淘宝、淘宝直播各个接口抓取 四、效果如下 接下去一段时间更新阿里系相关接口 文章目录 一、…

Bito(GPT-4) 的下载、安装与使用

Bito AI使用说明 Bito是由Chat-GPT团队专IDE开发的AI编码插件&#xff0c;通过将GTP-4和ChatGPT引入IDE或者CLI来帮助开发人员高效、高质量的进行编码工作&#xff0c;可以显著提高编码速度和代码质量。我们使用OpenAI的模型&#xff0c;且你不需要有OpenAI的密钥。 官网地址&a…

【代码+方案+思考】Discord 运营及个性化方案

文章目录 前言一、Discord Bot1. 获取 Token2. 连接API测试3. Bot自动回复4. Bot音频播放5. Bot回复Button6. Bot 接入ChatGPT7. Bot 显示个人简介8. Bot 发送附件/Coin限制/内容信息板10. 特别笔记1) 同时使用client.event和client.command 前言 要做好海外产品需要更好个性化…

烟雾弹?突然转变?如何看待微软发声:中国是主要的对手

是的&#xff0c;我又回来了&#xff0c;今天要跟各位唠的还是ChatGPT的嗑。今天的新闻是啥呢&#xff1f; 《微软总裁&#xff1a;中国将是 ChatGPT 的主要对手&#xff0c;我们的优势不大》 说实话&#xff0c;我看到这个新闻的时候&#xff0c;大感震撼&#xff0c;在相关报…

GitHub/GitLab同天宣布裁员,最高比例10%!GitHub所有办公室不再续租

明敏 发自 凹非寺量子位 | 公众号 QbitAI 一天之内&#xff0c;原本是老对手的GitHub、GitLab&#xff0c;双双宣布裁员计划。 比例分别是10%和7%。 预计将有300人离开GitHub&#xff0c;100人告别GitLab。 裁员原因十分一致&#xff1a;调整预算。 GitHub还宣布&#xff0c;所…

真实大揭秘:生成式AI到底对网络安全行业造成了哪些影响?

聚焦源代码安全&#xff0c;网罗国内外最新资讯&#xff01; 作者&#xff1a;ELIAS GROLL、CHRISTIAN VASQUEZ 和AJ VICENS 编译&#xff1a;代码卫士 在网络安全行业&#xff0c;放眼望去&#xff0c;无论是大会、交易博览会还是新闻头条&#xff0c;规模最大的企业都在声称&…

GTC23 | NVIDIA 与合作伙伴携手升级 Omniverse,为艺术家和开发者优化 3D 工作流奠定基础

Omniverse 平台进行重大更新&#xff0c;将新增生成式 AI、模拟和工业元宇宙访问入口。 基于 NVIDIA Omniverse&#xff08;创建和运行元宇宙应用的平台&#xff09;中全新的 Omniverse Connectors 及其他更新&#xff0c;开发者与创作者可以更好地挖掘生成式 AI、模拟和工业元…

垃圾分类数据集

训练集的制作是一件成本很高的事情&#xff0c;下面是一份包括4大类40个小类的垃圾数据集。

垃圾分类图片数据集

该图片数据集是作者自己收集整理的&#xff0c;一共有四个大文件夹&#xff0c;对应着不同的垃圾类别&#xff0c;每个文件夹中有各自包含的垃圾名称及其图片&#xff0c;当前数据集一共有246种垃圾&#xff0c;共包含图片80961张&#xff0c;大家如果有相关研究需要可以自行下…

【图像识别与处理】构建用于垃圾分类的图像分类器

1 构建图像分类器 训练一个卷积神经网络&#xff0c;用fastai库&#xff08;建在PyTorch上&#xff09;将图像分类为纸板&#xff0c;玻璃&#xff0c;金属&#xff0c;纸张&#xff0c;塑料或垃圾。使用了由Gary Thung和Mindy Yang手动收集的图像数据集。数据集下载地址如下&…

ART运行时垃圾收集机制简要介绍和学习计划

为了学习ART运行时的垃圾收集机制&#xff0c;我们先把Dalvik虚拟机的垃圾收集机制研究了一遍。这是因为两者都使用到了Mark-Sweep算法&#xff0c;因此它们在概念上有很多一致的地方。然而在实现上&#xff0c;Dalvik虚拟机的垃圾收集机制要简单一些。这样我们就可以先从简单的…

【电子学会】2019年03月图形化二级 -- 垃圾分类

垃圾分类 垃圾分类已经成为我们日常生活中很重要的一部分,这对于环境保护、资源回收利用具有重要意义。 下面我们做一个简单的垃圾分类互动游戏。 1. 准备工作 (1)导入背景库中的“Mural”,并编辑该背景,增加如下图中的两个垃圾桶,注明“可回收垃圾”和“不可回收垃圾…