文章目录
  1. 1. 引言
  2. 2. AliPay
  3. 3. 流程图
    1. 3.1. 支付流程
    2. 3.2. 业务流程
  4. 4. 设置RSA公钥
  5. 5. Code
    1. 5.1. 集成和配置
    2. 5.2. ATS 说明
    3. 5.3. 配置 Model
    4. 5.4. AppDelegate
    5. 5.5. 本地测试
    6. 5.6. 回调说明
    7. 5.7. 客户端验签
    8. 5.8. 解析结果
  6. 6. FQA
  7. 7. 参考资料

引言


移动支付越来越火,每一个应用都开始植入移动支付,比较常用的支付有支付宝、微信、银联等支付方式,今天来讲一下如何集成支付宝,讲的不好之处,请指出,共同探讨进步!

AliPay


版本号:v2.0.1 支付宝钱包支付接口开发包2.0标准版(20160516) 密码: bfj8
跟支付宝签名,商家成为支付宝的“商户”,二级商户:自己支付平台是第一级商户,加入平台的商户成为第二级商户。

流程图


大致支付流程(在服务端进行签名):用户在商户客户端下单 -> 商户客户端会获取用户的地址,收货人信息,商品ID,UID,私钥 -> 发送给商户服务端,商户服务端创建一个订单号,对订单号加密 -> 然后将加密的订单号返回给商户客户端 -> 商户客户端调用支付宝SDK,并传递信息 -> 等待支付宝支付结果,并做友好提示,支付宝服务端接收支付结果。

支付流程


支付宝支付流程

业务流程


支付宝数据业务交互

设置RSA公钥


1、如果您使用了支付宝移动支付、即时到账产品,请在【合作伙伴密钥管理】模块下添加RSA公钥。
2、如果您使用了支付宝手机网站支付产品,请在【无线产品密钥管理(wap专用)】模块下添加RSA公钥。
3、如果您使用了支付宝当面付产品(包括条码支付、扫码支付、声波支付),请在【开放平台密钥管理】接入应用为当面付的模块下添加RSA公钥

本地生成 RSA 私钥以公钥,私钥保存在本地,将公钥上传至支付宝平台,以下使用 Mac 上自带的 openssl 生成私钥和公钥

1
2
3
4
OpenSSL> genrsa -out rsa_private_key.pem   1024  #生成私钥
OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out rsa_private_key_pkcs8.pem #Java开发者需要将私钥转换成PKCS8格式
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem #生成公钥
OpenSSL> exit #退出OpenSSL程序

Code


集成和配置


关于如何集成和配置不过多的进行介绍,eg:导入包、所需类库和引入头文件等,具体相关配置请参考官方 Demo。

ATS 说明


如果你的app基于9.0编译,那么为了适配iOS9.0中的App Transport Security(ATS)对http的限制,这里需要对支付宝的请求地址alipay.com、alipayobjects.com做例外,在app对应的info.list中添加如下配置(文中以XML格式描述)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>alipay.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>alipayobjects.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>

也可以用下面进行替代:

1
2
3
4
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>

配置 Model


1
2
3
4
5
6
7
8
9
10
11
12
13
14
Order *order = [[Order alloc] init];
order.partner = partner; //商户ID
order.seller = seller; // 收款账号
order.tradeNO = [self generateTradeNO]; //订单ID(由商家自行制定)
order.productName = product.subject; //商品标题(产品名)
order.productDescription = product.body; //商品描述
order.amount = [NSString stringWithFormat:@"%.2f",product.price]; //商
品价格
order.notifyURL = @"http://www.test.com"; //回调URL
//以下目前固定写法
order.service = @"mobile.securitypay.pay";//没有支付宝客户端,跳转网页
order.paymentType = @"1"; //目前只有1
order.inputCharset = @"utf-8";
order.itBPay = @"30m";

AppDelegate


配置支付宝客户端返回url处理方法。(外部存在支付包钱包,支付宝钱包将处理结果通过url返回。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
如果从另一个应用进入,将调用此方法。
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
//url 支付宝传过来的结果,支付宝不建议解析url // scheme://safepay/ (scheme 自定义的, safepay 安全支付)
// url.scheme 协议头
// url.host 域名
// sourceApplication 从哪个应用来的

//如果极简开发包不可用,会跳转支付宝钱包进行支付,需要将支付宝钱包的支付结果回传给开发包
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
//【由于在跳转支付宝客户端支付的过程中,商户app在后台很可能被系统kill了,所以pay接口的callback就会失效,请商户对standbyCallback返回的回调结果进行处理,就是在这个方法里面处理跟callback一样的逻辑】
NSLog(@"result = %@",resultDic);
}];
}
if ([url.host isEqualToString:@"platformapi"]){//支付宝钱包快登授权返回authCode
[[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
//【由于在跳转支付宝客户端支付的过程中,商户app在后台很可能被系统kill了,所以pay接口的callback就会失效,请商户对standbyCallback返回的回调结果进行处理,就是在这个方法里面处理跟callback一样的逻辑】
NSLog(@"result = %@",resultDic);
}];
}
return YES; //YES 允许调起
}

本地测试


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//应用注册scheme,在AlixPayDemo-Info.plist定义URL types
NSString *appScheme = @"alisdkdemo"; //支付宝调到当前客户端的标识

//将商品信息拼接成字符串
NSString *orderSpec = [order description];
NSLog(@"orderSpec = %@",orderSpec);

//获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
id<DataSigner> signer = CreateRSADataSigner(privateKey);
NSString *signedString = [signer signString:orderSpec];

//将签名成功字符串格式化为订单字符串,请严格按照该格式
NSString *orderString = nil;
if (signedString != nil) { // 签名成功
//拼接最终的订单和签名信息
orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"", orderSpec, signedString, @"RSA"];
//调起支付宝支付
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
//【callback处理支付结果】 支付结束之后的回调
NSLog(@"reslut = %@",resultDic); //code == 9000 支付成功

}];
}

回调说明


在支付过程结束后,会通过callbackBlock同步返回支付结果。返回结果需要通过resultStatus以及result字段的值来综合判断并确定支付结果。在resultStatus=9000,并且success=“true”以及sign=“xxx”校验通过的情况下,证明支付成功。其它情况归为失败。较低安全级别的场合,也可以只通过检查resultStatus以及success=“true”来判定支付结果。以下为订单支付成功的完成信息示例:

1
2
3
4
5
{
memo = "";
result = "partner=\"2088101568358171\"&seller_id=\"[email protected]\"&out_trade_no=\"0819145412-6177\"&subject=\"测试\"&body=\"测试测试\"&total_fee=\"0.01\"&notify_url=\"http://notify.msp.hk/notify.htm\"&service=\"mobile.securitypay.pay\"&payment_type=\"1\"&_input_charset=\"utf-8\"&it_b_pay=\"30m\"&success=\"true\"&sign_type=\"RSA\"&sign=\"hkFZr+zE9499nuqDNLZEF7W75RFFPsly876QuRSeN8WMaUgcdR00IKy5ZyBJ4eldhoJ/2zghqrD4E2G2mNjs3aE+HCLiBXrPDNdLKCZgSOIqmv46TfPTEqopYfhs+o5fZzXxt34fwdrzN4mX6S13cr3UwmEV4L3Ffir/02RBVtU=\"";
resultStatus = "9000";
}

客户端验签


一般可以在服务器端进行验签,将支付宝返回的字段上传到服务器即可,服务器端进行判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//验签
//去掉返回字典中result值里面的“\\”
NSString *result = [resultDic[@"result"] stringByReplacingOccurrencesOfString:@"\\\\" withString:@""];
//分割字符串获取订单信息和签名
NSString * comStr = @"&sign_type=\"RSA\"&sign=\"";
NSArray *array = [result componentsSeparatedByString:comStr];
//返回的订单信息
NSString *orderString = array[0];
//返回的订单签名
NSString *signedString = [array[1] substringToIndex:[array[1]length]-1];
//验证返回信息与签名
if ([verifier verifyString:orderString withSign:signedString])
{
//验证签名成功,交易结果无篡改
NSLog(@"------------支付成功---------------");
}
else
{
//验签错误
NSLog(@"======错误=======");
}

解析结果


支付结果的提取,必须通过CompletionBlock获取,禁止开发者私自解析支付结果返回的URL。获取值的Key对应resultStatus、memo与result(result中的值,开发者可以自行解析);

为了保障已有商户的正常使用,返回参数ResultStatus首字母为大写。在新的SDK中已经用统一的工具类实现了ResultStatus到resultStatus的转换,商户从CompletionBlock中获取resultStatus即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ([resultDic[@"resultStatus"] isEqualToString:@"9000"]) {
NSString * resultStr = resultDic[@"result"];
NSRange signRange = [resultStr rangeOfString:@"&sign=\""];
NSString * sign = [resultStr substringWithRange:NSMakeRange(signRange.location + signRange.length, [resultStr length] - signRange.location - signRange.length - 1)];
NSLog(@"%@", sign);
NSRange successRange = [resultStr rangeOfString:@"&success=\""];
NSString * daiqianming = [resultStr substringToIndex:successRange.location];
NSLog(@"%@", daiqianming);
NSString * status = [resultStr substringWithRange:NSMakeRange(successRange.location + successRange.length, 1)];

if ([status isEqualToString:@"t"]) {
NSLog(@"HT 支付宝测试成功");
}
}

FQA


0、如何找到 AliPay SDK,大致方法如下:
文档中心 -> 资源下载 -> 开发工具包下载 -> 移动支付DEMO&SDK
1、如何在支付宝平台设置 RSA 公钥钥
商家服务 -> 我的商家服务 -> 查询PID、Key
Setting-RSA   

参考资料


1、导入代码
2、手动集成问题解决
3、支付宝支付生成与配置RSA密钥
4、查看RSA商户公钥与支付宝公钥
5、关于iOS开发支付宝集成,客户端签名与验证
6、PING++ 开发者中心
7、BeeCloud

文章目录
  1. 1. 引言
  2. 2. AliPay
  3. 3. 流程图
    1. 3.1. 支付流程
    2. 3.2. 业务流程
  4. 4. 设置RSA公钥
  5. 5. Code
    1. 5.1. 集成和配置
    2. 5.2. ATS 说明
    3. 5.3. 配置 Model
    4. 5.4. AppDelegate
    5. 5.5. 本地测试
    6. 5.6. 回调说明
    7. 5.7. 客户端验签
    8. 5.8. 解析结果
  6. 6. FQA
  7. 7. 参考资料