附3. 技能内付费 - dueros/AndroidBotSdkDemo GitHub Wiki
1. 小度技能内付费介绍
DuerOS支持技能内的商品售卖,包括道具,关卡,会员等等。技能付费云端文档可以参考DuerOS开放平台-技能内付费。本文主要介绍在小度设备端,App如何上报付费请求,处理付款结果。
2. 选择购买指令
DuerOS目前支持两种购买指令:Buy指令(推荐)和Charge指令。开发者可以根据需要自行选择任一指令:
- Buy指令
- 开发者预先在DuerOS中注册商品
- 可以自定义购买流程中涉及商品展现的相关提示
- DuerOS负责根据商品信息完成下单,收款,并通知技能付款完成
- 开发者可以直接调用DuerOS提供的api,获得商品列表以及用户的购买状态,降低开发成本
- Charge指令
- 开发者自行管理商品
- 购买流程中涉及商品展现的相关提示都为标准化配置,技能不能自行配置
- DuerOS仅负责完成指令中指定金额的收款,并通知技能付款完成
- 技能负责下单以及维护用户购买状态
3. 使用Buy指令
版本依赖:BotSdk版本号>=1.35.0, 小度系统版本号大于Sp35.
开发者需要预先在DuerOS中注册商品。
3.1 支付流程如下图。
3.2 App代码示例
/**
* 调用{@link RequestBotSdkUtil#requestBuyProduct(String, String)}发起购买流程,上报购买事件
* @param sellerOrderId 买家id
* @param productId 商品id
*/
private void requestBuyProduct(@NonNull final String sellerOrderId, @NonNull final String productId) {
RequestBotSdkUtil.requestBuyProduct(sellerOrderId, productId);
}
调用上述代码逻辑,会拉起小度收银台。用户在小度收银台完成扫码支付。
3.3 处理Buy指令返回结果
支付结果封装在com.baidu.duer.botsdk.IAccountChargeMsgListener
这个接口中,在需要处理支付结果的地方,通过BotSdk.getInstance().setAccountAndChargeListener(this);
注册回调,通过onBuyStatusUpdated
方法处理支付结果。购买结果,需要App向自己的后端二次确认
/**
* Buy流程结果回调
* @param purchaseResult 支付结果"SUCCESS" 支付成功,"ERROR"支付失败
* @param productId 商品Id
* @param baiduOrderId 百度侧订单id
* @param sellerOrderId 买方订单id
* @param msg msg
*/
@Override
public void onBuyStatusUpdated(@NonNull String purchaseResult, @NonNull String productId, @NonNull String baiduOrderId,
@NonNull String sellerOrderId, @Nullable String msg) {
Log.i("OnBuyStatusUpdated", "purchaseResult:" + purchaseResult + "; productId:" + productId
+ "; baiduOrderId:" + baiduOrderId + "; sellerOrderId:" + sellerOrderId + "; msg:" + msg);
}
4. 使用Charge指令
4.1 支付流程图
4.2 App代码调用示例
使用Charge指令,需要自行构造金额信息和卖方订单信息,调用BotSdk.getInstance(context).requireCharge
方法完成支付流程。代码示例:
/**
* 产生一个固定的金额信息
* @return amountinfo
*/
public static AmountInfo mockAmountInfo() {
AmountInfo amountInfo = new AmountInfo();
amountInfo.amount = "0.01";
amountInfo.currencyCode = "CNY";
return amountInfo;
}
/**
* 构造卖家订单信息
* @return
*/
public static SellerOrderStructure mockSellerOlrderStructure() {
SellerOrderStructure sellerOrderStructure = new SellerOrderStructure();
sellerOrderStructure.productId = "111" + System.currentTimeMillis();
sellerOrderStructure.description = "测试商品介绍";
sellerOrderStructure.sellerOrderId = "222" + System.currentTimeMillis();
sellerOrderStructure.productName = "测试商品名称";
sellerOrderStructure.sellerNote = "测试商品备注";
return sellerOrderStructure;
}
/**
* 发起Charge支付请求
* @param amountInfo 金额信息
* @param sellerOrderStructure 买方订单信息
* @param sellerAuthorizationNote 备注信息
*/
public static void requireCharge(@NonNull final AmountInfo amountInfo, @NonNull final SellerOrderStructure sellerOrderStructure,
@Nullable String sellerAuthorizationNote) {
BotSdk.getInstance().requireCharge(amountInfo, sellerOrderStructure, "测试订单");
}
4.3 处理Charge支付返回结果
支付结果封装在com.baidu.duer.botsdk.IAccountChargeMsgListener
这个接口中,在需要处理支付结果的地方,通过BotSdk.getInstance().setAccountAndChargeListener(this);
注册回调,通过onChargeStatusUpdated
方法处理支付结果。支付结果,需要App向自己的后端二次确认
/**
* Charge指令回调结果
* @param purchaseResult 支付结果 SUCCESS支付成功; ERROR 支付失败
* @param amountInfo 应收金额
* @param capturedAmount 实收金额(扣除折扣,优惠券等之后的实际金额)
* @param creationTimestamp 订单创建时间
* @param baiduOrderId 百度侧订单id
* @param sellerOrderId 卖方订单id
* @param msg 订单备注
*/
@Override
public void onChargeStatusUpdated(String purchaseResult, AmountInfo amountInfo, AmountInfo capturedAmount, long creationTimestamp,
String baiduOrderId, String sellerOrderId, String msg) {
Log.i("onChargeStatusUpdated", "purchaseResult:" + purchaseResult + "; amountInfo:" + amountInfo + "; capturedAmount:"
+ capturedAmount + "; creationTimestamp:" + creationTimestamp + "; baiduOrderId:"
+ baiduOrderId + "; selllerOrderId:" + sellerOrderId + "; msg:" + msg)
}
5. 支付成功回调,处理HTTP API成功回调
请求URL
由第三方事先提供,使用HTTPS协议。 DuerOS开放平台->控制台->选择技能->配置服务->支付配置
请求方法
GET
参数
名称 | 格式 | 含义 | 例子 |
---|---|---|---|
sellerOrderId | string | 第三方请求下单时生成的第三方内部订单id | ab502301c2ka |
baiduOrderReferenceId | string | 百度内部的订单id,与sellerOrderId唯一关联 | 367446032047198208 |
sellerAmount | int | 第三方请求扣款的具体金额,币种人民币,单位分 | 1900 |
payAmount | int | 用户实际支付的具体金额(有可能使用了代金券,所以payAmount <= sellerAmount),币种人民币,单位分 | 1900 |
payTime | int | 用户付款完成时间,以秒为单位的、10位整数unix时间戳 | 1559318400 |
requestTime | int | 本次通知请求的生成时间,以秒为单位的、10位整数unix时间戳 | 1559318402 |
sign | string | 对上述参数的签名验证结果,采用SHA-256算法 | 7fb0955900263511d9a0941030629e44782601a3ca1ec2c22ba8cea7cfbd57dc |
返回结果
{
"status": 0,
"msg": "error message"
}
返回status为0,则通知第三方成功,百度侧不再继续通知;否则,百度侧会重试通知一定次数。
签名方法
- 除了sign外的所有参数按照参数名称字母顺序排序后,以 k1=v1&k2=v2&k3=v3… 的方式进行拼接,生成字符串s1;
- 在s1后附加百度事先分配的签名密钥字符串KEY,生成字符串s2;
- 计算sign值:signValue = sha256(s2);
- 在s1字符串后拼接sign:s1&sign=signValue;
- 附php签名代码demo
/*
* 生成支付通知的sign
* $param array 参数字段数组
* $payCallbackKey string 签名密钥字符串KEY
* @return string
*/
public function getSign($param, $payCallbackKey) {
ksort($param);
$s1 = http_build_query($param);
$s2 = $s1 . $payCallbackKey;
$sign = hash('sha256', $s2);
return $sign;
}
请求样例
GET https://xx.yy.zz/pay/notify?sellerOrderId=ab502301c2ka&baiduOrderReferenceId=367446032047198208&sellerAmount=1900&payAmount=1900&payTime=1559318400&requestTime=1559318402&sign=xxxx
注意事项
开发者的订单状态,应在HTTP API成功回调接口中更新,且只信任该回调。BotApkSdk.onChargeStatusUpdated的回调仅用在APK前端页面的刷新。