近期客户提出要开发一个IOS上的app作为訪问他们站点的途径之中的一个。为什么说之中的一个呢。因为眼下PC和Mobile这两个站眼下都已经上线了。
所以问题就简单了,我们仅仅须要把mobile站UI改动一下,然后在依据客户的新需求改动下程序,之后把这个站套个IOS的壳子就能够了。
那么问题来了,我们的mobile支付的时候调用的是支付宝的网页支付,这个页面是支付宝的,我们没办法改动,所以假设套在壳子里继续使用这样的支付方式会有点不伦不类的感觉。所以我们就决定调用支付宝钱包,也就是支付宝client。
下面是我參考支付宝移动支付文档整理出来的一些资料:
这是demo的下载地址,包含IOS和Android两个版本号
http://aopsdkdownload.cn-hangzhou.alipay-pub.aliyun-inc.com/demo/WS_MOBILE_PAY_SDK_BASE.zip?
spm=0.0.0.0.LJBZ4o&file=WS_MOBILE_PAY_SDK_BASE.zip
首先要调用支付宝钱包你必须你登录商户的支付宝账户的“签约管理”里面去申请签约开通“移动支付”
PID和密钥管理
支付宝提供商户接口产品时,会自主提供一个保障商户接入安全的一组信息及其相应的配置平台。这组信息就是密钥。由商户密钥与支付宝密钥交换后与支付宝商户标识(如partnerID、APPID等)绑定。
合作伙伴密钥
在服务市场签约获得的大部分接口,签约主体是商户,接口权限属于详细的商户。这部分接口须要使用PID和密钥来调用,此类接口网关一般为mapi(https://mapi.alipay.com/gateway.do)。PID相应的密钥一共同拥有三种签名方式,各自是MD5、RSA、DSA。因为产品的特殊性,每一个产品支持哪些签名方式不尽同样,详细需參考各个产品的接口技术文档。
使用合作伙伴密钥的典型功能包含:快捷登录、移动支付、即时到账收款、手机站点支付等。查看PID和密钥
查看PID
查看MD5(Key)
查看RSA商户公钥与支付宝公钥
查看DSA商户公钥与支付宝公钥上传公钥
上传RSA公钥
上传DSA公钥密钥生成
RSA私钥及公钥生成
DSA私钥及公钥生成
这块流程能够让你上层领导来处理。这里的相关操作都要在商户支付宝账户中操作。我们来看一下我们开发人员须要care的点
①交互流程:
功能流程
流程说明(以Android平台为例):第2步:调用支付接口:此消息就是本接口所描写叙述的开发包提供的支付对象PayTask,将商户订单信息传进pay方法唤起支付宝收银台,订单格式详细參见“请求參数说明”。
第3步:手机支付宝支付开发包将会依照商户App提供的參数发送支付请求。
第5步:异步发送支付通知:手机支付宝支付server端发送异步通知消息给商户server端,參见“server异步通知參数说明”。
第7步:接口返回支付结果:商户应用client通过当前调用支付的Activity的Handler对象,通过它的回调函数获取支付结果,參见“同步通知參数说明”。数据交互
1.构造订单数据并签名
商户client依据手机支付宝支付开发包的接口规则,通过程序生成得到签名结果及要传输给手机支付宝支付开发包的数据集合。签名相关的公私钥生成及配置规则,见PID和密钥管理。
2.发送请求数据
把构造完毕的数据集合传递给手机支付宝支付开发包。
手机支付宝支付开发包对请求数据进行处理
手机支付宝支付开发包将请求数据依据业务规则包装后传递给支付宝服务端,服务端得到这些集合后,会先进行安全校验等验证,一系列验证通过后便会处理完毕这次发送过来的数据请求。
3.返回处理的结果数据
对于处理完毕的交易,支付宝会以两种方式把数据分别反馈给商户应用和商户server。
在手机client上,开发包client直接把处理的数据结果反馈给商户client;
支付宝server主动发起通知,调用商户在请求时设定好的页面路径(參数notify_url,假设商户没设定。则不会进行该操作)。
4.对获取的返回结果数据进行处理
商户在client同步通知接收模块或服务端异步通知接收模块获取支付宝返回的结果数据后,能够结合商户自身业务逻辑进行数据处理(如:订单更新、自己主动充值到会员账号中等)。同步通知结果仅用于结果展示,入库数据需以异步通知为准。
②client调用
iOS
Alipay接口主要为商户提供订单支付功能。接口所提供的方法,例如以下表所看到的:
方法名称 | 方法描写叙述 |
---|---|
+(Alipay *)defaultService; |
获取服务实例。
|
-(BOOL)isLogined; |
检測本地是否曾登录使用过。 |
-(void)payOrder:(NSString *)orderStr fromScheme:(NSString *)schemeStr callback:(CompletionBlock)completionBlock; |
支付并通过回调返回结果。 |
快捷订单支付iOS
方法名称:pay方法
方法原型:(void)payOrder:(NSString *)orderStr fromScheme:(NSString *)schemeStr callback:(CompletionBlock)completionBlock;
方法功能:提供给商户快捷订单支付功能。
參数名称 | 參数描写叙述 |
---|---|
NSString* scheme | 商户程序注冊的URL protocol,供支付完毕后回调商户程序使用。 |
(CompletionBlock)completionBlock | 快捷支付开发包回调函数,返回免登、支付结果。相应的结果參考“同步通知參数说明”。 |
NSString* orderStr | 主要包含商户的订单信息,key=“value”形式。以&连接。 |
支付參数示比例如以下,參数说明见“请求參数说明”:
partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測试"&body="測试測试"&total_fee="0.01"¬ify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&sign="lBBK%2F0w5LOajrMrji7DUgEqNjIhQbidR13GovA5r3TgIbNqv231yC1NksLdw%2Ba3JnfHXoXuet6XNNHtn7VE%2BeCoRO1O%2BR1KugLrQEZMtG5jmJIe2pbjm%2F3kb%2FuGkpG%2BwYQYI51%2BhA3YBbvZHVQBYveBqK%2Bh8mUyb7GM1HxWs9k4%3D"&sign_type="RSA"
处理client返回url
方法名称:处理client方法
方法原型:-(void)processOrderWithPaymentResult:(NSURL*)resultUrl standbyCallback:(CompletionBlock)completionBlock;
方法功能:设备已安装支付宝client情况下。处理支付宝client返回的url。
注意:该方法必须实现,否则将会导致在安装手机支付宝的情况下,支付结果无法正常同步返回。
參数名称 | 參数描写叙述 |
---|---|
NSURL *resultUrl | 支付宝client回传的url |
CompletionBlock completionBlock | 当支付宝client在操作时,商户app进程在后台被结束,仅仅能通过这个block输出支付结果。
|
备注:请在APPDelegate的- (BOOL)application:(UIApplication )application openURL:(NSURL )url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation中调用该方法,详细可參见Demo。
回调接口
在支付过程结束后,会通过callbackBlock同步返回支付结果。
返回结果须要通过resultStatus以及result字段的值来综合推断并确定支付结果。在resultStatus=9000,而且success=“true”以及sign=“xxx”校验通过的情况下,证明支付成功。
其他情况归为失败。
较低安全级别的场合。也能够仅仅通过检查resultStatus以及success=“true”来判定支付结果。
下面为订单支付成功的完毕信息演示样例:
ResultStatus={9000};memo={};result={partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測试"&body="測试測试"&total_fee="0.01"¬ify_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="}
注意:
支付结果的提取。必须通过CompletionBlock获取,禁止开发人员私自解析支付结果返回的URL。获取值的Key相应resultStatus、memo与result(result中的值,开发人员能够自行解析);
为了保障已有商户的正常使用。返回參数ResultStatus首字母为大写。
在新的SDK中已经用统一的工具类实现了ResultStatus到resultStatus的转换。商户从CompletionBlock中获取resultStatus就可以。
③导入代码:
步骤1:启动IDE(如Xcode)。把iOS包中的压缩文件里下面文件复制到项目目录下,并导入到项目project中。
AlipaySDK.bundle
AlipaySDK.framework
在Build Phases选项卡的Link Binary With Libraries中,添加下面依赖:
当中。须要注意的是:
假设是Xcode 7.0之后的版本号,须要加入libc++.tbd、libz.tbd;
假设是Xcode 7.0之前的版本号,须要加入libc++.dylib、libz.dylib(例如以下图)。
步骤2:在须要调用AlipaySDK的文件里,添加头文件引用。
#import <AlipaySDK/AlipaySDK.h>
步骤3:假设你的app基于9.0编译。那么为了适配iOS9.0中的App Transport Security(ATS)对http的限制。这里须要对支付宝的请求地址alipay.com、alipayobjects.com做例外,在app相应的info.list中加入例如以下配置(文中以XML格式描写叙述)。
<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>
说明:
假设商户配置了例如以下的配置:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
则上述的NSAppTransportSecurity能够不配置。
步骤4:配置请求信息。
Order *order = [[Order alloc] init];
order.partner = partner;
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.xxx.com"; //回调URL
order.service = @"mobile.securitypay.pay";
order.paymentType = @"1";
order.inputCharset = @"utf-8";
order.itBPay = @"30m";
//应用注冊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);
}];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
详细可參见Demo中演示样例文件
AliSDKDemo\APViewController.h
AliSDKDemo\APViewController.m
AliSDKDemo\Order.h
AliSDKDemo\Order.m
步骤5:配置支付宝client返回url处理方法。
(外部存在支付包钱包。支付宝钱包将处理结果通过url返回。)
如演示样例AliSDKDemo\APAppDelegate.m文件里,添加引用代码:
#import <AlipaySDK/AlipaySDK.h>
在@implementation AppDelegate中添加例如以下代码:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
//假设极简开发包不可用,会跳转支付宝钱包进行支付,须要将支付宝钱包的支付结果回传给开发包
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
//【因为在跳转支付宝client支付的过程中,商户app在后台非常可能被系统kill了,所以pay接口的callback就会失效,请商户对standbyCallback返回的回调结果进行处理,就是在这种方法里面处理跟callback一样的逻辑】
NSLog(@"result = %@",resultDic);
}];
}
if ([url.host isEqualToString:@"platformapi"]){//支付宝钱包快登授权返回authCode
[[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
//【因为在跳转支付宝client支付的过程中,商户app在后台非常可能被系统kill了。所以pay接口的callback就会失效。请商户对standbyCallback返回的回调结果进行处理,就是在这种方法里面处理跟callback一样的逻辑】
NSLog(@"result = %@",resultDic);
}];
}
return YES;
}
④针对demo的执行注意:
1、关于签名代码问题
AliSDKDemo\Util及下面全部文件
AliSDKDemo\openssl及下面全部文件
libcrypto.a
libssl.a
这些文件是为演示样例签名所在client本地使用。出于安全考虑。请商户尽量把私钥保存在服务端,在服务端进行签名验签。
2、假设遇到执行后报错。相似于下面提示信息:
Cannot find interface declaration for \'NSObject\', superclass of \'Base64\'
那么须要打开报错了的文件,添加头文件。
#import <Foundation/Foundation.h>
3、假设商户要在某个文件里使用支付宝的开发包类库。需添加引用头文件。
#import <AlipaySDK/AlipaySDK.h>
4、点击项目名称,点击“Build Settings”选项卡,在搜索框中,以关键字“search”搜索,对“Header Search Paths”添加头文件路径:$(SRCROOT)/项目名称。
假设头文件信息已添加,可不必再添加。
5、点击项目名称。点击“Build Phases”选项卡,在“Link Binary with Librarles”选项中。新增“AlipaySDK.framework”和“SystemConfiguration.framework”两个系统库文件。
假设商户项目中已有这两个库文件,可不必再添加。
6、点击项目名称。点击“Info”选项卡。在“URL Types”选项中。点击“+”。在“URL Schemes”中输入“alisdkdemo”。“alisdkdemo”来自于文件“APViewController.m”的NSString *appScheme = @“alisdkdemo”;。
注意:这里的URL Schemes中输入的alisdkdemo,为測试demo,实际商户的app中要填写独立的scheme。建议跟商户的app有一定的标示度,要做到和其他的商户app不反复。否则可能会导致支付宝返回的结果无法正确跳回商户app。
⑤基本配置信息:
打开“APViewController.m”文件,对下面三个參数进行编辑。
NSString *partner = @"";
NSString *seller = @"";
NSString *privateKey = @"";
IOS基本信息配置表:
參数 | 含义 |
---|---|
partner | 合作身份者ID,以2088开头由16位纯数字组成的字符串。请參考查看PID。 |
seller | 支付宝收款账号。手机号码或邮箱格式。 |
private_key | 商户方的私钥。pkcs8格式。请參考RSA私钥及公钥生成。 |
注意:这些參数配置是为client签名功能服务的。仅作为演示样例使用。
商户在接入支付宝产品时,请把这些信息通过商户项目自己的服务端传递。
⑥代码演示样例执行逻辑:
步骤1:调用order.m里的函数description将商品信息拼接成字符串作为待签名字符串,如:
"partner=\"2088101568353491\"&seller_id=\"2088101568353491\"&out_trade_no=\"YR2VGG3G1I31XDZ\"&subject=\"1\"&body=\"我是測试数据\"&total_fee=\"0.02\"¬ify_url=\"http://www.xxx.com\"&service=\"mobile.securitypay.pay\"&payment_type=\"1\"&_input_charset=\"utf-8\"&it_b_pay=\"30m\""
步骤2:使用类CreateRSADataSigner,调用signString签名函数做签名,如:
"GsSZgPloF1vn52XAItRAldwQAbzIgkDyByCxMfTZG%2FMapRoyrNIJo4U1LUGjHp6gdBZ7U8jA1kljLPqkeGv8MZigd3kH25V0UK3Jc3C94Ngxm5S%2Fz5QsNr6wnqNY9sx%2Bw6DqNdEQnnks7PKvvU0zgsynip50lAhJmflmfHvp%2Bgk%3D"
步骤3:把签名结果赋值给參数sign,并把sign加入之前的待签名数组中,此时得到的便是要请求给支付宝的全部数据。
"partner=\"2088101568353491\"&seller_id=\"2088101568353491\"&out_trade_no=\"YR2VGG3G1I31XDZ\"&subject=\"1\"&body=\"我是測试数据\"&total_fee=\"0.02\"¬ify_url=\"http://www.xxx.com\"&service=\"mobile.securitypay.pay\"&payment_type=\"1\"&_input_charset=\"utf-8\"&it_b_pay=\"30m\"&sign=\"GsSZgPloF1vn52XAItRAldwQAbzIgkDyByCxMfTZG%2FMapRoyrNIJo4U1LUGjHp6gdBZ7U8jA1kljLPqkeGv8MZigd3kH25V0UK3Jc3C94Ngxm5S%2Fz5QsNr6wnqNY9sx%2Bw6DqNdEQnnks7PKvvU0zgsynip50lAhJmflmfHvp%2Bgk%3D\"&sign_type=\"RSA\""
步骤4:调用(AlipaySDK *)defaultService类下面的支付接口函数。唤起支付宝支付页面。
(void)payOrder:(NSString *)orderStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock
appScheme为app在info.plist注冊的scheme。
支付宝支付页面:
后面的动作全由买家在支付宝收银台中操作完毕。假设设备中有支付宝client,会优先调用支付宝client进行支付,支付完毕后会又一次唤起商户app。
步骤5:当这笔交易被买家支付成功后支付宝收银台上显示该笔交易成功,并提示用户“返回”。此时在APAppDelegate.m的 - (BOOL)application:(UIApplication )application openURL:(NSURL )url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation 中调用获取返回数据的代码:
[[AlipaySDK defaultService]
processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"result = %@",resultDic);//返回的支付结果
//【因为在跳转支付宝client支付的过程中,商户app在后台非常可能被系统kill了。所以pay接口的callback就会失效,请商户对standbyCallback返回的回调结果进行处理,就是在这种方法里面处理跟callback一样的逻辑】
}];
拿到返回数据:
点取消后返回
"alisdkdemo://safepay/?
%7B%22memo%22:%7B%22result%22:%22%22,%22memo%22:%22%E7%94%A8%E6%88%B7%E4%B8%AD%E9%80%94%E5%8F%96%E6%B6%88%22,%22ResultStatus%22:%226001%22%7D,%22requestType%22:%22safepay%22%7D"
对其做URLDecode
"alisdkdemo://safepay/?{"memo":{"result":"","memo":"用户中途取消","ResultStatus":"6001"},"requestType":"safepay"}"
点确认后返回
"alisdkdemo://safepay/?
%7B%22memo%22:%7B%22result%22:%22partner=%5C%222088101568353491%5C%22&seller_id=%5C%222088101568353491%5C%22&out_trade_no=%5C%22QU6ZOD85K4HVQFN%5C%22&subject=%5C%221%5C%22&body=%5C%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%5C%22&total_fee=%5C%220.02%5C%22¬ify_url=%5C%22http:%5C/%5C/www.xxx.com%5C%22&service=%5C%22mobile.securitypay.pay%5C%22&payment_type=%5C%221%5C%22&_input_charset=%5C%22utf-8%5C%22&it_b_pay=%5C%2230m%5C%22&success=%5C%22true%5C%22&sign_type=%5C%22RSA%5C%22&sign=%5C%22pg16DPA%5C/cIRg1iUFCl8lYZG54de+kfw+vCj32hGWye97isZ1A4bW6RNaDXHhZXVaI5Vk2YDxhNUl85EHRd+EL7%5C/+ogQTnsaEHl+D13PuZExIXRKGBnkYqaNV6kH6hDygnf5IOtoojHWLQyem7oRBVzB0vlF%5C/+YGFpzFHZyTVpM8=%5C%22%22,%22memo%22:%22%22,%22ResultStatus%22:%229000%22%7D,%22requestType%22:%22safepay%22%7D"
对其做URLDecode
"alisdkdemo://safepay/?{"memo":{"result":"partner=\"2088101568353491\"&seller_id=\"2088101568353491\"&out_trade_no=\"QU6ZOD85K4HVQFN\"&subject=\"1\"&body=\"我是測试数据\"&total_fee=\"0.02\"¬ify_url=\"http:\/\/www.xxx.com\"&service=\"mobile.securitypay.pay\"&payment_type=\"1\"&_input_charset=\"utf-8\"&it_b_pay=\"30m\"&success=\"true\"&sign_type=\"RSA\"&sign=\"pg16DPA\/cIRg1iUFCl8lYZG54de+kfw+vCj32hGWye97isZ1A4bW6RNaDXHhZXVaI5Vk2YDxhNUl85EHRd+EL7\/+ogQTnsaEHl+D13PuZExIXRKGBnkYqaNV6kH6hDygnf5IOtoojHWLQyem7oRBVzB0vlF\/+YGFpzFHZyTVpM8=\"","memo":"","ResultStatus":"9000"},"requestType":"safepay"}"
之后,对这些数据做处理。
注意:
因为在跳转支付宝client支付的过程中,商户app在后台非常可能被系统kill了。所以pay接口的callback就会失效。请商户对standbyCallback返回的回调结果进行处理;
同步返回数据时,建议通过服务端的验签功能代码做验签处理,之后再对返回的数据做业务逻辑处理;
须以server异步通知的结果数据为准,并对其做业务逻辑处理;
SDK付款有两种模式:假设外部存在支付宝钱包。则直接跳转到支付宝钱包付款;不存在的场景下。在SDK内部进行H5支付。測试同学须要关注这两类測试场景。
至此文档结束,因为我本人对于IOS开发并不精通,所以以上绝大部分借鉴支付宝相关文档,但都是我觉得比較重要的地方,仅供參考。