SDK接入(2)之Android Google Play内支付(in-app Billing)接入

继上篇SDK接入(1)之Android Facebook SDK接入整理完Facebook接入流程之后,再来整理下Google Play in-app Billing支付的接入流程。众所周知,Google Play是Google Android官方的应用商店,也是将应用发布到世界各地一个重要的渠道。支付作为盈利的一个重要手段,可以借助Google in-app Billing api来达到目的。

Google Play in-app Billing的接入过程需要阅读接入文档。官方的接入文档地址为:

https://developer.android.com/google/play/billing/api.html

(1)Google Play开发者控制台

Google Play开发者控制台是管理应用,配置商品和发布的后台。参考地址为:

https://developer.android.com/distribute/googleplay/developer-console.html

Google Play的帮助文档地址为:

https://support.google.com/googleplay/android-developer/answer/6112435?hl=zh-Hans

使用步骤:

1. 注册Google Play开发者帐号

Google Play开发者帐号注册地址为:(需支付25美元的注册费,支持Visa信用卡等支付。)

https://play.google.com/apps/publish/signup

2. 配置应用商品,获取客户端接入参数,步骤简述如下:

在Google Play后台创建应用,设置游戏名称。按照要求填写商品详情。上传APK,注意上传的APK必须是release签名的正式包,同时要匹配好包名和版本号,然后再配置商品品项。获取Google Play的接入公钥(Base64编码的RSA公共密钥)。

受管理的商品:每个帐号只能购买一次,不能重复购买的商品。例如:激活码、解锁关卡等。

不受管理的商品:该商品可重复购买。包含支付完须消费,没消费的不可能重复购买,这步对消费者是透明的。例如:金币、钻石等。

订阅:通过按月或按年结算的方式在应用内向用户销售内容、服务或功能。

3. 获取服务端接入参数

支付完成之后,需要在服务端校验支付的票据是否合法。同样,也需要获取服务端参数。步骤如下:

(1)使用创建应用的开发者帐号,进入Google API管理后台。地址如下:

https://console.developers.google.com/apis/credentials

(2)确认是否启用了Google Play Android Developer API。若未启用,则点启用。

(3)配置OAuth,填写邮件地址和产品名称,并保存。

(4)创建客户端OAuth id。

(5)在新界面中,选择网页应用。并配置授权地址和重定向地址,并点击创建。

(6)获取客户端id和客户端密钥。

(7)回到在Google Play后台启用API。确保一个关联和一个启用状态。

(8)用客户端id获取code。

在浏览器中访问,如下地址(注意XXX替换实际的客户端id):

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=http://www.example.com/oauth2callback&client_id=XXX

会得到如下地址,至此便获取code的值:

https://www.example.com/oauth2callback?code=XXX

(9)再利用获取到的code,获取refresh_token参数。

用post请求如下地址,注意参数:code=XXX&client_id=XXX&client_secret=XXX&redirect_uri=http://www.example.com/oauth2callback&grant_type=authorization_code,其中grant_type为固定值。

https://accounts.google.com/o/oauth2/token

得到json:

   {
"access_token" : "ya29.dAFAF9xX89iR4s0Li4_faSmtGFonWQz67HvfXZFkPWsY_tHI_q1c7fc6WTS9EqKMi7_wonxhp4Q2FA",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "XXX"
}

这样便获得了refresh_token参数。

服务器校验的时候,便可以通过refresh_token,来获取access_token等。

(2)Google Play in-app Billing购买流程

这里我就直接从Google Play官方文档摘取过来购买流程的内容,方便查找。

Google Play官方购买流程文档:https://developer.android.com/google/play/billing/api.html?hl=zh-cn

1. 购买流程

先熟悉下V3版本的购买流程,知道大体的支付步骤和实现逻辑。如图:



(1) 您的应用向 Google Play 发送 isBillingSupported 请求,以确定您当前使用的应用内结算 API 目标版本是否受支持。

(2) 当您的应用启动或用户登录时,最好向 Google Play 进行查询,确定该用户拥有哪些商品。要查询用户的应用内购买,请发送 getPurchases 请求。如果该请求成功,Google Play 会返回一个 Bundle,其中包含所购商品的商品 ID 列表、各项购买详情的列表以及购买签名的列表。

(3) 通常情况下,您需要通知用户商品是否可供购买。要查询您在 Google Play 中定义的应用内商品的详细信息,应用可以发送 getSkuDetails 请求。您必须在该查询请求中指定商品 ID 列表。如果该请求成功,Google Play 会返回一个包含产品详情(包括商品的价格、标题、说明和购买类型)的 Bundle

(4) 如果该用户还未拥有应用内商品,您可以提示购买。为了发起购买请求,您的应用会发送 getBuyIntent 请求,指定要购买商品的商品 ID 以及其他参数。当您在开发者控制台中创建新的应用内商品时,应记录其商品 ID。

Google Play 返回的 Bundle 中包含 PendingIntent,您的应用可用它来启动购买结帐界面。

您的应用通过调用 startIntentSenderForResult 方法来启动 PendingIntent

当结帐流程结束后(即用户成功购买商品或取消购买),Google Play 会向您的 onActivityResult 方法发送响应 Intent。onActivityResult 的结果代码中有一个代码将用于表明用户是完成了购买还是取消了购买。响应 Intent 中会包含所购商品的相关信息,其中包括 Google Play 为了唯一识此次购买交易而生成的 purchaseToken 字符串。Intent 中还包含使用您的私人开发者密钥签署的购买签名。

2. 消耗流程

Google Play的支付分为购买-消耗两步。如果是在Google Play后台配置的商品品项是受管理类型的商品,则只需要调用购买即可,即不可重复购买。如果配置的是不受管理类型的商品,则在购买成功回调里要手动调用下消耗接口,否则该商品不能重复购买。

在第 3 版中,所有应用内商品都是托管的。也就是说,用户对所购应用内商品的所有权由 Google Play 进行维护,您的应用可以在需要时查询用户的购买信息。当用户成功购买应用内商品后,该次购买就会记录在 Google Play 中。应用内商品一经售出,就会被视为“被拥有”。处于“被拥有”状态的应用内商品无法再通过 Google Play 购买。您必须对“被拥有”的应用内商品发送消耗请求,然后 Google Play 才能再次将其设成可购买状态。消耗应用内商品会将商品切换回“未被拥有”状态并删除之前的购买数据。

为了检索用户所拥有商品的列表,您的应用会向 Google Play 发送 getPurchases 调用。您的应用可以通过发送 consumePurchase 调用提出消耗请求。在请求参数中,您必须指定应用内商品独一无二的 purchaseToken 字符串,此字符串是在商品售出时由 Google Play 指定的。Google Play 会返回一个状态代码,指明此次消耗是否已成功记录。

(1)调用 getBuyIntent 启动购买流程。

(2)从 Google Play 接收指示购买是否成功完成的响应 Bundle

(3)如果购买成功,通过调用 consumePurchase 消耗此次购买。

(4)从 Google Play 接收指示消耗是否成功完成的响应代码。

(5)如果消耗成功,在应用中配置商品。

以上是购买到消耗的整个流程,这么复杂的购买流程到代码层该如何实现了。还好我们可以通过取巧的办法,用Google Play给我们提供的Samples中代码“拿来即用”,节省开发周期。

(3)Google Play in-app Billing api接入

1. 下载Google Play Billing Library

打开ANdroid SDK Manager。在extras中勾选Google Play Billing Library和Google Play Service。如图:

下载完的Library路径应该会在<android-sdk-root>/extras/google/play_billing。目录结构如图:



并导入samples到Eclipse中。用AndroidStudio也类似,这里主要介绍下Eclipse的操作步骤。

2. 将samples对应的代码直接拷贝到自己的项目中。如图:

3. 在AndroidManifest中添加如下权限:
   <uses-permission android:name="com.android.vending.BILLING" />
4. 初始化in-app Billing api。直接把以下代码放到合适的地方,一般是主Activity的onCreate中。IabHelper是一个封装了购买-消耗的个工具类,queryInventoryAsync是订单查询方法。注意替换实际的公钥(Google Play后台创建应用里,在服务和API这项可以找到,一串Base64编码的字符串)。
    // base64EncodedPublicKey为Base64编码RSA公共密钥
String base64EncodedPublicKey = "CONSTRUCT_YOUR_KEY_AND_PLACE_IT_HERE";
// Create the helper, passing it our context and the public key to verify signatures with
Log.d(TAG, "Creating IAB helper.");
mHelper = new IabHelper(this, base64EncodedPublicKey); // enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(true); // Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished."); if (!result.isSuccess()) {
// Oh noes, there was a problem.
return;
} // Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return; // IAB is fully set up. Now, let's get an inventory of stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
5. 支付。在发起购买请求的时候,调用以下代码。sku参数为对应Google Play后台配置的商品品项id。extraData可用于透传参数
   IabHelper.launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener, String extraData)
6. 消耗。一般是在支付成功或查询成功的回调里调用消费方法。

注意:不受管理的商品,在支付完需要调用消费。不然,没法重复购买。测试帐号返回的票据中不带orderId。

   IabHelper.consumeAsync(Purchase purchase, OnConsumeFinishedListener listener)
7. 查询。在查询回调里,检测如果存在支付但没消费的商品,继续调用消费。可用于漏单处理。直接放在IapHelper初始化中即可。
   IabHelper.queryInventoryAsync(QueryInventoryFinishedListener listener)
8. 销毁。一般是在主Activity的onDestory里执行。
    public void onDestroy() {
super.onDestroy(); // very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) mHelper.dispose();
mHelper = null;
}

(4)测试Google Play in-app Billing api的接入

1. 测试机上安装Google框架

国内的手机一般需要手动安装Google框架(Google Play商店,Google Play Service等),这里推荐个“谷歌安装器”的app。安装这个app可以自动检测手机内缺少哪些Google服务。不过,安装“谷歌安装器”部分手机需要Root权限。

下载谷歌安装器。当然,安装完Google框架还需要VPN,能FQ,正常打开Google Play商店。

2. 安装接入好Google Play in-app Billing的app到手机

前面提到,测试Google Play in-app Billing的接入,须包名,版本好跟上传的一致,而且签名必须是release签名的。这样我们可以将release签名文件修改为默认的签名,方便我们调试。直接连手机运行,省去了每次打包再安装到手机

(1)先备份正式的签名文件。然后,在Windows命令行窗口中修改keystore密码为android。

keytool -storepasswd -keystore test.keystore

先输入原签名文件的密码,再输入新密码为android。

(2)修改原签名文件的alias,修改为androiddebugkey。

keytool -changealias -keystore test.keystore -alias test -destalias androiddebugkey

test为原签名文件的alias,修改为androiddebugkey

这步会要求输入keystore的密码(即:android)和当前alias的密码

(3)修改alias密码

keytool -keypasswd -keystore my.keystore -alias androiddebugkey

这步会要求输入keystore密码(即:android)和原alias密码,然后在输入新的alias密码,输入android即可。

(4)Eclipse中指定默认的签名

选择Window->Preferences->Android->Build->Browse,选择刚制作的签名文件即可。这样,就可以直接连手机调试运行了。

3. 添加测试帐号

在Google Play后台上传Alpha版测试或Beta测试版里添加测试人员帐号。

(1)创建Google+群

邀请测试人员加入Google+群组的方式,邀请会收到邮件,不过邀请大概会有4小时延迟。

(2)分享测试连接

将形如以下连接分享给测试者,测试者打开连接加入测试。“org.cocos2d.game”为应用对应的包名。

https://play.google.com/apps/testing/org.cocos2d.game

(5)接入常见问题

1. 无法购买您要买的商品。

当前Google Play帐号不是测试帐号

2. 需要验证身份。您需要登录自己的Google帐号。

本地测试的版本号和google上传的版本号要一致

3. Cannot load library: soinfo_relocate(linker.cpp:993): cannot locate symbol "signal"

05-05 19:08:32.148: E/AndroidRuntime(7822): FATAL EXCEPTION: main

05-05 19:08:32.148: E/AndroidRuntime(7822): java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_relocate(linker.cpp:993): cannot locate symbol "signal" referenced by "libcocos2dlua.so"...

05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.Runtime.loadLibrary(Runtime.java:372)

05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.System.loadLibrary(System.java:514)

05-05 19:08:32.148: E/AndroidRuntime(7822): at org.cocos2dx.lib.Cocos2dxActivity.onLoadNativeLibraries(Cocos2dxActivity.java:113)

05-05 19:08:32.148: E/AndroidRuntime(7822): at org.cocos2dx.lib.Cocos2dxActivity.onCreate(Cocos2dxActivity.java:128)

05-05 19:08:32.148: E/AndroidRuntime(7822): at org.cocos2dx.lua.AppActivity.onCreate(AppActivity.java:90)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.Activity.performCreate(Activity.java:5226)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1151)

05-05 19:08:32.148: E/AndroidRuntime(7822): at com.lbe.security.service.core.client.b.x.callActivityOnCreate(Unknown Source)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2360)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2448)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.access$600(ActivityThread.java:173)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1392)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.os.Handler.dispatchMessage(Handler.java:107)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.os.Looper.loop(Looper.java:194)

05-05 19:08:32.148: E/AndroidRuntime(7822): at android.app.ActivityThread.main(ActivityThread.java:5469)

05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.reflect.Method.invokeNative(Native Method)

05-05 19:08:32.148: E/AndroidRuntime(7822): at java.lang.reflect.Method.invoke(Method.java:525)

05-05 19:08:32.148: E/AndroidRuntime(7822): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:857)

05-05 19:08:32.148: E/AndroidRuntime(7822): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)

05-05 19:08:32.148: E/AndroidRuntime(7822): at dalvik.system.NativeStart.main(Native Method)

Application.mk添加:APP_PLATFORM := android-17

4. 此版本的应用为配置为通过Google Play结算。有关详情,请访问帮助中心。

检查下打包所用的签名与上传Google Play后台的签名是否一直。

5. In-app billing error: Purchase signature verification FAILED

代码中base64EncodedPublicKey参数不正确,跟Google后台的不一致。

6. IabResult: Error checking for billing v3 support. (response: 3:Billing Unavailable)

在手机的设置里需创建并登录Google账号。

技术交流QQ群:528655025

作者:AlphaGL

出处:http://www.cnblogs.com/alphagl/

版权所有,欢迎保留原文链接进行转载

SDK接入(2)之Android Google Play内支付(in-app Billing)接入的更多相关文章

  1. Google play billing(Google play 内支付) 上篇

    写在前面: 最近Google貌似又被全面封杀了,幸好在此之前,把Google play billing弄完了,现在写篇 博客来做下记录.这篇博客一是自己做个记录,二是帮助其他有需要的人.因为现在基本登 ...

  2. Google play billing(Google play 内支付) 下篇

    开篇: 如billing开发文档所说,要在你的应用中实现In-app Billing只需要完成以下几步就可以了. 第一,把你上篇下载的AIDL文件添加到你的工程里,第二,把 <uses-perm ...

  3. Google play billing(Google play 内支付)

    准备工作 1. 通过Android SDK Manager下载extras中的Google Play services和Google Play Billing Library两个包. 2. 把下载的. ...

  4. Android Google AdMob 广告接入示例

    Android Google AdMob 广告接入示例 [TOC] 首先请大家放心,虽然 Google搜索等服务被qiang了,但是 广告服务国内还是可以用的,真是普天同庆啊~~~噗! 其实这篇文章也 ...

  5. SDK接入(3)之iOS内支付(In-App Purchase)接入

    SDK接入(3)之iOS内支付(In-App Purchase)接入 继整理了Android平台的SDK接入过程.再来分享下iOS平台的内支付(In-App Purchase)接入,作为笔者在游戏开发 ...

  6. SDK接入(1)之Android Facebook SDK接入

    SDK接入(1)之Android Facebook SDK接入 由于游戏已上线,且处于维护阶段,所以有空写写各种SDK接入过程和遇到的问题,也当作一种工作总结.SDK接入主流分为这么几类,登录.支付. ...

  7. Google Play内购测试

    Google Play内购测试 最近项目做海外版本,接入Google wallet支付后,测试验证比较繁琐,故记录一下. Google wallet支付方式接入完成后,需要按照如下步骤设置,才可以进行 ...

  8. 在Eclipse+ADT中开发Android系统的内置应用

    转自:  http://www.iteye.com/topic/1050439 在Eclipse+ADT中开发Android系统的内置应用 Android系统内置有:Browser(浏览器).Mms( ...

  9. 【FAQ】接入华为应用内支付服务常见问题解答

    HMS Core应用内支付服务(In-App Purchases,IAP)为应用提供便捷的应用内支付体验和简便的接入流程.开发者的应用集成IAP SDK后,调用IAP SDK接口,启动IAP收银台,即 ...

随机推荐

  1. JS高级前端开发群加群说明及如何晋级

    JS高级前端开发群加群说明 一.文章背景: 二. 高级群: 三. 加入方式: 四. 说明:   一.文章背景: 去年年初建了几个群,在不经意间火了,一直排在“前端开发”关键字搜索结果第一名.当然取得这 ...

  2. [转载]Java 8 日期&时间 API

    Java 8 日期和时间 声明 本文转自http://www.journaldev.com/2800/java-8-date-localdate-localdatetime-instant,以mark ...

  3. 《深入理解Java虚拟机》调优案例分析与实战

    上节学习回顾 在上一节当中,主要学习了Sun JDK的一些命令行和可视化性能监控工具的具体使用,但性能分析的重点还是在解决问题的思路上面,没有好的思路,再好的工具也无补于事. 本节学习重点 在书本上本 ...

  4. 详解前端模块化工具-webpack

    webpack是一个module bundler,抛开博大精深的汉字问题,我们暂且管他叫'模块管理工具'.随着js能做的事情越来越多,浏览器.服务器,js似乎无处不在,这时,使日渐增多的js代码变得合 ...

  5. mysql sleep进程过多,应用级配置

    <property name="hibernateProperties"> <props> <prop key="hibernate.dia ...

  6. MySQL基础知识

    一.MySQL安装 MySQL的下载 http://dev.mysql.com/downloads/mysql/ MySQL版本选择 MySQL功能自定义选择安装 1.功能自定义选择 2.路径自定义选 ...

  7. Atitit. 提升存储过程与编程语言的可读性解决方案v3 qc25.docx

    Atitit. 提升存储过程与编程语言的可读性解决方案v3 qc25.docx 1. 大原则:分解+命名1 1.1. 命名规范1 1.2. 分层.DI和AOP是继OO1 1.3. 运算符可读性一般要比 ...

  8. JavaScript权威设计--跨域,XMLHttpRequest(简要学习笔记十九)

    1.跨域指的是什么? URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a. ...

  9. 聊聊ASP.NET Core默认提供的这个跨平台的服务器——KestrelServer

    跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server.KestrelServer利用一个名为KestrelEngine的网络 ...

  10. 检索COM类工厂中CLSID为{00024500-0000-0000-C000-000000000046}的组件时失败

    具体解决方法如下: 1:在服务器上安装office的Excel软件: 2:在"开始"->"运行"中输入dcomcnfg.exe启动"组件服务&q ...