App支付场景
更新时间:2024.08.15# 1. 接口规则
为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考APIv3接口规则。
# 2. 开发准备
# 2.1. 搭建和配置开发环境
为了帮助开发者调用开放接口,我们提供了JAVA、PHP、GO三种语言版本的开发库,封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传 等基础功能(更多语言版本的开发库将在近期陆续提供)。
测试步骤:
1、根据自身开发语言,选择对应的开发库并构建项目,具体配置请参考下面链接的详细说明:
- wechatpay-java (opens new window)(推荐)、wechatpay-apache-httpclient (opens new window),适用于Java开发者。
- 注:当前开发指引接口JAVA示例代码采用wechatpay-apache-httpclient版本。
- wechatpay-php (opens new window)(推荐)、wechatpay-guzzle-middleware (opens new window),适用于PHP开发者。
- 注:当前开发指引接口PHP示例代码采用wechatpay-guzzle-middleware版本。
- wechatpay-go (opens new window),适用于Go开发者。
更多资源可前往微信支付开发者社区 (opens new window)搜索查看。
2、创建加载商户私钥、加载平台证书、初始化httpClient的通用方法。
3、基于接口的示例代码,替换请求参数后可发起测试。
说明:
- 上面的开发库为微信支付官方开发库,其它没有审核或者控制下的第三方工具和库,微信支付不保证它们的安全性和可靠性。通过包管理工具引入SDK后,可根据下面每个接口的示例代码替换相关参数后进行快速测试。
- 开发者如果想详细了解签名生成、签名验证、敏感信息加/解密、媒体文件上传等常用方法的具体代码实现,可阅读下面的详细说明:
- 如想更详细的了解我们的接口规则,可查看我们的接口规则指引文档。
# 2.2. 业务开发配置
合单支付目前支持在微信外H5、App、JSAPI、小程序、Native扫码5个场景使用,下面为你介绍App场景业务开发配置。
# 2.2.1. 注册App
App接入微信支付,需要先将商户App在微信开放平台进行注册,登记App开发参数以生成AppID。具体操作步骤如下:
1、登录微信开放平台,进入【管理中心 > 移动应用 > 创建移动应用】;
2、完成基本信息的录入,商户需要在本步骤提交App对应的下载地址,应用官网,应用水印,icon等业务信息;
3、完成平台信息的录入,商户需要在本步骤提交App在Android及iOS端对应的开发参数,包括Android端应用的包名,应用签名,iOS端应用的bundle ID, universal link等;
注意
Android应用包名和签名的相关说明,请参考Andriod开发要点说明。
4、以上信息全部提交完成后,即完成App的注册,商户可在【管理中心 > 移动应用】中,选择具体的应用查看其AppID及已获得的接口能力;
5、获取到App的AppID后,需要将该AppID与商户的收款mchid进行绑定,商户可登录商户平台后前往【产品中心 > AppID账号管理】界面中进行AppID的绑定及管理,界面如图所示:
# 2.2.2. iOS开发要点说明
1、iOS系统opensdk升级指引:
由于苹果公司在iOS13系统回收了查询 App bundleID 的能力,导致微信无法保证授权凭证能正确返回给AppID对应的应用。为此,微信支付强烈要求所有商户尽快升级到OpenSDK1.8.6,并让用户及时更新App,否则安全风险将一直存在。谢谢配合!
详细OpenSDK升级指引请参见:opensdk升级指引 (opens new window)。
注意
opensdk升级后请一定按照文档要求完成验证工作,确保opensddk升级成功。
2、开发配置:
以下项目开发环境以Xcode6.0,运行环境为IOS7.0为例,说明其开发中需要的操作。
a. 项目设置AppID
商户在微信开放平台申请开发App应用后,微信开放平台会生成App的唯一标识AppID。在Xcode中打开项目,设置项目属性中的URL Schemes为您的AppID。如图标红位置所示。
b. 注册AppID
商户App工程中引入微信lib库和头文件,调用API前,需要先向微信注册您的AppID,代码如下:
1[WXApi registerApp:@"wxd930ea5d5a258f4f" withDescription:@"demo 2.0"];
注意
OpenSDK前端拉起支付及SDK回调的相关说明,请参考App调起支付。
# 2.2.3. Android开发要点说明
1、后台设置
商户在微信开放平台申请开发应用后,微信开放平台会生成App的唯一标识AppID。由于需要保证支付安全,需要在开放平台绑定商户应用包名和应用签名,设置好后才能正常发起支付。设置界面在【开放平台】中的栏目【管理中心 > 修改应用 > 修改开发信息】里面,如图红框内所示。
应用包名:是在App项目配置文件AndroidManifest.xml中声明的package
值,例如图中的package="demo.wxpay.tenpay.com"
。
应用签名:根据项目的应用包名和编译使用的keystore,可由签名工具生成一个32位的md5串,在调试的手机上安装签名工具后,运行可生成应用签名串,如图8.9所示,绿色串即应用签名。下载地址: 签名工具下载地址 (opens new window)。
2、注册AppID
商户App工程中引入微信JAR包,调用API前,需要先向微信注册您的AppID,代码如下:
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null)
;
// 将该App注册到微信
msgApi.registerApp("wxd930ea5d5a258f4f")
;
# 3. 快速接入
# 3.1. 业务流程图
业务流程时序图如下。
重点步骤说明:
步骤1:用户在商户侧发起支付请求,商户先通过后台接口合单下单-App接口创建合单支付订单。
步骤2:商户再根据用户发起支付请求的具体场景通过App页面调起微信支付收银台,完成支付请求。
步骤3:用户支付成功后,商户可接收到支付结果回调通知。
步骤4:如果商户长时间未收到回调通知,可通过合单查询订单接口主动查询订单支付状态。
# 3.2. API接入(含示例代码)
文档展示了如何使用微信支付服务端SDK快速接入商家券产品,完成与微信支付对接的部分。
注意
- 文档中的代码示例是用来阐述API基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。
- 以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。
# 3.2.1. 【服务端】合单下单-App
步骤说明:用户在商户侧选择商品下单购买时,商户系统先调用该接口在微信支付服务后台生成预支付交易单,然后使用我们提供的客户端方法(下文介绍)调起微信支付收银台,即可完成支付。
示例代码:
重要入参说明:
- out_trade_no:商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
- description:商品描述。
- notify_url:支付回调通知URL,该地址必须为直接可访问的URL,不允许携带查询串。
- total:订单总金额,单位为分。
- OpenID:OpenID是微信用户在AppID下的唯一用户标识(AppID不同,则获取到的OpenID就不同),可用于永久标记一个用户。OpenID获取方式请参考以下文档小程序获取OpenID (opens new window)、公众号获取OpenID (opens new window)、App获取OpenID (opens new window)。
更多参数、响应详情及错误码请参见合单下单-App。
# 3.2.2.【客户端】App调起支付
步骤说明:通过App下单API成功获取预支付交易会话标识(prepay_id
) 后,需要通过OpenSDK来调起微信支付收银台。
注意
- 该步骤请使用开放平台的官方OpenSDK,可前往开放平台资源中心 (opens new window)下载。
- SDK的调用需要携带签名(参与签名的参数为:
appid
、partnerid
、prepayid
、package
、noncestr
、timestamp
,参数区分大小写)。
重要入参说明:
- package: 取固定值
Sign=WXPay
- signType: 该接口V3版本仅支持RSA
- paySign: 签名
paySign生成规则、响应详情及错误码请参见App调起支付 (opens new window)接口文档。
一、iOS SDK调用说明:
1、拉起支付
商户服务器生成支付订单,先调用合单App下单API生成预付单,获取到prepay_id后将参数再次签名传输给App发起支付。以下是调起微信支付的关键代码:
1PayReq *request = [[[PayReq alloc] init] autorelease];2request.partnerId = @"10000100";3request.prepayId= @"1101000000140415649af9fc314aa427";4request.package = @"Sign=WXPay";5request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";6request.timeStamp= @"1397527777";7request.sign= @"582282D72DD2B03AD892830965F428CB16E7A256";8[WXApi sendReq:request]
注意
该sign
生成字段名列表见调起支付API (opens new window)。
2、SDK结果回调
照微信SDK Sample,在类实现onResp函数,支付完成后,微信App会返回到商户App并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码,如果支付成功则去后台查询支付结果再展示用户实际支付结果。
注意
一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付结果通知或查询API返回的结果为准**。
代码示例如下:
1-(void)onResp:(BaseResp*)resp{2 if ([respisKindOfClass:[PayRespclass]]){3 PayResp*response=(PayResp*)resp;4 switch(response.errCode){5 caseWXSuccess: //服务器端查询支付结果通知或查询API返回的结果再提示成功6 NSlog(@"支付成功");7 break;8 default:9 NSlog(@"支付失败,retcode=%d",resp.errCode);10 break;11 }12 }13}
回调中errCode值列表:
名称 | 描述 | 解决方案 |
---|---|---|
0 | 成功 | 展示成功页面 |
-1 | 错误 | 可能的原因:签名错误、未注册AppID、项目设置AppID不正确、注册的AppID与设置的不匹配、其他异常等。 |
-2 | 用户取消 | 无需处理。发生场景:用户不支付了,点击取消,返回App。 |
二、Android SDK调用说明
1、SDK拉起支付
商户服务器生成支付订单,先调用【合单App下单API】生成预付单,获取到prepay_id后将参数再次签名传输给App发起支付。以下是调起微信支付的关键代码:
1IWXAPI api;2PayReq request = new PayReq();3request.appId = "wxd930ea5d5a258f4f";4request.partnerId = "1900000109";5request.prepayId= "1101000000140415649af9fc314aa427",;6request.packageValue = "Sign=WXPay";7request.nonceStr= "1101000000140429eb40476f8896f4c9";8request.timeStamp= "1398746574";9request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";10api.sendReq(request);
注意
该sign生成字段名列表见调起支付API (opens new window)。
2、支付结果回调
参照微信SDK Sample,在商户包名.wxapi包路径中实现WXPayEntryActivity类(包名或类名不一致会造成无法回调),在WXPayEntryActivity类中实现onResp函数,支付完成后,微信App会返回到商户App并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码,如果支付成功则去后台查询支付结果再展示用户实际支付结果。
注意
一定不能以客户端返回作为用户支付的结果,应以服务器端的接收的支付结果通知或查询API返回的结果为准。
代码示例如下:
1publicvoidonResp(BaseRespresp){2 if(resp.getType()==ConstantsAPI.COMMAND_PAY_BY_WX){3 Log.d(TAG,"onPayFinish,errCode="+resp.errCode);4 AlertDialog.Builderbuilder=newAlertDialog.Builder(this);5 builder.setTitle(R.string.app_tip);6 }7}
回调中errCode值列表:
名称 | 描述 | 解决方案 |
---|---|---|
0 | 成功 | 展示成功页面 |
-1 | 错误 | 可能的原因:签名错误、未注册AppID、项目设置AppID不正确、注册的AppID与设置的不匹配、其他异常等。 |
-2 | 用户取消 | 无需处理。发生场景:用户不支付了,点击取消,返回App。 |
# 3.2.3.【服务端】接收支付结果通知
步骤说明:当用户完成支付,微信会把相关支付结果将通过异步回调的方式通知商户,商户需要接收处理,并按文档规范返回应答。
- 支付结果通知的地址需要在请求App下单API时传入
notify_url
参数中。 - 支付结果通知是以POST 方法访问商户设置的通知URL,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情。
- 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头
Wechatpay-Signature
。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考 《微信支付API v3签名验证 (opens new window)》。 - 支付结果通知HTTP应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。
- 商户成功接收到回调通知后应返回成功的HTTP应答码为200或204。
- 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
- 后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止,但微信不保证通知最终一定能成功。
特别提醒:
- 商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄露导致出现“假通知”,造成资金损失。
- 当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
- 技术人员可登进微信商户后台 (opens new window)扫描加入接口报警群,获取接口告警信息。
更多参数、响应详情及错误码请参见支付结果通知API接口文档。
# 3.2.4. 【服务端】合单查询订单
步骤说明:当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付结果通知时商户可通过查询订单接口核实订单支付状态。
示例代码:
注意
查询订单可通过合单商户订单号查询。
更多参数、响应详情及错误码请参见查询订单API接口文档。
# 3.2.5. 【服务端】合单关闭订单
步骤说明:当商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
示例代码:
注意
- 订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。
- 已支付成功的订单不能关闭。
更多参数、响应详情及错误码请参见合单关单API接口文档。
# 3.2.6. 【服务端】申请交易账单
步骤说明:微信支付按天提供交易账单文件,商户可以通过该接口获取账单文件的下载地址。
示例代码:
更多参数、响应详情及错误码请参见申请交易账单API (opens new window)接口文档。
# 3.2.7. 【服务端】下载账单
步骤说明:通过申请交易账单接口获取到账单下载地址(download_url)后,再通过该接口获取到对应的账单文件,文件内包含交易相关的金额、时间、营销等信息,供商户核对订单、退款、银行到账等情况。
示例代码:
注意
- 账单文件的下载地址的有效时间为30s。
- 强烈建议商户将实际账单文件的哈希值和之前从接口获取到的哈希值进行比对,以确认数据的完整性。
更多参数、响应详情及错误码请参见下载账单API (opens new window)接口文档。
# 4. 常见问题
问: 获取OpenID接口报“此公众号并没有这些scope的权限,错误码10005”,如下图所示。
答: 请按以下步骤进行排查:
- 建议检查一下公众号的功能。比如是不是在订阅号/未认证的公众号里面尝试调用认证服务号的功能。
- 确认AppID是否认证过期或者AppID填写错误。
- 请尝试使用snsapi_userinfo的授权登录方式。
问:获取OpenID接口报“redirect_url域名与后台配置不一致,错误码:10003”。
答:请按以下步骤进行排查:
- 本错误是公众号获取OpenID接口报的错误,可参考文档检查是否符合开发规范:网页授权 (opens new window)
- 检查下单接口传的AppID与获取OpenID接口的AppID是否同一个(需一致)。
- 检查AppID对应的公众号后台 (opens new window),是否配置的授权域名和获取OpenID的域名一致。授权域名配置路径:【公众平台 (opens new window)-> 设置-> 公众号设置-> 功能设置–> 网页授权域名】。