iOS支付宝支付集成
最近做了一个新项目,涉及到支付宝和微信支付,支付宝和微信都是业界的老大哥,相信大家都有所觉得文档、SDK都是各种坑吧(纯粹吐槽而已),本文先整理支付宝支付集成,下一篇我保证是微信支付集成。
1.准备工作
1> 向支付宝”签约" 成为支付宝的”商户”, 签约完成后, 支付宝会提供一些必要的数据给我们(商户ID-partner,帐号ID-支付宝帐号)
注意:签约成为支付宝商户,需要提供公司营业执照
http://act.life.alipay.com/shopping/before/help/index.html
2> 获取支付相关的 '私钥' 和 '密钥'
https://doc.open.alipay.com/doc2/detail?treeId=44&articleId=103242&docType=1
3> 下载支付的SDK
https://doc.open.alipay.com/doc2/detail?treeId=54&articleId=103419&docType=1
2.集成支付宝SDK步骤:
1>
从官方Demo中把红色标注的文件添加进入项目中,记得选copy;
A6C4BD34-0AE0-4C91-9095-2C923F07B3F8.png2>
点击项目名称,点击“Build Phases”选项卡,在“Link Binary with Librarles” 选项中,新增“AlipaySDK.framework”和“SystemConfiguration.framework” 两个系统库文件。如果项目中已有这两个库文件,可不必再增加;
添加下图中的库
localhost:alipay mac$ ls
APAuthV2Info.h Order.h libssl.a
APAuthV2Info.m Order.m openssl
AlipaySDK.bundle Util
AlipaySDK.framework libcrypto.a
导入系统库
SystemConfiguration.framework
3>
添加Pch文件新建pch成功后,在pch文件中添加#import然后按照下图所示,进行修改pch的文件路径
也可以不设置,我这个是我需要设置#import <UIKit/UIKit.h> #import <Foundation/Foundation.h>,也可以不用使用,只在当前文件里添加相对应的使用即可,但是这样针对整个项目来说方便些
4>
修改SDK路径完成以上两步之后,会发现出现了一个经典的错误,找不到:#include解决这个问题,需要在Header Search Path中配置SDK中的点a(libssl.a/libcrypto.a)文件所在的路径,找到之后设置好正确的路径
点击项目名称,点击“Build Settings”选项卡,在搜索框中,以关键字“search” 搜索,对“Header Search Paths”增加头文件路径:“$(SRCROOT)/项目名称/IntegratedAlipay/AlipayFiles”(注意:不包括引号,如果不是放到项目根目录下,请在项目名称后面加上相应的目录名);
E6CC94B7-0553-4113-8B30-3A29FE998F4A.png根据你文件位置,我的是:
“$(SRCROOT)/QTXStudent/Classes/Alipay/AlipayFiles”
5>
点击项目名称,点击“Info”选项卡,在URL types里面添加一项,Identifier可以不填,URL schemes必须和appScheme的值相同,用于支付宝处理回到应用的事件;
为URL Types 添加支付宝回调scheme
6> 在工程项目的plist文件中添加
iOS 9以后的系统需要添加支付宝分享的scheme到白名单中,scheme名为alipayshare
按如下形式添加即可:
A6BF0BC0-4CEC-47B7-A68C-6A065AE71C2C.png
7> 在AppDelegate中处理事件回调:
// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
BOOL result = [UMSocialSnsService handleOpenURL:url];
if (result == NO) { // 調用其他 SDK 支付寶
//如果极简 SDK 不可用,会跳转支付宝钱包进行支付,需要将支付宝钱包的支付结果回传给 SDK
if ([url.host isEqualToString:@"safepay"]) {
//跳转支付宝钱包进行支付,处理支付结果
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
QTXLog(@"支付宝客户端支付结果result = %@",resultDic);
if (resultDic && [resultDic objectForKey:@"resultStatus"] && ([[resultDic objectForKey:@"resultStatus"] intValue] == 9000)) {
// 发通知带出支付成功结果
[QTXNotificationCenter postNotificationName:QTXAliReturnSucceedPayNotification object:resultDic];
} else {
// 发通知带出支付失败结果
[QTXNotificationCenter postNotificationName:QTXAliReturnFailedPayNotification object:resultDic];
}
}];
}
if ([url.host isEqualToString:@"platformapi"]){//支付宝钱包快登授权返回 authCode
[[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
QTXLog(@"支付宝网页版result = %@",resultDic);
if (resultDic && [resultDic objectForKey:@"resultStatus"] && ([[resultDic objectForKey:@"resultStatus"] intValue] == 9000)) {
// 发通知带出支付成功结果
[QTXNotificationCenter postNotificationName:QTXAliReturnSucceedPayNotification object:resultDic];
} else {
// 发通知带出支付失败结果
[QTXNotificationCenter postNotificationName:QTXAliReturnFailedPayNotification object:resultDic];
}
}];
}
//微信的支付回调
if ([url.host isEqualToString:@"pay"]) {
return [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
}
}
return result;
}
8> 在需要用的地方导入“AlipayHeader.h”,并使用“[AlipayRequestConfig alipayWithPartner:...”方法进行支付;
#import <Foundation/Foundation.h>
#import "AlipayHeader.h"
@interface AlipayRequestConfig : NSObject
/**
* 配置请求信息,仅有变化且必要的参数
*
* @param partner 合作者身份ID 以 2088 开头由 16 位纯数字组成的字符串。
* @param sellerID 卖家支付宝账号 以 2088 开头由 16 位纯数字组成的字符串。
* @param outTradeNO 商户网站唯一订单号
* @param subject 商品名称
* @param body 商品详情
* @param totalFee 总金额
* @param notifyURL 服务器异步通知页面路径
* @param itBPay 未付款交易的超时时间
*/
+ (void)alipayWithPartner:(NSString *)partner
sellerID:(NSString *)sellerID
outTradeNO:(NSString *)outTradeNO
subject:(NSString *)subject
body:(NSString *)body
totalFee:(NSString *)totalFee
notifyURL:(NSString *)notifyURL;
@end
#import "AlipayRequestConfig.h"
@implementation AlipayRequestConfig
// 仅含有变化的参数
+ (void)alipayWithPartner:(NSString *)partner
sellerID:(NSString *)sellerID
outTradeNO:(NSString *)outTradeNO
subject:(NSString *)subject
body:(NSString *)body
totalFee:(NSString *)totalFee
notifyURL:(NSString *)notifyURL {
[self alipayWithPartner:partner sellerID:sellerID outTradeNO:outTradeNO subject:subject body:body totalFee:totalFee notifyURL:aliNotifyURL service:@"mobile.securitypay.pay" paymentType:@"1" inputCharset:@"utf-8" itBPay:@"30m" privateKey:aliPrivateKey appScheme:aliAppScheme];
}
// 包含所有必要的参数
+ (void)alipayWithPartner:(NSString *)partner
sellerID:(NSString *)sellerID
outTradeNO:(NSString *)outTradeNO
subject:(NSString *)subject
body:(NSString *)body
totalFee:(NSString *)totalFee
notifyURL:(NSString *)notifyURL
service:(NSString *)service
paymentType:(NSString *)paymentType
inputCharset:(NSString *)inputCharset
itBPay:(NSString *)itBPay
privateKey:(NSString *)privateKey
appScheme:(NSString *)appScheme {
Order *order = [Order order];
order.partner = partner;
order.sellerID = sellerID;
order.outTradeNO = outTradeNO;
order.subject = subject;
order.body = body;
order.totalFee = totalFee;
order.notifyURL = notifyURL;
order.service = service;
order.paymentType = paymentType;
order.inputCharset = inputCharset;
order.itBPay = itBPay;
// 将商品信息拼接成字符串
NSString *orderSpec = [order description];
// 获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循 RSA 签名规范, 并将签名字符串 base64 编码和 UrlEncode
NSString *signedString = [self genSignedStringWithPrivateKey:aliPrivateKey OrderSpec:orderSpec];
// 调用支付接口
[self payWithAppScheme:appScheme orderSpec:orderSpec signedString:signedString];
}
// 生成signedString
+ (NSString *)genSignedStringWithPrivateKey:(NSString *)privateKey OrderSpec:(NSString *)orderSpec {
// 获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循 RSA 签名规范, 并将签名字符串 base64 编码和 UrlEncode
id<DataSigner> signer = CreateRSADataSigner(privateKey);
return [signer signString:orderSpec];
}
// 支付
+ (void)payWithAppScheme:(NSString *)appScheme orderSpec:(NSString *)orderSpec signedString:(NSString *)signedString {
// 将签名成功字符串格式化为订单字符串,请严格按照该格式
NSString *orderString = nil;
if (signedString != nil) {
orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"", orderSpec, signedString, @"RSA"];
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) { // 网页版
QTXLog(@"支付宝支付结果 reslut = %@", resultDic);
// 返回结果需要通过 resultStatus 以及 result 字段的值来综合判断并确定支付结果。 在 resultStatus=9000,并且 success="true"以及 sign="xxx"校验通过的情况下,证明支付成功。其它情况归为失败。较低安全级别的场合,也可以只通过检查 resultStatus 以及 success="true"来判定支付结果
if (resultDic && [resultDic objectForKey:@"resultStatus"] && ([[resultDic objectForKey:@"resultStatus"] intValue] == 9000)) {
// 发通知带出支付成功结果
[QTXNotificationCenter postNotificationName:QTXAliReturnSucceedPayNotification object:resultDic];
} else {
// 发通知带出支付失败结果
[QTXNotificationCenter postNotificationName:QTXAliReturnFailedPayNotification object:resultDic];
}
}];
}
}
@end
9>
在本头文件中设置aliPartnerID、aliSellerAccount、aliNotifyURL、aliAppScheme和aliPrivateKey的值(所有的值在支付宝回复的邮件里面:注意,建议除appScheme以外的字段都从服务器请求);
这时候,我们支付就直接一句话搞定:
// 支付宝支付
[AlipayRequestConfig alipayWithPartner:aliPartnerID sellerID:aliSellerAccount outTradeNO:self.order subject:self.shortName body:self.shortName totalFee:totalFee notifyURL:aliNotifyURL];
// 接收通知处理支付结果不同事件 当然最后不要忘了去delloc移除通知
[QTXNotificationCenter addObserver:self selector:@selector(paySucceed) name:QTXAliReturnSucceedPayNotification object:nil];
[QTXNotificationCenter addObserver:self selector:@selector(payFailed) name:QTXAliReturnFailedPayNotification object:nil];
10> 建议除appScheme以外的字段都从服务器请求!
建议除appScheme以外的字段都从服务器请求!建议除appScheme以外的字段都从服务器请求!
PS:重要的事情说三遍!!!
上面的第七步和第八步建议不要使用,直接用第九步去替代!建议除appScheme以外的字段都从服务器请求!
如果后台给你一个接口返回那些参数了,你就不用客户端去加密算法,只负责请求后台拿到这些参数再去请求支付宝即可.
下面例子是支付宝的拼接方式,请按照当前版本的相对应的拼接方式来.
// 支付宝支付
- (void)alipayPay {
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"orderNo"] = self.orderNo; // 订单号
params[@"realAmt"] = [NSString stringWithFormat:@"%.2lf", self.realAmt]; // 金额
__weak __typeof(self) weakSelf = self;
[QTXHttpTool post:QTX_aliPay_url params:params success:^(id json) {
QTXLog(@"支付宝支付返回参数接口 请求成功-%@", json);
if ([json[@"success"] isEqual:@(YES)]) {
// 返回生成订单信息及签名
NSString *signedString = json[@"data"][@"sign"];
NSString *orderInfoEncoded = json[@"data"][@"orderInfo"];
// NOTE: 如果加签成功,则继续执行支付
if (signedString != nil) {
// NOTE: 将签名成功字符串格式化为订单字符串,请严格按照该格式
// NSString *orderString = [NSString stringWithFormat:@"%@&sign=%@&sign_type=RSA", orderInfoEncoded, signedString];
NSString *orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",
orderInfoEncoded, signedString, @"RSA"];
// NOTE: 调用支付结果开始支付
[[AlipaySDK defaultService] payOrder:orderString fromScheme:XHHAppScheme callback:^(NSDictionary *resultDic) {
QTXLog(@"reslut = %@",resultDic);
if ([resultDic[@"resultStatus"] intValue] == 9000) {
[QTXNotificationCenter addObserver:self selector:@selector(paySucceed) name:QTXWXReturnSucceedPayNotification object:nil];
} else {
[QTXNotificationCenter addObserver:self selector:@selector(payFailed) name:QTXWXReturnFailedPayNotification object:nil];
}
}];
}
} else {
[MBProgressHUD showError:[NSString stringWithFormat:@"%@", json[@"errorMessage"]]];
}
} failure:^(NSError *error) {
[MBProgressHUD showError:@"暂无网络,稍后再试"];
QTXLog(@"支付宝支付返回参数接口 请求失败-%@", error);
}];
}
11> 支付宝集成失败相关问题
-
报错 AL159
查看金额是否是两位小数,切不可拼接"元" -
报错“创建交易异常,请重新创建后再付款”
返回的状态码是“6001”,取消支付
当是用公司注册支付宝App时分配的商户账号登陆的支付宝,进行支付测试的。支付宝那边检测到是商户而不是普通的支付账号,商户支付给商户自己,所以支付失败! -
新版的 iOS 11, 除appScheme以外的字段都从服务器请求的, 我们服务器是直接返回拼接好的数据, 这块一定需要用新的支付宝集成文件包, 否则一直不能返回支付成功或失败的.
如果需要微信支付, 请移步:iOS微信支付集成