• UID10
  • 登录2016-10-31
  • 粉丝38
  • 关注4
  • 发帖386
  • 主页
  • 金币2541枚
社区居民
忠实会员
原创写手
bill 发布于2015-10-09 18:39
3/2412

基于iOS支付宝支付设计和开发方案

楼层直达
概述
在“支付宝支付设计和开发方案一文中我们讨论了支付宝支付在Android客户端以及服务器端的解决方案,本文讲解iOS客户端的支付实现方案。
从支付宝SDK附带的文档中,商户客户端与支付宝移动支付 SDK 交互模式图如下:

图片:Screen Shot 2015-10-09 at 8.46.16 PM.png



从中可以看到客户端的主要工作:构造订单数据并签名,发动请求支付数据,对同步返回的数据进行处理。下面是某个项目中支付相关的代码逻辑,本文不讲解具体背景,而且透过这个具体案例来讲解支付宝支付流程。

构造订单数据
parter, seller, private key这三项是申请支付宝支付成功后获得的支付信息,这个信息为了安全必须存放在服务器端,下面的代码首先发送数据请求,获得这些信息后,调用ShareUtils类方法来生成订单数据。
[DataRequest checkAlipayConfigFinished:^(id model, NSError *error) {
    if ([[model objectForKey:@"code"] integerValue] == 200) {
        NSDictionary *dic = [model objectForKey:@"result"];
        NSDictionary *alipay = @{ALIPAY_PARTER:[dic objectForKey:ALIPAY_PARTER],
                                 ALIPAY_SELLER:[dic objectForKey:ALIPAY_SELLER],
                                 ALIPAY_PRIVATEKEY:[dic objectForKey:ALIPAY_PRIVATEKEY]
                                 };
                  
          
    NSString *orderString = [ShareUtils freeOfChargeWithalipay:alipay
                                              WithproductName:_orderListModel.barCouponName
                                       WithproductDescription:_orderListModel.barCouponName
                                            WithproductAmount:self.priceLabel.text
                                              WithTradeNumber:_orderListModel.tradeNo];
    [self doActionUseAlipaySDKOrderString:orderString];
    }
} ];<font size="2"></font>

 ShareUtils相应的类方法主要工作:创建Order对象,并填充数据。最后使用支付宝SDK提供的数据签名类进行签名。
+ (NSString *)freeOfChargeWithalipay:(NSDictionary *)alipayConfig
                     WithproductName:(NSString *)productName
              WithproductDescription:(NSString *)productDescription
                   WithproductAmount:(NSString *)amount
                     WithTradeNumber:(NSString *)tradeNumber
{
             
    Order *order = [[Order alloc] init];
    order.productName = productName;
    order.productDescription = productDescription;
    order.amount = amount;
    order.tradeNO = tradeNumber;
             
    order.partner = [GTMBase64 decodeBase64String:[alipayConfig objectForKey:ALIPAY_PARTER]];
    order.seller = [GTMBase64 decodeBase64String:[alipayConfig objectForKey:ALIPAY_SELLER]];
    NSString *privateKey = [GTMBase64 decodeBase64String:[alipayConfig objectForKey:ALIPAY_PRIVATEKEY]];
             
    if ([order.partner length] == 0 || [order.seller length] == 0) {
                 
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"
                                                        message:@"缺少partner或者seller。"
                                                       delegate:self
                                              cancelButtonTitle:@"确定"
                                              otherButtonTitles:nil];
        [alert show];
        return nil;
    }
             
             
             
    order.notifyURL = [NSString stringWithFormat:@"%@business/payOver.do",WebSite_Http];
    order.paymentType = @"1";
             
    order.service = @"mobile.securitypay.pay";
    order.inputCharset = @"utf-8";
    order.itBPay = @"30m";
    order.showUrl = @"m.alipay.com";
             
    //将商品信息拼接成字符串
    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"];
        NSLog(@"--------%@----------",orderString);
    }
    return orderString;
}

支付请求
调用AlipaySDK的defaultService获得服务后,调用payOrder:fromScheme:callback:方法进行支付请求:
//使用alipaySDK进行支付操作
- (void)doActionUseAlipaySDKOrderString:(NSString *)orderString
{
    [[AlipaySDK defaultService] payOrder:orderString
                              fromScheme:ALIPAY_APPSCHEME
                                callback:^(NSDictionary *resultDic) {
           
                                    NSLog(@"reslut = %@",resultDic);
                                    NSString *resultStatus = [resultDic objectForKey:@"resultStatus"];
                                    if ([resultStatus isEqual:@"9000"]) {
                                        NSArray *viewCtrls = self.navigationController.viewControllers;
                                        for (UIViewController *viewCtrl in viewCtrls) {
                                            if ([viewCtrl isKindOfClass:[MyOrderListViewController class]]) {
                                                [self.navigationController popToViewController:viewCtrl animated:YES];
                                            } else if ([viewCtrl isKindOfClass:[CouponDetailViewController class]]){
                                                [self.navigationController popToRootViewControllerAnimated:NO];
                                                BaseTabBarViewController *tabBarCtrl = (BaseTabBarViewController *)[UIApplication sharedApplication].keyWindow.rootViewController;
                                                tabBarCtrl.selectedIndex = 3;
                                                           
                                                BaseNavViewController *myAccount = (BaseNavViewController *)[tabBarCtrl.viewControllers lastObject];
                                                MyOrderListViewController *orderCtrl = [[MyOrderListViewController alloc] init];
                                                orderCtrl.hidesBottomBarWhenPushed = YES;
                                                [myAccount pushViewController:orderCtrl animated:YES];
                                            }
                                        }
                                    } else {
                                        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"交易失败" delegate:self cancelButtonTitle:@"确定" otherButtonTitles: nil];
                                                   
                                        [alert show];
                                    }
                                               
                                }];
}
返回数据处理
在支付宝请求返回的数据处理block中,先判断result status是否是9000(9000代表成功)。
之后切换控制器MyOrderListViewController,该控制器实现TableView相关的delegate方法
@interface MyOrderListViewController ()<UITableViewDataSource , UITableViewDelegate>
{
    int _notpayingNum;//未付款
    int _notSpending;// 未消费
    int _didSpending;//已消费
    BOOL _close[3];
}
加载数据的方法loadData,读取该user下的订单数据,存放在OrderListModel中:
- (void)loadData
{
    [self.spengdingListArray removeAllObjects];
    [self.noSpendingListArray removeAllObjects];
    [self.willPayOrderListArray removeAllObjects];
    [DataRequest getUserId:[ShareUtils shareUtils].user.pid finished:^(id model, NSError *error) {
        if ([[model objectForKey:@"code"] integerValue] == 200) {
            NSArray *modelArray = [model objectForKey:@"result"];
            for (NSDictionary *dic in modelArray) {
                if ([[dic objectForKey:@"status"] isEqualToString:@"0"]||[[dic objectForKey:@"statusCode"] isEqualToString:@"6000"]) {
                    OrderListModel *model = [[OrderListModel alloc]initWithDictionary:dic];
                    [self.willPayOrderListArray addObject:model];
                }else if ([[dic objectForKey:@"status"] isEqualToString:@"10"]) {
                    OrderListModel *model = [[OrderListModel alloc]initWithDictionary:dic];
                    [self.noSpendingListArray addObject:model];
                }else if ([[dic objectForKey:@"status"] isEqualToString:@"7000"]) {
                    OrderListModel *model = [[OrderListModel alloc]initWithDictionary:dic];
                    [self.spengdingListArray addObject:model];
                }
                [self.tableView reloadData];
            }
        }
    }];
}
model定义:
@interface OrderListModel : BaseModel
      
//amount = 17;
//barCoupon = 0;
//barCouponImg = "";
//id = 1;
//isRefund = "";
//orderNo = "";
//payNo = "";
//productDescription = "";
//status = 0;
//tradeNo = "3-6-1-371343";
//userId = 27;
      
@property (nonatomic, copy) NSString *amount;
@property (nonatomic, copy) NSString *barCoupon;
@property (nonatomic, copy) NSString *img;
@property (nonatomic, copy) NSString *barCouponName;
@property (nonatomic, copy) NSString *pid;
@property (nonatomic, copy) NSString *barName;
@property (nonatomic, copy) NSString *count;
@property (nonatomic, copy) NSString *isRefund;
@property (nonatomic, copy) NSString *orderNo;
@property (nonatomic, copy) NSString *payNo;
@property (nonatomic, copy) NSString *status;
@property (nonatomic, copy) NSString *tradeNo;
@property (nonatomic, copy) NSString *userId;
@property (nonatomic, copy) NSString *createTime;
      
@end



总结
本文通过分析某个项目中支付宝支付的客户端处理流程,讲解了主要的开发步骤。希望对支付类的应用开发起到一个帮助。

0人打赏
  • UID362
  • 登录2015-11-12
  • 粉丝1
  • 关注1
  • 发帖6
  • 主页
  • 金币1枚
caspar_520 发布于2015-10-22 18:13
沙发F
能发个相关项目吗?小的工程即可
  • UID362
  • 登录2015-11-12
  • 粉丝1
  • 关注1
  • 发帖6
  • 主页
  • 金币1枚
caspar_520 发布于2015-10-22 18:14
板凳F
求啊!!!
  • UID362
  • 登录2015-11-12
  • 粉丝1
  • 关注1
  • 发帖6
  • 主页
  • 金币1枚
caspar_520 发布于2015-10-22 18:28
地板F
楼主能发下本文的工程不?
您需要登录后才可以回帖
发表回复
极贡献
技术问答
专题荟萃
程序人生
视觉设计
Android开发
iOS开发
编程语言
前端开发
后端开发
服务器架构
软件测试
运维方案
创业路上



最热文章墙

  • 64975/360   【精品推荐】200多种Android动画效果的强悍框架,太全了,不看这个,再有动画的问题,不理你了^@^

  • 36268/189   情人节福利,程序员表白的正确姿势:改几行代码就变成自己的表白了

  • 33714/143   省时省力的Android组件群来了,非常棒的原型参考

  • 32717/243   【精品推荐】Android版产品级的音乐播放器源码,功能太强大了,最好的产品原型有木有?

  • 31270/0   Python爬虫:常用浏览器的useragent

  • 27120/2   超全!整理常用的iOS第三方资源

  • 26016/71   原创表白APP,以程序员的姿势备战新年后的7夕,持续完善中!

  • 24762/139   2016抢红包软件及源码

  • 20824/30   麻省理工的一帮疯子,真的实现了随意操控万物!(绝对黑科技)

  • 20553/25   Android工程师面试题大全

  • 20129/27   2016程序员跳槽全攻略

  • 19957/9   GitHub上排名前50的iOS项目:总有一款你用得着

  • 19264/20   码魂:程序员的牛B漫画

  • 18860/153   Android版类似UC浏览器:非常赞,产品级的源码

  • 17405/3   吐槽那些程序员的搞笑牛逼注释

  • 17377/10   2016年最全的Android面试考题+答案 精编版

  • 16351/1   iOS 动画总结

  • 16238/42   一个绚丽的loading动效分析与实现!

  • 15952/84   Android小而全的博客源码:非常适合全面掌握开发技巧

  • 15944/73   【持续更新中】Android福利贴(二):资料源码大放送

  • 15376/44   惊艳的App引导页:背景图片切换加各个页面动画效果

  • 15161/10   女程序员的梦,众网友的神回复

  • 15075/23   个人收集的Android 各类功能源代码

  • 14937/11   年会上现场review代码是怎么样的体验!

  • 14871/5   新一代Android渠道打包工具:1000个渠道包只需要5秒

  • 14213/23   珍藏多年的素材,灵感搜寻网站

  • 14136/53   基于瀑布流的美女图片浏览App,有注释的源代码

  • 14060/77   仿京东商城客户端Android最新版,不错的原型和学习资料

  • 13818/17   用JavaScript 来开发iOS和Android 原生应用:React Native开源框架中文版来啦

  • 13526/94   Android带弹幕的视频播放器源码,来自大名鼎鼎的Bilibili弹幕网站

  • 13510/20   Android福利第三波【Android电子书】

  • 13319/15   基于Android支付宝支付设计和开发方案

  • 13145/18   65条最常用正则表达式,你要的都在这里了

  • 13086/72   【精品推荐】类似360安全卫士安Android源码:非常赞的产品原型

  • 12887/0   iOS中文版资源库,非常全

  • 12817/17   什么是真正的黑客:收获12200+Stars,人气远超微软开源VS

  • 12355/11   有木有这样一张酷图帮你集齐所有git命令超实用

  • 12248/7   一张图搞定iOS学习路线,非常全面

  • 12214/7   用程序员的姿势抢过年的火车票

  • 11747/10   成为Java顶尖程序员 ,看这11本书就够了

  • 11516/44   在线音乐播放器完整版(商用级的源码):非常赞,可听免费高品质专辑

  • 11513/18   一张图搞定Android学习路线,非常全面

  • 11437/10   微信支付终于成功了(安卓,iOS),在此分享

  • 11310/3   基于Node.js的强大爬虫,能直接发布抓取的文章哦

  • 11218/0   GitHub iOS 库和框架Top100 

  • 11055/29   【持续更新中】Android福利贴(一):资料源码

  • 10719/61   【技巧一】搭配Android Studio,如何实现App远程真机debug?

  • 10521/4   46 个非常有用的 PHP 代码片段

  • 10398/3   即时通信第三方库

  • 10079/8   流媒体视频直播方案

  • 9961/9   B站建开源工作组:APP想支持炫酷弹幕的看过来

  • 9930/9   烧了5亿美金,这家神秘的公司即将颠覆人类未来!

  • 9825/18   八个最优秀的Android Studio插件

  • 9654/2   【精品推荐】高质量PHP代码的50个实用技巧:非常值得收藏

  • 9585/10   中国黑客的隐秘江湖:攻守对立,顶尖高手月入千万美元

  • 9078/6   开箱即用!Android四款系统架构工具

  • 8914/10   十大技巧快速提升Android应用开发性能

  • 8898/3   一张图看清Linux 内核运行原理

  • 8866/3   10款GitHub上最火爆的国产开源项目——可以媲美西半球

  • 8581/1   Android性能优化视频,文档以及工具

  • 返回顶部