iOS 银联支付开发流程

支付流程图: 

1.sdk下载:https://open.unionpay.com/ajweb/help/file

在inc和libs里面分别有UPPaymentControl.h和libPaymentControl.a两个文件,这就是我们需要的,直接添加到项目中,别的不用看了。

2.配置: 

a.添加需要的框架和静态库CFNetwork.framework、SystemConfiguration.framework 、libz。

b.在工程info.plist设置中添加一个URL Types回调协议(在UPPayDemo工程中使用“UPPayDemo”作为协议),用于在支付完成后返回商户客户端。(知识扩展:http://blog.csdn.net/qq_29892943/article/details/65444498)

c.http请求设置 

在Xcode7.0之后的版本中进行http请求时,需要在工程对应的plist文件中添加NSAppTransportSecurity Dictionary 并同时设置里面NSAllowsArbitraryLoads 属性值为 YES

d.添加协议白名单 

在Xcode7.0之后的版本中进行开发,需要在工程对应的plist文件中,添加LSApplicationQueriesSchemes Array并加入uppaysdk、uppaywallet、uppayx1、uppayx2、uppayx3五个item,具体设置可参考以下截图: 

e.加-ObjC宏 (不理解的看这遍博客:http://blog.csdn.net/qq_29892943/article/details/64439624) 

选择工程targets——》build settings ->Linking->other linker flags 

f.调用插件

在需要调用支付控件接口的代码文件内引用头文件UPPaymentControl.h。

(注意:如果工程的compile source as 选项的值不是Objective–C++,则引用此头文件的文件类型都要改为.mm)

商户App从商户服务器获取tn(注:先通过调用后台接口获取订单信息)

* @param tn 订单信息

* @param schemeStr 调用支付的app注册在info.plist中的scheme

* @param mode 支付环境”00”代表接入生产环境(正式版本需要);”01”代表接入开发测试环境

* @param viewController 启动支付控件的viewController

* @return 返回成功失败

if (tn != nil &;&; tn.length > 0) { NSLog(@"tn=%@",tn); [[UPPaymentControl defaultControl] startPay:tn fromScheme:@"UPPayDemo" mode:kMode_Development viewController:self]; } 

7.返回结果接口调用 

支付控件结果处理函数handlePaymentResult: completeBlock:需要在工程AppDelegate文件的application: openURL: sourceApplication: annotation: 方法中进行调用。

支付控件结果处理函数handlePaymentResult: completeBlock:包含两个参数,参数1url为支付结果串,由handlePaymentResult: completeBlock:方法解析url内容;参数2completionBlock为商户APP定义的结果处理方法,包含两个传入参数code和data,其中code表示支付结果,取值为suceess,fail,cancel分别表示支付成功、支付失败和支付取消,data表示结果签名数据,商户使用银联公钥验证结果真实性。

completeBlock中的NSDictionary *data结构如下:

sign —— 签名后做Base64的数据

data —— 用于签名的原始数据,结构如下:

pay_result —— 支付结果success,fail,cancel

tn —— 订单号

Data转换为String后的示例如下:

“{“sign”:”ZnZY4nqFGu/ugcXNIhniJh6UDVriWANlHtIDRzV9w120E6tUgpL9Z7jIFzWrSV73hmrkk8BZMXMc/9b8u3Ex1ugnZn0OZtWfMZk2I979dxp2MmOB+1N+Zxf8iHr7KNhf9xb+VZdEydn3Wc/xX/B4jncg0AwDJO/0pezhSZqdhSivTEoxq7KQTq2KaHJmNotPzBatWI5Ta7Ka2l/fKUv8zr6DGu3/5UaPqHhnUq1IwgxEWOYxGWQgtyTMo/tDIRx0OlXOm4iOEcnA9DWGT5hXTT3nONkRFuOSyqS5Rzc26gQE6boD+wkdUZTy55ns8cDCdaPajMrnuEByZCs70yvSgA==”,”data”:”pay_result=success&;tn=201512151321481233778”}”

对于新增的签名信息需注意以下几点:

1. 前台返回的支付结果中包含银联签名,要在商户后台对签名进行校验后才能展示结果。

2. 前台签名使用的密钥和算法与后台结果中的签名一致。

3. 如果商户APP在客户端内进行签名验证,要自行实现签名密钥更新的机制,否则更换密钥后会导致验签失败。(不推荐)

4. 商户订单是否成功支付应该以商户后台收到全渠道返回的支付结果为准,此处支付控件返回的结果仅作为参考。

调用支付接口后,结果处理方法示例代码(AppDelegate.h):

//当用户通过其它应用启动本应用时,会回调这个方法,url参数是其它应用调用openURL:方法时传过来的。- (BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { [[UPPaymentControl defaultControl] handlePaymentResult:url completeBlock:^(NSString *code, NSDictionary *data) { //结果code为成功时,先校验签名,校验成功后做后续处理 if([code isEqualToString:@"success"]) { //如果想对结果数据验签,可使用下面这段代码,但建议不验签,直接去商户后台查询交易结果 if(data != nil){ //数据从NSDictionary转换为NSString NSData *signData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil]; NSString *sign = [[NSString alloc] initWithData:signData encoding:NSUTF8StringEncoding]; //此处的verify建议送去商户后台做验签,如要放在手机端验,则代码必须支持更新证书 if([self verify:sign]) { //验签成功,展示支付成功 NSLog(@"验签成功,展示支付成功"); } else { //验签失败,交易结果数据被篡改,商户app后台查询交易结果 } } //结果code为成功时,去商户后台查询一下确保交易是成功的再展示成功 } else if([code isEqualToString:@"fail"]) { //交易失败 } else if([code isEqualToString:@"cancel"]) { //交易取消 } }]; return YES;}// NOTE: 9.0以后使用新API接口- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options{ [[UPPaymentControl defaultControl] handlePaymentResult:url completeBlock:^(NSString *code, NSDictionary *data) { if([code isEqualToString:@"success"]) { //如果想对结果数据验签,可使用下面这段代码,但建议不验签,直接去商户后台查询交易结果 if(data != nil){ //数据从NSDictionary转换为NSString NSData *signData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil]; NSString *sign = [[NSString alloc] initWithData:signData encoding:NSUTF8StringEncoding]; //此处的verify建议送去商户后台做验签,如要放在手机端验,则代码必须支持更新证书 if([self verify:sign]) { //验签成功 } else { //验签失败 } } //结果code为成功时,去商户后台查询一下确保交易是成功的再展示成功 } else if([code isEqualToString:@"fail"]) { //交易失败 } else if([code isEqualToString:@"cancel"]) { //交易取消 } }]; return YES;} 

最后附上代码demo:

//// ViewController.m// 支付demo//// Created by huasu on 17/3/17.// Copyright © 2017年 JY. All rights reserved.// 运行时机制#import "ViewController.h"#import "UPPaymentControl.h"#import "AFNetworking.h"#define kMode_Development @"01"#define kURL_TN_Normal @"http://101.231.204.84:8091/sim/getacptn"#define kURL_TN_Configure @"http://101.231.204.84:8091/sim/app.jsp?user=123456789"@interface ViewController (){ NSMutableData* _responseData;}@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; UIButton *btn=[[UIButton alloc]init]; btn.backgroundColor=[UIColor redColor]; [btn setTitle:@"点我支付" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(btnclick) forControlEvents:UIControlEventTouchUpInside]; btn.frame=CGRectMake(10, 100, 100, 50); [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [self.view addSubview:btn];}-(void)btnclick{ NSURL *url=[NSURL URLWithString:kURL_TN_Normal]; NSURLRequest * urlRequest=[NSURLRequest requestWithURL:url]; NSURLConnection* urlConn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self]; [urlConn start];// AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];//// manager.responseSerializer = [AFJSONResponseSerializer serializer];//// manager.requestSerializer=[AFJSONRequestSerializer serializer];//// [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];// // NSString *strurl=kURL_TN_Normal;// // // [manager GET:strurl parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {// // }// success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {// // NSLog(@"返回tn成功");// NSLog(@"JSON: %@", responseObject);// //// if (tn != nil &;&; tn.length > 0)//// {//// //// NSLog(@"tn=%@",tn);//// [[UPPaymentControl defaultControl] startPay:tn fromScheme:@"UPPayDemo" mode:self.tnMode viewController:self];//// //// }// // // }// // failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {// // NSLog(@"请求失败");// NSLog(@"Error: %@", error);// // }];}- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response{ _responseData = [[NSMutableData alloc] init];}- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [_responseData appendData:data];}- (void)connectionDidFinishLoading:(NSURLConnection *)connection{ NSString* tn = [[NSMutableString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding]; if (tn != nil &;&; tn.length > 0) { NSLog(@"tn=%@",tn); [[UPPaymentControl defaultControl] startPay:tn fromScheme:@"UPPayDemo" mode:kMode_Development viewController:self]; }}-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}/*#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller.}*/@end 

测试卡号信息: 

借记卡:6226090000000048 

手机号:18100000000 

密码:111101 

短信验证码:123456 

(短信验证码记得点下获取验证码之后再输入)

贷记卡:6226388000000095; 

手机号:18100000000; 

cvn2:248; 

有效期:1219; 

短信验证码:123456 

(短信验证码记得点下获取验证码之后再输入)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • 一:介绍 项目中要用到支付功能,需要支付宝支付[https://www.jianshu.com/p/af9b584...
    Swift社区阅读 5,252评论 5 18
  • 开发前的准备工作 SDK说明 接口说明 1、支付接口 - (BOOL)startPay:(NSString*)tn...
    Detailscool阅读 3,380评论 5 50
  • 官方SDk下载地址 https://open.unionpay.com/ajweb/index 笔者Demo : ...
    SmallWhiteMouse阅读 1,960评论 0 0
  • 项目最近需要集成银联,在网上搜了一下发现都并不是最新版的银联集成教程,自己摸索了一下,总结写了下来。 附上3.3....
    嗜糖63阅读 632评论 2 5
  • 牵手走过青草街道 想时间再慢几分 爱在土地里生根发芽 我在风中摇曳长大 地上的脚印拼成一副画 留下爱情的童话 路边...
    夜光姑娘阅读 137评论 3 5