copy源码:XHPayKit
2个支付方式都通过UIApplication.shared.open(url, completionHandler: nil)
方式调起支付宝
、微信
客户端支付,不需要集成'SDK'。
在Info.plist
添加白名单
<key>LSApplicationQueriesSchemes</key>
<array>
<string>alipay</string>
<string>weixin</string>
</array>
添加URL Types

组装url
的格式:
- 微信
- 让后台将
payInfo
的key
、value
拼接成String
weixin://app/微信的AppID/pay/?key=value&key=value
格式如下面的wxUrl
字段
{
"errno": "0",
"errmsg": "请求成功!",
"wxUrl": "weixin://app/微信的AppID/pay/?nonceStr=ZLOOW0wSxjYZt6AP&package=Sign=WXPay&partnerId=1603068427&prepayId=wx22214520388210c0a8bc66702ed24d0000&timeStamp=1603374320&sign=DBF8AC4C59AAA0B65757421A37EEBBB9",
"payInfo": {
"appid": "微信的AppID",
"noncestr": "ZLOOW0wSxjYZt6AP",
"package": "Sign=WXPay",
"partnerid": "1603068427",
"prepayid": "wx22214520388210c0a8bc66702ed24d0000",
"sign": "DBF8AC4C59AAA0B65757421A37EEBBB9",
"timestamp": 1603374320
}
}
-
替换
Sign=WX
let urlStr = result["wxUrl"].replacingOccurrences(of: "Sign=WX", with: "Sign%3DWX")
-
直接打开链接,进入微信支付页面
if let url = URL(string: urlStr) {
UIApplication.shared.open(url, completionHandler: nil)
}
- 支付回调,
AppDelegate
/// MARK: - open url iOS9.0及以后推荐使用
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let handleUrlStr = url.absoluteString
DebugLog("=========open url Links=========")
//wx123://pay/?returnKey=&ret=-2
DebugLog(url.scheme ?? "🈳", handleUrlStr)
//微信的
if handleUrlStr.contains(微信的AppID) {
var errCode = 0
var errStr = ""
//拿到ret returnKey=&ret=-2
if let rstStr = handleUrlStr.components(separatedBy: "?").last {
let rets = rstStr.components(separatedBy: "&")
for keyV in rets {
if keyV.contains("ret=") {
errCode = keyV.replacingOccurrences(of: "ret=", with: "").ext2Int
break
}
}
}
switch errCode {
case 0:
errStr = "成功"
case -2:
errStr = "用户取消"
case -3:
errStr = "发送失败"
case -4:
errStr = "授权失败"
case -5:
errStr = "微信不支持"
default:
errStr = "普通错误"
}
DebugLog("=========微信 errStr: \(errStr) =========")
NotificationCenter.default.post(name: NSNotification.Name(kNotificatonWechatPayDone), object: nil, userInfo: ["errMsg": errStr])
return true
}
return true
}
- 支付宝
- 后台请求支付宝拿到
orderStr
alipay_sdk=alipay-sdk-java-3.4.49.ALL&app_id=123456&biz_content=%7B%22body%22%3A%22%E5%8D%83%E7%AD%BE%E4%BD%99%E9%A2%9D%E5%85%85%E5%80%BC%22%2C%22out_trade_no%22%3A%221603543654767%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22%E5%85%85%E5%80%BC%22%2C%22timeout_express%22%3A%2230m%22%2C%22total_amount%22%3A%220.01%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2F11.11.11.11%3A8090%2Fa%2Freturn_url_Balan&sign=bhxuUOzWMWzyMtKREEyMEGsvBoYJR4Z2IR%2Bj9S4EPhHssC6QvXS6pMPscfZbaM7kLERpi0Heab6kKouJmeLaCgTecRlTwnVQdxflKb8C9vZBgOEcHVIpAthiUDvYrOnO%2FfZG0MTme6ecSTcTylcVLsRBOLpBoidsSWrcOsSsgxrNhyqkNDr6MhoEF09CiNYtDL0ubqZNekBwt2mKmhO0LHhcEIrkYZ0Gt5daq36z8%2FSPsrdmWt%2FMJoPv4Jz36yflC9oO9%2FhS%2FDXDGe76tAmzlboDy3YmY9LtwzOuR%2FmQUT0LizKurOyjQ3koQIsaogVI6nVmMY7SFHhRvZF%2BpaK5ug%3D%3D&sign_type=RSA2×tamp=2020-10-24+20%3A47%3A34&version=1.0
- 组成字典
let dic = [
"fromAppUrlScheme": "myScheme",
"requestType": "SafePay",
"dataString": orderStr
]
- 转成
JSON
字符串dictJsonStr
guard let dicJsonStr = dic.ext2JsonString(true) else { return }
DebugLog(dicJsonStr)
-
dictJsonStr
URL
编码成dicJsonEncodeStr
let dicJsonEncodeStr = dicJsonStr.extUrlEncode()
DebugLog(dicJsonEncodeStr)
- 拼接"alipay://alipayclient/?"+
dicJsonEncodeStr
,得到url
直接打开链接,进入支付宝支付页面
if let url = URL(string: url) {
UIApplication.shared.open(url, completionHandler: nil)
}
func zfbPay() {
let dic = [
"fromAppUrlScheme": "myScheme",
"requestType": "SafePay",
"dataString": orderStr
]
guard let dicJsonStr = dic.ext2JsonString(true) else { return }
DebugLog(dicJsonStr)
let dicJsonEncodeStr = dicJsonStr.extUrlEncode()
DebugLog(dicJsonEncodeStr)
if let url = URL(string: "alipay://alipayclient/?"+dicJsonEncodeStr) {
DebugLog(url)
UIApplication.shared.open(url, completionHandler: nil)
}
}
}
- 支付回调
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let handleUrlStr = url.absoluteString
DebugLog("=========open url Links=========")
/** rstDic:
{
memo = "支付未完成";
result = "";
resultStatus = 6001;
}
*/
if let scheme = url.scheme {
///支付宝的
if scheme == kSelfScheme {
let urlDecoded = handleUrlStr.extUrlDecoded()
DebugLog("解码:", urlDecoded)
//拿到{"memo"字典
if var rstStr = urlDecoded.components(separatedBy: "?").last {
rstStr = rstStr.replacingOccurrences(of: "ResultStatus", with: "resultStatus")
if let rstDic = rstStr.ext2Dictionary() {
DebugLog(rstDic)
if let mmDic = rstDic["memo"] as? [String: Any], let resultStatus = mmDic["resultStatus"] as? String {
DebugLog(mmDic)
DebugLog(resultStatus)
var errStr = ""
let errCode = resultStatus.ext2Int
switch errCode {
case 9000:
errStr = "成功"
case 6002:
errStr = "网络连接出错"
case 6001:
errStr = "用户取消"
case 4000:
errStr = "订单失败"
case 5000:
errStr = "重复请求"
default:
errStr = "请查询订单的状态"
}
DebugLog("===============baobao errStr: \(errStr) ================")
NotificationCenter.default.post(name: NSNotification.Name(kNotificatonZfbPayDone), object: nil, userInfo: ["errMsg": errStr])
return true
}
}
}
return true
}
}
return true
}
-
String
扩展
//
// MARK: - URL编码 解码
//
extension String {
func extUrlEncode() -> String {
let str = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,self as NSString, nil,
"!*'();:@&=+$,/?%#[]" as CFString, CFStringConvertNSStringEncodingToEncoding(String.Encoding.utf8.rawValue))
return str! as String
}
func extUrlDecoded() -> String {
return removingPercentEncoding ?? ""
}
}
extension String {
func ext2Dictionary() -> [String: Any]? {
guard let data = data(using: .utf8) else {
return nil
}
guard let dic = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String: Any] else {
DebugLog(self, " 不能解析成字典")
return nil
}
return dic
}
}
oc 拼接url
NSDictionary *dic = @{
@"appid": @"微信的AppID",
@"noncestr": @"ZLOOW0wSxjYZt6AP",
@"package": @"Sign=WXPay",
@"partnerid": @"1603068427",
@"prepayid": @"wx22214520388210c0a8bc66702ed24d0000",
@"sign": @"DBF8AC4C59AAA0B65757421A37EEBBB9",
@"timestamp": @"1603374320"
};
NSMutableString *result= [NSMutableString string];
for (NSString *key in dic) {
NSString *value = dic[key];
[result appendFormat:@"%@=%@&", key, value];
}
NSString *rst = [result stringByReplacingOccurrencesOfString:@"Sign=WX" withString:@"Sign%3DWX"];
rst = [rst substringToIndex:result.length-1];
NSLog(@"%@\n%@", result, rst);
- 支付宝返回码
返回码 | 含义 |
---|---|
9000 | 订单支付成功 |
8000 | 正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态 |
4000 | 订单支付失败 |
5000 | 重复请求 |
6001 | 用户中途取消 |
6002 | 网络连接出错 |
6004 | 支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态 |
其它 | 其它支付错误 |
最后贴个集成SDK
的文档链接
https://opendocs.alipay.com/open/204/105295/
https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html#jump2
网友评论