美文网首页iOS支付分享
iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务

iOS 接入支付宝SDK封装的工具类HHAliPaySDK(服务

作者: Hai1丶HydrA | 来源:发表于2017-06-14 22:43 被阅读646次

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


    看一下支付宝给的流程图

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


    {7D03662F-CC3F-AE65-ECAB-8DA5F7FF92F9}.png

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

    看下面官方给的提示:

    {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)


    2EA80578-7343-433E-8803-73E4E826BE11.png

    添加依赖库

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


    {6F9683DA-F3FC-EB1C-9F34-C2D3EA014542}.png

    设置头文件路径

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

    添加URL Schemes白名单

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

    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 <Foundation/Foundation.h>
    
    @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 <AlipaySDK/AlipaySDK.h>
    @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<NSString*, id> *)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<String, String> 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(服务

        本文链接:https://www.haomeiwen.com/subject/tsheqxtx.html