APP调起支付(Android)
SDK名称:QQ钱包SDK
SDK版本号:1.0.0
主要功能:适用于商户在移动端APP中集成QQ钱包支付功能。商户APP调用QQ钱包提供的SDK调用QQ钱包支付模块,商户APP会跳转到QQ钱包中完成支付,支付完后跳回到商户APP内,最后展示支付结果。
开发者:财付通支付科技有限公司
隐私政策:https://privacy.qq.com/document/preview/4796a8f96429482293dd15bc17b92c65
开发前准备:
商户需要具备以下条件才接入QQ钱包支付:
1、申请QQ钱包商户号:商户可以在QQ钱包商户平台自助申请:https://qpay.qq.com/;
2、提交APP信息审核:商户需登录QQ钱包商户平台,在“账户管理--开发配置--APP支付”一栏,提交APP支付信息审核。审核通过后,才能正常调用SDK拉起支付。
SDK说明
1、 SDK和开发文档
“QQWalletSDK-Android(点击下载)”中的“libs”目录存放“mqqopenpay.jar”jar文件。它作为QQ钱包支付提供的接入AndroidQQ钱包支付的SDK,需复制mqqopenpay.jar至商户应用工程libs下。
2、 示例工程
“QQWalletSDKDemo-Android(点击下载)”为一个调用QQ钱包支付的示例工程。
注意:示例工程为了演示方便,在终端进行数据签名的相关操作。为了保证数据据传输过程中的真实性和完整性,商户App不应在终端代码进行数据签名。建议在商户服务器下发tokenid时,同时按QQ钱包支付的要求下发数字签名相关数据。
3、 接口说明
(1)判断手机是否安装手Q
方法名:isMobileQQInstalled
请求参数:无
(2)判断手Q是否支持指定的Api
方法名:isMobileQQSupportApi
请求参数:
字段名 | 类型 | 说明 |
apiName | String | 所有的ApiName都申明在OpenConstants类中。如支付的ApiName为:OpenConstants.API_NAME_PAY |
(3)执行指定的Api
方法名:execApi
请求参数:
字段名 | 类型 | 说明 |
api | BaseApi | 如果要支付时,传入PayApi,它继承于BaseApi。 |
4、Api参数说明
PayApi存放调用QQ钱包支付的所需要的所有参数。下表中“参与签名”项目中被打“√”的参数需要进行数字签名。其参数列表:
字段名 | 类型 | 参与签名 | 说明 |
appId | String | √ | 应用唯一id,http://open.qq.com申请 |
nonce | String | √ | 随机串,随机字段串每次请求都要不一样 |
timeStamp | long |
| 时间戳,时间戳,为1970年1月1日00:00到请求发起时间的秒数 |
tokenId | String | √ | QQ钱包的预支付会话标识,具体值请传入调用统一下单接口后返回的“prepay_id”的值 注:参与签名参数key为“tokenId”,如“tokenId=8888888” |
pubAcc | String | √ | 手Q公众帐号,暂时未对外开放申请。 注:所有参与签名的参数,如果value为空, 生成格式如“pubAcc=” |
pubAccHint | String |
| 关注手Q公众帐号提示语 |
bargainorId | String | √ | QQ钱包支付商户号,具体值请传入调用统一下单接口时传入的“mch_id” 的值 注:参与签名参数key为“bargainorId” |
sigType | String |
| 加密方式,签名时,使用的加密算法。目前只支持"HMAC-SHA1",因此该参数填写"HMAC-SHA1"。 |
sig | String |
| 签名串,参看“数字签名” |
5、response参数说明
PayResponse存放QQ钱包支付结果的所有参数:
字段名 | 类型 | 说明 |
apiMark | int | 执行的Api标识 |
apiName | String | 执行的Api名称 |
retCode | int | 支付结果代码,0 : 表示成功。非0:表示失败 |
retMsg | String | 支付结果描述,仅支付成功有效 |
serialNumber | String | 支付序号,用于标识此次支付 |
openId | String | 腾讯开放平台openId,注,仅开通获得openId权限的App才返回 |
transactionId | String | 财付通交易号(订单号),仅支付成功有效 |
payTime | String | 支付时间,仅支付成功有效 |
callbackUrl | String | 商户提供的回调url地址(HTML5方式调用适用,其它情形为空),仅支付成功有效 |
totalFee | String | 订单总金额,以分为单位,仅支付成功有效 |
spData | String | 返回给商户的信息,商户前端可解析校验订单支付结果,仅支付成功有效,该值被URL encode |
其中 retCode错误信息描述表
返回码 | 说明 |
0 | 成功 |
-1 | 用户主动放弃支付 |
-2 | 登录态超时 |
-3 | 重复提交订单 |
-4 | 快速注册用户手机号不一致 |
-5 | 账户被冻结 |
-6 | 支付密码输入错误次数超过上限 |
-100 | 网络异常错误 |
-101 | 参数错误 |
其它非0值 | 未知错误 |
其中 sp_data为订单相关信息,URL decode之后示例为:
attach=100001000002&bank_type=0&bargainor_id=1618339989&charset=1&fee_type=1&pay_result=0&purchase_alias=242509874&sign=C932267553D4EE236E5C24640A0B03F6&sp_billno=0311207301109290002810000107631&time_end=20130917152936&total_fee=1&transaction_id=1900000109201309170000212327
sp_data中各字段含义见下表。
字段名 | 属性 | 说明 |
charset | 字符串 | 1 :UTF-8, 2 : GB2312 |
bank_type | 字符串 | 银行类型:财付通支付填0 |
pay_result | 字符串 | 支付结果: 0—成功;其它—失败 |
purchase_alias | 字符串 | 买家唯一标识,由财付通生成。注意不同于purchase_id财付通帐户。 |
bargainor_id | 字符串 | 卖方账号(商户spid),值等同于后台接口中的“mch_id” |
transaction_id | 字符串 | 财付通交易号(订单号) |
sp_billno | 字符串 | 商户系统内部的定单号,此参数仅在对账时提供,值等同于后台接口中的“out_trade_no” |
total_fee | 字符串 | 订单总金额,以分为单位 |
fee_type | 字符串 | 现金支付币种 |
attach | 字符串 | 商家数据包,原样返回 |
time_end | 字符串 | 支付完成时间,格式为yymmddhhmmss,如2009年12月27日9点10分10秒表示为20091227091010。时区为GMT+8 beijing。该时间取自财付通服务器 |
sign | 字符串 | MD5签名结果,详见“3.2商户后台签名规则” 仅此data数据包中字段参与签名 |
SDK使用方法
1、 准备工作
(1)将“mqqopenpay.jar”复制到商户App工程的libs目录下:
(2)通过OpenApiFactory工厂类获得开放Api实例:
IOpenApi openApi = OpenApiFactory.getInstance(this, APP_ID);
2、前提条件判断
调用isMobileQQSupportApi函数判断手Q是否支持QQ钱包支付:
boolean isSupport = openApi.isMobileQQSupportApi(OpenConstants.API_NAME_PAY);
3、启动QQ钱包支付
(1)初始化PayApi,并将数据填写完整:
PayApi api = new PayApi();
api.appId = APP_ID; // 在http://open.qq.com注册的AppId,参与支付签名,签名关键字key为appId
api.serialNumber = ...; // 支付序号,用于标识此次支付
api.callbackScheme = ...; // QQ钱包支付结果回调给urlscheme为callbackScheme的activity.,参看后续的“支付回调结果处理”
api.tokenId = ...; // QQ钱包支付生成的token_id
api.pubAcc = ...; // 手Q公众帐号id.参与支付签名,签名关键字key为pubAcc
api.pubAccHint = ...; // 支付完成页面,展示给用户的提示语:提醒关注公众帐号
api.nonce = ...; // 随机字段串,每次支付时都要不一样.参与支付签名,签名关键字key为nonce
api.timeStamp = ...; // 时间戳,为1970年1月1日00:00到请求发起时间的秒数
api.bargainorId = ...; // 商户号.参与支付签名,签名关键字key为bargainorId
api.sig = ...; // 商户Server下发的数字签名,生成的签名串,参看“数字签名”
api.sigType = "HMAC-SHA1"; // 签名时,使用的加密方式,默认为"HMAC-SHA1"
(2)在启动QQ钱包支付前,判断一下数据是否完整,再启动QQ钱包支付:
if (api.checkParams()) {
openApi.execApi(api);
}
4、 支付回调结果处理
(1)在AndroidManifest.xml配置接支付收回的Activity,其中android:scheme建议填写规则:qwallet + APP_ID。该值在”启动QQ钱包支付”时填写在api.callbackScheme中。
示例:
<activity
android:name="com.pay.sample.CallbackActivity"
android:launchMode="singleTop"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="qwallet100619284"/>
</intent-filter>
</activity>
(2)在Activity的onCreate和onNewIntent里调用OpenApi的handleIntent处理支付回调。
示例:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_callback);
openApi = OpenApiFactory.getInstance(this, appId);
openApi.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
openApi.handleIntent(intent, this);
}
(3)在Activity实现支付回调响应。
示例:
public class CallbackActivity extends Activity implements IOpenApiListener {
@Override
public void onOpenResponse(BaseResponse response) {
if (response == null) {
// 不能识别的intent
return;
} else {
if (response instanceof PayResponse) {
// 支付回调响应
PayResponse payResponse = (PayResponse) response;
message = " apiName:" + payResponse.apiName
+ " serialnumber:" + payResponse.serialNumber
+ " isSucess:" + payResponse.isSuccess()
+ " retCode:" + payResponse.retCode
+ " retMsg:" + payResponse.retMsg
+ " openId:" + payResponse.openId;
if (payResponse.isSuccess()) {
// 支付成功,这个支付结果不能作为发货的依据
}
} else {
// 不能识别的响应
}
}
}
数字签名
为了保障商户利益与安全,商户App调用QQ钱包支付时启用另一套签名机制。该签名机制与“商户后台与QQ钱包支付后台的签名机制”是不同的。
1、源串构造方法
(1)将需要参与签名的所有参数按key进行字典升序排列。
(2)将第1步中排序后的参数(key=value)用&拼接起来;
(3)key中存在大小写字母,保持大小写字母的存在。不要将key进行统一转换为大写或小写操作;
(4)如果value为空, 生成格式为“key=”,这点与后台之间签名方法是不一样的;
(5)签名原始串中,字段名和字段值都采用原始值,不进行URL Encode。
举例:
调用某个接口,接口有如下字段:
appId、nonce、tokenId、pubAcc、bargainorId
实际调用接口时,各字段的值:
appId=100619284、nonce=ksjfwierwfjk、tokenId=1000000002、pubAcc=、bargainorId=1618339989
正确的签名原始串是:
appId=100619284&bargainorId=1618339989&nonce=ksjfwierwfjk&pubAcc=&tokenId=1000000002
常见的错误有:
appId=100619284&bargainorId=1618339989&nonce=ksjfwierwfjk&tokenId=1000000002
appid=100619284&bargainorid=1618339989&nonce=ksjfwierwfjk&pubacc=&tokenid=1000000002
appId=100619284&nonce=ksjfwierwfjk&tokenId=1000000002&pubAcc=&bargainorId=1618339989
2、 密钥构造方法
(1)在http://open.qq.com申请appId,并获得appKey;
(2)构造到密钥的方式:在应用的appkey末尾加上一个字符的“&”,即appkey&。
示例:
appkey 值为 d139ae6fb0175e5659dce2a7c1fe84d5
正确的密钥为:d139ae6fb0175e5659dce2a7c1fe84d5&
3、 生成签名值方法
(1)使用HMAC-SHA1加密算法,使用”密钥构造方法“中得到的密钥对“源串构造方法”中得到的源串进行加密(注:一般程序语言中会内置HMAC-SHA1加密算法的函数,例如PHP5.1.2之后的版本可直接调用hash_hmac函数);
(2)然后将加密后的字符串进行Base64编码(注:一般程序语言中会内置Base64编码函数,例如PHP中可直接调用 base64_encode() 函数);
(3)最后得到的签名值sig结果如下:
c6xXw0tNABhOMc869h1bfxTp9Mk=
示例截图
FAQ
Q:接入QQ钱包支付,对手机QQ Android版本有什么要求?
A:手机QQ Android 5.3.0版本以上对第三方商户应用提供了支付接入的功能。因此,商户应用在调用QQ钱包支付前需要作一下判断,参看“前提条件判断”。
Q: 商户生成订单token_id是否可以在前端访问财付通下单接口生成?
A: 技术上是可以的,但为避免商户的签名Key泄露,建议商户通过后台服务器访问此接口,得到订单token_id后再传回商户的前台应用。
Q:用户在手机QQ侧支付完成后,商户应用怎样知道支付是否成功?
A:手机QQ侧支付成功后,其会发出特定协议格式的Intent,回调商户应用,返回支付成功信息;商户应用可依赖手机QQ前端回调进行支付结果的展示,可依赖财付通后台回调notify_url进行发货等逻辑处理。