项目中要用到支付功能,需要支付宝,微信,银联三大支付,所以打算总结一下,写两篇文章,方便以后的查阅, 大家在做的时候也能稍微参考下,用到的地方避免再次被坑。这是第二篇支付宝集成,第一篇银联支付。本来要用那个ping++的神器,可以集成各种支付手段,异常的方便,但是考虑到安全性问题的话,支付的渠道还是不让第三方参与的好,不然会不安全,于是就苦逼地慢慢的一个一个集成了。。。。这里就代理支付宝的集成过程:
刚开始以为支付宝集成还是比较简单的,看了几个文章,网上的各位大神也是各种秀操作,说集成很简单,但是,真正做起来就不是那回事了, 特别是新版的1月11号更新的,我正好是这一天开始看的,网上的经验什么的 大都是比较老的,比较新的能用到的文章不多(但是好文章还是有的,对我帮助也很大),现在我就来一步一步说一下自己集成支付宝的血泪史!
下载支付宝SDK
首先是开发包下载,还是比较难发现的,网上以前文章中的链接都打不开,我找了好久才找到的。(注意的是下载出来的SDK包里面并没有传说中的开发文档,需要其他地方找或者看网页上的)。
公钥、私钥、PID、sellerID、key这些东西的用途和获取方式在文档上都有详细的说明,这里不再赘述,一定要把概念分清楚再去做,不然一会就乱了。如果遇到问题的话咱们可以再一起探讨。支付流程理解
开发文档、开发文档、开发文档,重要的事情一定要说三遍!!!建议先把开发文档仔仔细细看一遍,一定要看,本小白刚开始的时候没有老老实实地看完,结果遇到很多很多的坑,以血和泪劝解大家,浪费的挺多的时间的,所以建议一定要好好看看,特别是交互流程这一部分
到这里就完成了支付的过程了。我觉得这个流程还是很容易理解的。
其中咱们就是商户客户端需要做的就是:• 调用支付宝支付接口• 处理支付宝返回的支付结果ps:签名部分为了安全起见都放在了后台,如果你们执意要在手机客户端做签名,不怕被拦截那就再加上一步签名。也才三步,还是很简单。
调用支付接口
在调用支付宝支付接口前,我们需要先生成一个订单,文档中描述时,是将这步也放在客户端来做了,但这个最好是 放在服务器端来做,后台生成订单然后拼接,签名,然后服务器端直接给客户端传一个加密签名过的参数就可以了,这样比较安全,官方demo上放在客户端生成订单并且签名是因为没有服务给你用啊,所以就客户端上生成了~~~。
我做的时候,为了安全,生成订单,拼接字符串,签名,都是在服务器上做的,所有的订单信息,商户信息等都掌握在自己的手中,这样的话APP端就不怕被拦截数据,并且调用起来也就特别简单了,只需要调用支付的接口,打开支付宝APP客户端进行支付就行了,没有用户的手机上没有安装支付宝客户端的话会调用网页来支付,也是一样的。如果只需要发送订单和处理支付返回结果,只需要添加AlipaySDK.bundle和AlipaySDK.framework这两个就行了,下载的SDK中很容易发现。快捷支付方法是这个:-(void)payOrder:(NSString *)orderStr fromScheme:(NSString *)schemeStr callback:(CompletionBlock)completionBlock;
在支付的按钮中,试用支付宝这个类,再调用这个方法就行啦!如下如:
在调用支付宝接口的时候,我们需要两个参数,orderString
和APPScheme
, APPScheme是app在info.plist注册的scheme。
流程就这么简单,接下来是集成SDK的时间,这部分很坑,因为是我们是商品的数据签名什么的都在后台做的,所以客户端做的时候遇到的坑就不多说了,可以参考,基本上遇到的坑都能找到。
是有人对这个进行的一个简单的封装,如果签名,数据部分需要在APP上做的话,可以直接用这个,封装很简单,也是加了个类目进行做出来的,实现很简单。大家可以参考一下。支付宝的SDK给了一个处理返回结果的方法,就是那个openURL的那个,在demo的appdelegate里面有。
if ([url.host isEqualToString:@"safepay"]) {[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) { NSLog(@"result = %@",resultDic); }]; }
关于签名(主要是在客户端签名时候注意的)
支付宝上要用那个RSA,这是个算法,所以为了方便,可以使用第三方的方法,或者找demo上的代码粘贴上去!不过还是那句话,为了安全,最好还是后台的做,不怕被拦截了 。
签名的时候,涉及到了RSA公钥、私钥的生产,RSA的签名、验证签名,SHA1值的计算,base64和URL编码等等等等烦人的东西,估计支付的程序猿也不想麻烦,就用了一个开源的代码来统一解决这些问题,就是openssl这个文件夹。如果你执意要在客户端上签名(前面说过,并不安全),也可以用demo中的openssl这个文件夹,那你需要导入这几个文件夹:DEMO中的openssl目录头文件,两个库文件libcrypto.a libssl.a,DEMO里支付宝自己写的Util目录,如下图:支付宝文档上的,写的很详细了,一般遇到的问题都有提到。
推荐几篇好文章,可以参考下,减少点坑(1、4、5务必看看,很有启发的):
1.2.3.4.5.这篇文章是在的,写的也很详细
今天又遇到个问题:调起了支付宝客户端,但是支付不了。
这个是因为,如果订单来自服务器此错误表示后台返回的签名订单含有特殊字符 ,需要编码。
由于RSA签名机制每次生成的签名都不一样,也就是是二进制数,后台返回签名的订单时,是基于base64位编码的 。可能基于base64位编码生成带有+=/等在url序列中不被允许的字符。当我们拿着后台不进行特殊字符处理的订单作为参数去调用支付宝的接口时,便会出现由于支付宝客户端吊起支付宝服务器是URL有问题,导致错误ALI64 。解决办法是 让后台处理一下参数中的特殊字符,具体的.
iOS 移动支付之种类
iOS 端的移动支付,大概包括:支付宝支付、微信支付、银联卡支付、paypal支付,现在又多出一个Apple pay支付;
如何集成这些种类的支付方式
谈及如何集成这些支付方式,面对各种支付方式的SDK以及Demo写的详细的完美无缺,我还真不如还如何去写,这里我就接地气的写写,写的不好请勿喷哦☺!
支付宝支付
大致有以下步骤:
1.向支付宝申请, 与支付宝签约,获得商户PID(partner)和账号ID(seller)和私钥(privateKey)
注:*这一步,一般公司会搞定的,这里只是让你知道来龙去脉☺
没有支付宝账号的同学,可以; 已经有支付宝账号的同学申请签约有个门槛比较难,就是不管你是个人还是企业,都需要营业执照,这点有点蛋疼,不过人家也是为了有质量的管理申请者嘛,可以理解,我这里没有营业执照,申请工作就死在了摇篮里,不过大致流程,我基本弄清楚了,不过作为开发者,这申请工作就不用多关心了,一般公司都会有申请过的,我这里写出来也就是让我们开发者也大概知道流程,而不是直接就是用,只知去向,不知来龙。 申请签约成功后,就可以查看 PID(partner)和账号ID(seller)和私钥(privateKey) , 进行登录,点击下图中的查询PID和Key;但是这里查询到的Key 是公钥,不是私钥,你到底该怎么弄私钥呢?同学们,不用急,支付宝文档写的还是比较清楚的,
这里文档给出了两种平台下的生产方式,我们既然是iOS 开发者,那就选择Linux用户生产的方式吧,可以直接在Mac的终端敲这些命令;
敲过这些命令后,会在本地生产两个文件,分别是私钥和公钥文件在命令行敲入(以行为单位)$cd ~/$open . //打开文件的存放位置想要查看文件内容,还需要使用命令$cat rsa_private_key.pem //会在终端显示文件中的内容,这就是私钥到这里,第一步基本上就可以了,具体还需要自己动手试试,不然还是会一头雾水。2.下载支付宝SDK以及Demo
这一步,没啥好说的,给个地址就行
3.集成SDK到工程中(生成订单信息,签名加密)
支付宝官方集成文档
集成支付宝SDK的步骤,这里是官方给出的, 按照步骤集成总是会出错,这不是我们脑子不行,而是官方毕竟是官方。
查看支付宝给出的Demo,会发现这些文件必须要加到项目中: 其中小方框中的为必须加入,而除了小方框以外的,那就要看你们后台人员是否将签名成功字符串格式化的订单字符串,给你传到前端来,如果没有,那就必须你自己在前端处理; 按理说,这些应该由后台来处理,为了订单信息的安全,以及前端业务的轻运行,都该有后端来处理(注:这点不懂,不要紧,后面还会根据代码在进行讲解;集成中可能遇到的错误
1)Cannot find interface declaration for ‘NSObject’
解决方案:a. 可以在报错的文件中加入#import <Foundation/Foundation.h>
b. 可以建个pch文件加入 `#ifdef __OBJC__#import UIKit/UIKit.h#import Foundation/Foundation.h#endif`
2)提示找不到 openssl/asn1.h 文件
解决方案:Build Settings –> Search Paths –> Header Search paths:$(PROJECT_DIR)/ASPayDemo/Alipay3)_CNCopyCurrentNetworkInfo,referenced from:
解决方案:添加SystemConfiguration.framework部署代码
NSString *partner = @""; //PID NSString *seller = @""; //收款账户,手机号或者邮箱 NSString*privateKey= @"";// 私钥 if ([partner length] == 0 || [seller length] == 0 || [privateKey length] == 0) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"缺少partner或者seller或者私钥。" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alert show]; return; } Order *order = [[Order alloc] init]; order.partner = partner; order.seller = seller; order.tradeNO = @"20160324012412412"; //订单ID(由商家自行制定) order.productName = @"iOS 高级教程"; //商品标题 order.productDescription = @"这是一本关于iOS的一本高级教程书"; //商品描述 order.amount = @"0.1"; //商品价格 order.notifyURL = @"http://www.devashen.com/Notify/Alipay/"; //回调URL order.service = @"mobile.securitypay.pay"; order.paymentType = @"1"; order.inputCharset = @"utf-8"; order.itBPay = @"30m"; order.showUrl = @"m.alipay.com"; NSString *appScheme = @"alisdkdemo"; //将商品信息拼接成字符串 该方法支付宝已经封好 NSString *orderSpec = [order description]; //获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode id 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) { if ([[resultDic objectForKey:@"resultStatus"] isEqualToString:@"9000"]) { //9000为支付成功 } }]; }
看代码,如果后台将签名成功字符串格式化的订单字符串,给你传到前端来,那我们就只需要做很少的工作就可以了,只需要直接处理订单字符串即可:
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) { if ([[resultDic objectForKey:@"resultStatus"] isEqualToString:@"9000"]) { //9000为支付成功 } }];
最后,千万别忘了,在Appdelegate中,处理支付宝客户端返回url处理方法, 少了这一步,支付宝SDK的回调方法是不会执行的:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { //跳转支付宝钱包进行支付,处理支付结果 [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) { NSLog(@"result = %@",resultDic); }]; return YES;}
到这里,支付宝支付基本上完成, 迫不及待的你,赶紧去试验试验吧, 别忘了给你们相关负责人要对应的PID、收款账号、以及私钥,当然如果后台直接传给你订单字符串的话,你可以直接给后台要接口了,置于PID什么的你就不用管了。