iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签)

开篇吐槽,文档看不懂,文档看不懂,文档看不懂.重要的事说三遍.
对于没集成过支付宝SDK的人来说,官方文档看完也是一脸懵逼,在网上搜完别人写的什么文档流程,看完也是一脸懵逼.
官方demo运行不了,还有各种什么order类生成签名,返回结果验签巴拉巴拉,反正说的我心累.


看一下支付宝给的流程图

图中的“商户客户端”其实就是我们的iOS客户端需要做的事情:
1.用后台给的签名后订单信息调用支付宝支付接口
2.处理支付宝返回的支付结果
完了,这就完事了,很简单的事情,只需要这两步,官方文档给的那么乱七八糟的复杂东西,什么order类啥的,都是把后台做的事情,放在了客户端来做,所以才那么复杂.


iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签)_第1张图片
{7D03662F-CC3F-AE65-ECAB-8DA5F7FF92F9}.png

那么为什么官方demo中能放在客户端做的事情(签名,验签)要给后台来做.

看下面官方给的提示:

iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签)_第2张图片
{ABDC1148-DE4D-8D69-61BD-E3B6741D5818}.png

第一条:私钥要保存在服务端,那么决定了调用支付宝接口需要的签名后的订单信息(也就是参数payOrder)需要后台来生成,传给我们.
第二条:到底付款成没成功,需要依赖服务端收到的异步通知结果来进行判断,我们客户端这边收到成功的提示也没用,必须后台告诉我们,他们也成功了,才算成功
第三条:说到了难住大多数人的验签,官方建议验签规则参考 异步通知验签,而异步通知验签,是在服务端来完成的,官方在服务端的SDK中提供了一个工具类用来验签,所以我们也是在服务端完成的.


了解以上就可以集成支付宝SDK了

这里是官方支付宝SDK集成流程
这里是创建应用获取APPID和配置秘钥的方法

设置URL Scheme(要记住这个标识,调用支付宝方法时会用到这个参数)

修改 info.plist 文件 URL types 项中后面的URL Schemes内容,官方建议跟商户的app有一定的标示度,要做到和其他的商户app不重复,否则可能会导致支付宝返回的结果无法正确跳回商户app。(比如你们项目名称+AliPay,我这里设置了支付宝,qq,微信,微博,只用到支付宝的话,就添加支付宝的就ok)


iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签)_第3张图片
2EA80578-7343-433E-8803-73E4E826BE11.png

添加依赖库

把下载的SDK中AlipaySDK.bundle和AlipaySDK.framework拖入工程,然后按官方给的图添加依赖库.官方文档看到这张图这里就够了,其余以下的不用管,都是教你demo怎么运行,签名和验签也没我们客户端的事,看他demo干嘛.


iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签)_第4张图片
{6F9683DA-F3FC-EB1C-9F34-C2D3EA014542}.png

设置头文件路径

点击“Build Settings”选项卡,在搜索框中,以关键字“search”搜索,对“Header Search Paths”增加头文件路径:$(SRCROOT)/项目名称。如果头文件信息已增加,可不必再增加.

添加URL Schemes白名单

在“Info.plist”中增加一个LSApplicationQueriesSchemes值,设置为array, 添加支付宝需要的item:
alipay
也就是图中的最后一项,其他的都是微信微博和QQ的.

iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签)_第5张图片
4ECDABF8-640E-4CF9-BBB8-C93037F155D9.png

设置https访问

在“Info.plist”中增加一个App Transport Security Settings值, 其中有一个Allow Arbitrary Loads对应的值要设置为YES


39DD2532-0055-4AC0-AC11-920D6A18E179.png

然后就就可以愉快的写代码了

创建了一个继承于NSObject的 HHAliPaySDK工具类,我在其中封装了一下向后台请求签名后的订单信息(也就是payOrder)的方法和处理回调结果用到的方法.

ps:这个类中有网络请求,HHttpManager是我自己对AFNetworking3.0的二次封装,感兴趣的可以看一看,不感兴趣的同学可以用AFN或者自己的网络框架.

.h文件

#import 

@interface HHAliPaySDK : NSObject

/**
 根据订单信息向后台申请prepayId以调用支付宝支付接口

 @param amount  金额
 @param orderId  订单信息(支付前请求后台给的没有签名过的订单号)
 */
+ (void)sendAliPayRequestWithAmount:(NSString *)amount
                            orderId:(NSString *)orderId;

/**
 openURL
 */
+(BOOL)handleOpenURL:(NSURL *)url;


@end

.m文件


#import "HHAliPaySDK.h"
#import 
@implementation HHAliPaySDK

//post请求后台,获取签名后的订单信息(也就是payOrder)
+ (void)sendAliPayRequestWithAmount:(NSString *)amount
                            orderId:(NSString *)orderId{
    NSDictionary *paramDict = @{
                                @"totalAmount":amount,
                                @"orderId":orderId,
                                };
//getAliPayOrder:后台提供的接口,用来请求签名后的订单信息(也就是payOrder)
    [HHttpManager POST:getAliPayOrder parameters:paramDict success:^(id responseObject) {
        NSNumber *state = responseObject[@"state"];
        if (state.integerValue == 0) {
            NSString *orderStr = responseObject[@"data"][0][@"AlipaySign"];
            [self sendPayRequstWithPayOrder:orderStr];
        }else{
            NSLog(@"请求失败--%@",responseObject[@"msg"]);
        }
    } failure:^(NSError * error) {
        NSLog(@"请求失败--%@",error);
 
    }];
}


//调用支付宝支付(无支付宝客户端时的结果回调也在此方法中)
+ (void)sendPayRequstWithPayOrder:(NSString *)payOrder{
    NSLog(@"%@", payOrder);
//AliPay_Scheme:设置URL Scheme时让你记住的参数.
    [[AlipaySDK defaultService] payOrder:payOrder fromScheme:AliPay_Scheme callback:^(NSDictionary *resultDic) {
        NSLog(@"%@", resultDic);
        [self handleAliPayCallBackResultWithDictionary:resultDic];
        
    }];
}

/**
 openURL(有支付宝客户端时返回的结果)
 */
+(BOOL)handleOpenURL:(NSURL *)url{
    if ([url.host isEqualToString:@"safepay"] ) {
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            [self handleAliPayCallBackResultWithDictionary:resultDic];
        }];
    }
    
    if ([url.host isEqualToString:@"platformapi"]){
        [[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
            [self handleAliPayCallBackResultWithDictionary:resultDic];
        }];
    }
    return YES;
}


+ (void)handleAliPayCallBackResultWithDictionary:(NSDictionary *)resultDic{
    if ([resultDic[@"resultStatus"] isEqual:@"9000"])
    {
        //客户端支付成功,然后向后台请求,看他是否验签成功,他也成功了,才证明支付成功,
    }
    
    if ([resultDic[@"resultStatus"] isEqual:@"4000"])
    {
        //支付失败
    }
    
    if ([resultDic[@"resultStatus"] isEqual:@"6001"])
    {
        //取消支付
    }
    
    if ([resultDic[@"resultStatus"] isEqual:@"6002"])
    {
        //网络连接失败
    }
    
}
@end

设置(个人喜欢类方法,调用方便,可自己修改)

在AppDelegate.m文件中
openURL方法中设置回调,支付宝不用初始化,是不是很开森0.0(这里一个是iOS9以下的系统调用的系统方法和一个是iOS9以上的系统调用的系统方法,都要设置)

#pragma mark - OpenURL回调结果
//iOS9-
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
    [self handleOpenURLWithURLHost:url];
    return YES;
}
//iOS9和9+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options{
    [self handleOpenURLWithURLHost:url];
    return YES;
}

- (void)handleOpenURLWithURLHost:(NSURL *)url{
 NSLog(@"url.host:%@", url.host);
    //支付宝
   if ([url.host isEqualToString:@"safepay"]||[url.host isEqualToString:@"platformapi"]) {
        [HHAliPaySDK handleOpenURL:url];
    }

}


调用

类方法直接调用封装好的接口就行,orderId是需要向后台请求的订单号(比如:D123457890)

/**
 根据订单信息向后台申请prepayId以调用支付宝支付接口

 @param amount  金额
 @param orderId  订单信息(支付前请求后台给的没有签名过的订单号)
 */
+ (void)sendAliPayRequestWithAmount:(NSString *)amount
                            orderId:(NSString *)orderId;

客户端题外话,关于RSA

(上面引入的是阮一峰写的一篇RSA算法原理,都是专业数学知识,看的我一愣一愣的,感谢大大的讲解)

签名和验签都交给后台的来做,对我们客户端来说,既安全有方便(真不是我们客户端不做,是官方建议的,上面我有说明过,涉及钱的问题,一切为了安全),客户端这边是不需要了解RSA加密解密的(没错,反正我是不会),但是需要后台了解,最简单来说,在生产订单时,需要使用私钥生成签名,在处理返回的支付结果时,需要使用公钥验证返回结果是否被篡改.验证通过才算支付成功.具体后台怎么验签,支付宝提供了方法,他给服务端的SDK提供了一个工具类用来验签,官方举的例子是Java

Map paramsMap = ... //将异步通知中收到的待验证所有参数都存放到map中
boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap, ALIPAY_PUBLIC_KEY, CHARSET) //调用SDK验证签名
if(signVerfied){
   // TODO 验签成功后
   //按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
}else{
    // TODO 验签失败则记录异常日志,并在response中返回failure.
}

你可能感兴趣的:(iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务端签名和验签))