关于iOS支付的小结

项目中碰到过的支付方式一直以来没有系统的梳理过,今天就开发过程中的问题来做一次详细的总结,为今后的使用提供参考。

目前为止较为广泛使用的支付方式:

三方支付:

  • 微信支付
  • 支付宝支付
  • 银行支付
  • 内购(简称 IAP)

  • 感想: 所有三方支付最好写一个单例来封装,便于维护

微信支付

关于微信支付后的回调处理

  • 问题触发场景:当我们使用微信支付成功后,没有在微信App内,点击完成按钮,跳转到我们自己的App,而是点击了系统提供的左上角快捷键返回到了我们自己的App。
  • 场景导致的bug:由于没有点击完成按钮,微信SDK无法调用其回调接口:
-(void)onResp:(BaseResp*)resp{
              if ([resp isKindOfClass:[PayResp class]]){
                  PayResp*response=(PayResp*)resp;
                  switch(response.errCode){
                      case WXSuccess:
                                //服务器端查询支付通知或查询API返回的结果再提示成功
                                NSlog(@"支付成功");
                        break;
                        default:
                        NSlog(@"支付失败,retcode=%d",resp.errCode);
                        break;
                  }
                    }
                }

如此一来,我们就无法完整的处理微信支付流程了。

  • 解决方案:app每次从后台进入时会调用applicationWillEnterForeground(注:应用将要进入前台)方法,我们可以在这里发送一个微信支付的通知,并在相应的界面获取该通知,在通知方法里,向服务端发送微信支付结果请求,获取支付结果。
#pragma mark - AppDelegate中发送通知

- (void)applicationWillEnterForeground:(UIApplication *)application 
{
    DTLog(@"applicationWillEnterForeground");

    [[NSNotificationCenter defaultCenter] postNotificationName:@"wxPayBack" object:nil];
}
#pragma mark - 相关接收通知的controller
// 考虑到添加时机的问题,最好是在获取订单信息的回调中添加该通知,确保该通知回调一定会被执行
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(wxPayBack) name:@"wxPayBack" object:nil];
- (void)wxPayBack
{
//判断订单号是否存在,以及当前回调是否为微信支付(若有其它支付,也会调起该通知),然后通过订单号向服务端发起支付结果请求
    if (订单号.length > 0 && _isWxPay)
    {
        [self judgeWxPayStationWithWxPayOrder:订单号];
    }
}
#pragma mark - 对请求结果的处理
- (void)judgeWxPayStationWithWxPayOrder:(NSString *)wxOrder
{
    NSDictionary *dic = 请求体参数;
    [[NetWorkManager shareManager] postDataSourceFromURL:请求订单信息的接口 Dic:dic Success:^(NSDictionary *success) {
        
        // 参考微信SDK自定义PayResp对象
        PayResp *resp = [[PayResp alloc] init];
        resp.errCode = 0;
        resp.errStr = nil;
        resp.type = 0;
        NSString *state = success[支付结果对应的key];
        if (![state isEqualToString:支付成功对应的值])
        {
            resp.errCode = 0;
        }
        [self wxPaySResp:resp];

    } AndFail:^(NSError *fail) {
        
    }];
}

- (void)wxPaySResp:(PayResp *)resp
{
    NSString *strTitle = nil;
    if ([resp isKindOfClass:[PayResp class]]) {
        
        switch (resp.errCode) {
            case WXSuccess:
            {
                strTitle = @"支付成功!";
                break;
            }
            case WXErrCodeUserCancel: //用户点击取消并返回
                strTitle = @"您未成功支付";
                break;
            default:
                break;
        }
    }
    if (strTitle != nil)
    {
        弹出相应的提示
    }
}

  • 微信支付流程(客户端具体实现)
  • 下载对应iOS平台的Demo,添加依赖库,修改plist
  • 真机测试时,需要在build setting里修改bitcode为NO
  • 设置project——>info——>URL types——>新增微信URLSchemes
  • 商户APP工程中引入微信lib库和头文件,调用API前,需要先向微信注册APPID(在APPDelete中注册即可)

-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[WXApi registerApp: @"自己的appid替换" withDescription: @"自己定义一个描述"];
}

  • 向服务端发起请求,获取订单号——>通过商品价格等参数拼接请求体发起订单号请求
    • 在订单号返回成功的回调中添加微信客户端回调通知
    • 在点击微信支付后,拼接请求体(请求体中包含订单号)发起支付请求
    • 支付回调成功处,设置PayReq对象,调起微信客户端(最好增加客户端是否安装的判断)
  • 微信客户端调起自己的app,此时获取到微信支付处理的通知,接下来处理该通知(处理细节请在上面查看)

名称 描述 解决方案
0 成功 展示成功页面
-1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
-2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。
支付宝支付
  • 支付宝支付,分为网页快捷支付、支付宝客户端支付两种情况
  • 支付宝支付流程(客户端具体实现)
  • 下载对应iOS平台的Demo,添加依赖库

  • 设置project——>info——>URL types——>新增支付宝URLSchemes

  • 向服务端发起请求,获取订单号——>通过商品价格等参数拼接请求体发起订单号请求

    • 在点击支付宝支付后,拼接请求体order(请求体中包含订单号、服务端提供的notifyURL)发起支付宝签名请求
    • 获取签名请求成功回调中,处理订单字符串、回调URLScheme(保证支付处理完成回调到自己的app),使用[AlipaySDK defaultService]调起支付宝处理支付
    • 支付处理完成,APPDelegate中,处理一次回调,然后在调起支付宝的controller中进行第二次回调处理
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary*)options
{
    if ([[url absoluteString] hasPrefix:URLScheme])
    {
    // 支付宝客户端二次回调条件
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
          
        }];
        
        [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) {
            NSLog(@"result = %@",resultDic);
            // 解析 auth code
            NSString *result = resultDic[@"result"];
            NSString *authCode = nil;
            if (result.length>0) {
                NSArray *resultArr = [result componentsSeparatedByString:@"&"];
                for (NSString *subResult in resultArr) {
                    if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) {
                        authCode = [subResult substringFromIndex:10];
                        break;
                    }
                }
            }
            NSLog(@"授权结果 authCode = %@", authCode?:@"");
        }];
        
    }
}


银联支付

银联移动支付平台地址:https://open.unionpay.com/ajweb/product/detail?id=3 下载SDK

  1. 导入SDK
    SDK包括两个文件:UPPaymentControl.h文件和libPaymentControl.a,将SDK目录添加到工程.

  2. 添加依赖
    使用UPPaymentControl需要添加CFNetwork.framework、SystemConfiguration.framework 、libz、libPaymentControl.a到工程中,

  3. 修改配置
    3.1 在工程info.plist设置中添加一个URL Types回调协议(在UPPayDemo工程中使用“UPPayDemo”作为协议),用于在支付完成后返回商户客户端。
    3.2 在Xcode7.0之后的版本中进行http请求时,需要在工程对应的plist文件中添加
    NSAppTransportSecurity Dictionary
    并同时设置里面
    NSAllowsArbitraryLoads 属性值为 YES.
    3.3 添加协议白名单
    在Xcode7.0之后的版本中进行开发,需要在工程对应的plist文件中,添加LSApplicationQueriesSchemes Array并加入uppaysdk、uppaywallet、uppayx1、uppayx2、uppayx3五个item
    或者直接添加如下代码到plist文件中:

<key>LSApplicationQueriesSchemes</key>
     <array>
        <string>uppaysdk</string>
        <string>uppaywallet</string>
        <string>uppayx1</string>
        <string>uppayx2</string>
        <string>uppayx3</string>
     </array>

3.4 修改编译选项
选择工程targets——>build settings ->Linking->other linker flags
如果该设置和其他第三方库冲突,或银联客户端莫名失败,则可尝试去掉-ObjC,改为-force_load+空格+控件路径,如:-force_load $(PROJECT_DIR)/xxxx/ libPaymentControl.a
3.5 凡是引入银联头文件UPPaymentControl.h,需要将源文件后缀.m改为.mm

  1. 接口说明
    4.1 支付接口


    支付接口.png

    4.2 回调接口


    返回接口.png
内购
  • 内购需要在开发者账号发布app界面,添加内购物品
  • 完善银行卡信息
  • 添加测试人员账号
  • 在app中添加内购代码

内购实现流程

  1. 客户端向自己公司服务端请求productIds(可能是多个商品)
  2. 使用这些produceId创建SKProductsRequest对象,调用start方法,设置该对象代理,在代理方法中获取可以销售的product(代理方法中获取创建UI所需要的数据)
  3. 当用户点击某个商品后,我们客户端获取被点击商品的SKProduct对象,创建SKPayment票据对象(使用SKProduct对象创建),添加SKPayment对象的监听者,将票据添加到购买队列,在监听商品更新信息回调方法中获取商品购买状态
  4. 如果商品返回状态为:成功 | 失败 | 恢复,那么将该票据从队列移除,成功购买,应返回给本公司服务器商品购买成功信息,用于下次更新商品状态
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,361评论 25 707
  • 支付宝简介文档 (适用于ydm-java接口与后台,如有误入,但愿也能给您带来帮助) 此文档写于2017年3月,只...
    隔壁付叔叔阅读 17,043评论 3 19
  • 你大概像是燃烧的烛火 我却是怕死的蛾 不敢撩拨 无法上演飞蛾扑火 我是怕冷的蛾 惧怕火但从未离去过 是生存的本能让...
    伍丁零阅读 309评论 0 1
  • 日子一天天的过 很是平常 洗澡,打扮,吃饭 上班,下班,睡觉 很喜欢这种平静安详 生活没有一丝波澜 才能品出时间的...
    李木只阅读 309评论 2 0
  • 赤壁之战是《三国演义》中大家最为熟悉的一场战役,也是疑云最多的一场战役,它为刘备、孙权、曹操三分天下奠定了...
    百合花杨贻宸阅读 1,879评论 0 0