支付宝快捷支付的主要步骤:
而iOS客户端需要做的是:
在调用支付宝支付接口前,还需要先生成一个订单,下载的支付宝文档中描述时,是将这步也放在客户端来做了,但也可以在服务器端生成这个订单(支付宝会在支付成功后通知服务器端,所以在服务器端生成订单的话,开发者掌握所有订单,而且也会更安全)。
支付宝支付的安全问题,需要在生成订单和处理支付结果的时候做一个安全性校验:即生成订单时对数据签名,收到支付结果时对数据进行签名验证,以检验数据是否被篡改过(支付宝目前只支持采用RSA加密方式做签名验证)。简单地说,就是在生产订单时,需要使用私钥生成签名值;在处理返回的支付结果时,需要使用公钥验证返回结果是否被篡改。
支付宝iOS SDK的官方下载地址:
https://b.alipay.com/order/productDetail.htm?productId=2013080604609654&tabId=4#ps-tabinfo-hash
压缩包里有两个相关文档:
《支付宝钱包支付接口开发包2.0标准版.pdf》
《支付宝钱包支付接口开发包2.0标准版接入与使用规则.pdf》
集成支付宝支付的主要流程:
将需要的文件,静态库等拖入工程中,这里有include,libs,Utilities,libcrypto.a,libssl.a文件(如果只需要发送订单和处理支付返回结果,只需要添加AlipaySDK.bundle和AlipaySDK.framework)。如下图:
设置Head Search Paths 和 Library Search Paths
即:targets->Build Setting ->Search Paths->Always Search User Paths和 Library Search Paths,注意:Always Search User Paths 和 Library Search Paths的路径一定要根据这个地址能找到对应的头文件。
- (void)payOrder:(NSString *)orderStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock;
如果手机内没安装支付宝的app,会直接展现支付宝web支付界面,通过callback返回支付结果;如果手机内安装了支付宝的app,会跳转到支付宝的app支付,然后通过openURL的回调返回支付结果。
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
if ([resultDic[@"resultStatus"] intValue] == 9000) {
//支付成功
}
else{
NSString *resultMes = resultDic[@"memo"];
resultMes = (resultMes.length<=0?@"支付失败":resultMes);
NSLog(@"%@",resultMes); }
}];
支付宝的SDK只给了一个处理返回结果的方法,没有提供处理openURL的方法:
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"result = %@",resultDic);
}]; }
SDK提供了处理openURL返回结果的方法:
- (void)processOrderWithPaymentResult:(NSURL *)resultUrl standbyCallback:(CompletionBlock)completionBlock;
两个回调block都统一定义为typedef void(^CompletionBlock)(NSDictionary *resultDic)。
resultStatus状态码对应的信息:
result是订单信息,以及签名验证信息。
代码过程展示:
- (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;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
[self parseURL:url application:application];
return YES;
}
//签名验证
- (void)parseURL:(NSURL *)url application:(UIApplication *)application {
AlixPay *alixpay = [AlixPay shared];
AlixPayResult *result = [alixpay handleOpenURL:url];
if (result) {
//是否支付成功
if (9000 == result.statusCode) {
/*
*用公钥验证签名
*/
id verifier = CreateRSADataVerifier([[NSBundle mainBundle] objectForInfoDictionaryKey:@"RSA public key"]);
if ([verifier verifyString:result.resultString withSign:result.signString]) {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示"
message:result.statusMessage
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alertView show];
}//验签错误
else {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"签名错误"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alertView show];
}
}
//如果支付失败,可以通过result.statusCode查询错误码
else {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示"
message:result.statusMessage
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alertView show];
}
}
}
- (void)payTreasurePay {
/*
*商户的唯一的parnter和seller。
*签约后,支付宝会为每个商户分配一个唯一的 parnter 和 seller。
*/
//如果partner和seller数据存于其他位置,请改写下面两行代码
NSString *partner = @"商户的parnter";
NSString *seller = @"商户的seller";
//partner和seller获取失败,提示
if ([partner length] == 0 || [seller length] == 0)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"缺少partner或者seller"
delegate:self
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alert show];
return;
}
/*
*生成订单信息及签名
*/
//将商品信息赋予AlixPayOrder的成员变量
AlixPayOrder *order = [[AlixPayOrder alloc] init];
order.partner = partner;
order.seller = seller;
order.tradeNO = @"订单ID"; //订单ID(由商家自行制定)
order.productName = @"商品标题"; //商品标题
order.productDescription = @"商品描述"; //商品描述
order.amount = [NSString stringWithFormat:@"%.2f",2.5]; //商品价格
order.notifyURL = @"http://www.xxx.com"; //回调URL
order.service = @"mobile.securitypay.pay";
order.paymentType = @"1";
order.inputCharset = @"utf-8";
order.itBPay = @"30m";
order.showUrl = @"m.alipay.com";
//应用注册scheme,在AlixPayDemo-Info.plist定义URL types,用于安全支付成功后重新唤起商户应用
NSString *appScheme = URLScheme;
//将商品信息拼接成字符串
NSString *orderSpec = [order description];
NSLog(@"orderSpec = %@",orderSpec);
//获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
NSString *privateKey = @"私钥";
id signer = CreateRSADataSigner(privateKey);
NSLog(@"prikey = %@",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) {
NSString *resultStatus=resultDic[@"resultStatus"];
if([resultStatus isEqualToString: @"9000"]){
[self alert:@"恭喜" msg:@"您已成功支付啦!"];
}else{
[self alert:@"提示" msg:@"支付失败,可在待付款订单中查看"];
}
[self.navigationController popToRootViewControllerAnimated:YES];
}];
/*
//获取安全支付单例并调用安全支付接口
AlixPay * alixpay = [AlixPay shared];
int ret = [alixpay pay:orderString applicationScheme:appScheme];
if(ret == 9000){
[self alert:@"恭喜" msg:@"您已成功支付啦!"];
}else{
[self alert:@"提示" msg:@"支付失败,可在待付款订单中查看"];
}
[self.navigationController popToRootViewControllerAnimated:YES];
if (ret == kSPErrorAlipayClientNotInstalled) {
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"您还没有安装支付宝快捷支付,请先安装。"
delegate:self
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alertView show];
}
else if (ret == kSPErrorSignError) {
NSLog(@"签名错误!");
}
*/
}
}
- (void)alert:(NSString *)title msg:(NSString *)msg
{
UIAlertView *alter = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alter show];
}
注:
RSA加密算法,除了可加解密外,还可用来作签名校验。简单的说,RSA会生成一个私钥和一个公钥,私钥应该独自保管,公钥可以分发出去。做签名验证时,可以用私钥对需要传输的数据做签名加密,生成一个签名值,之后分发数据,接收方通过公钥对签名值做校验,如果一致则认为数据无篡改。
支付宝demo(包括ios,android,wp)下载地址:
http://download.csdn.net/download/pearlhuzhu/5736965
解决在iOS9上调用支付宝不可回调的问题以及支付宝的嵌入流程:
http://blog.csdn.net/baby_hua/article/details/51004405