1、我接手这个项目的时候,项目已经集成了一网通的网页版支付,只不过前一段时间的需求里面并没有一网通支付,最近领导要求开通一网通支付的,我就把一网通支付的网页版打开了,也没怎么细看,反正调试好用,这两天领导让App跳转到一网通的支付,就像跳转微信,支付宝一样,看文档迷迷糊糊,网上找资料也是没有跳转App这块相关的,不过最后还是解决了,怕过段时间忘了,还是早点写出来博客,供大家参考,好了,言归正传,直接正题
1、以下是 一网通 jsonRequestData报文组织:的请求示例,有些参数是必选的,有些参数是可选的
{
"version":"1.0",
"sign":"见签名处理章节",
"signType":"SHA-256",
"reqData":{
"dateTime":"20161216140241",
"date":"20161216",
"orderNo":"9999153784",
"amount":"0.01",
"expireTimeSpan":"30",
"payNoticeUrl":"http://www.merchant.com/path/payNotice.do",
"payNoticePara":"aaa",
"branchNo":"0755",
"merchantNo":"000054",
"returnUrl":" yunjiazheng://callback",
"clientIP":"99.12.43.61",
"cardType":"",
"encrypData":"FC779C8E6953AC0C97BE115D61FE1669AECBE5836DF120A84157D9515DFD375E00B0538C85B930E6A33BB9E0213150E07953DEB1D4E30EF4356FF0B2700357881B3A8670B37C25C76DF2378DF9",
"encrypType":"RC4",
"subMerchantNo":"",
"subMerchantName":"",
"subMerchantTPCode":"",
"subMerchantTPName":""
}
}
2、上面的请求报文主要是调用后台接口,然后后台人员返给前台人员,签名也是后台来做,后台做 sign 签名的时候 这个地方就需要注意了,后台拿上面报文里面的数据进行签名的时候用了多少个字段,前台传给一网通的时候就需要多少个字段,多了,或者少了都会报订单无效,签名错误
3、首先在自己的app里面配置一下白名单,否则不会跳转到一网通,如下,在plist里面添加
<key>LSApplicationQueriesSchemes</key>
<array>
<string>wechat</string>
<string>weixin</string>
<string>cmbmobilebank</string> // 一网通
</array>
4、此时可以用iOS自带的方法进行一下验证,验证是否跳转
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cmbmobilebank://"]]){
// 安装了app
}else{
// 没有安装了app
// 调用一网通网页版支付(这个后期会更新)
}
5、通过4的验证,我们能够打开一网通的app,接下来就需要按照一网通的开发文档拿着请求报文跳转到支付界面
5(1)后台返回的数据结构,按照一网通报文的结构
oneWangTong.h
@property (nonatomic, strong) oneWangTongSub *reqData;
@property (nonatomic, copy) NSString *sign;
@property (nonatomic, copy) NSString *signType;
@property (nonatomic, copy) NSString *version;
oneWangTongSub.h
@property (nonatomic, copy) NSString *dateTime;
@property (nonatomic, copy) NSString *date;
@property (nonatomic, copy) NSString *orderNo;
@property (nonatomic, copy) NSString *amount;
@property (nonatomic, copy) NSString *expireTimeSpan;
@property (nonatomic, copy) NSString *payNoticeUrl;
@property (nonatomic, copy) NSString *payNoticePara;
@property (nonatomic, copy) NSString *branchNo;
@property (nonatomic, copy) NSString *merchantNo;
@property (nonatomic, copy) NSString *returnUrl;
@property (nonatomic, copy) NSString *clientIP;
@property (nonatomic, copy) NSString *cardType;
5(2)组装字典,生成JSON字符串,因为后台sign加密用到了 下面dict最后6个,所以前台拼装的时候也需要这6个,当时和后台约定好了,读者可以做的灵活些,就是所有的参数都是后台传,自己只需要组装字典,生成JSON字符串就可以了,我们对写的有点不灵活,因为需要考虑到安卓,后台,我就没有多嘴,哈哈哈哈
// 直接用接口返回的 5(1)中的oneWangTong调用下面的方法生成JSON 字符串
- (NSString *)oneWangTongchangeFromModel:(oneWangTong *)model
{
oneWangTongSub *subModel = model.reqData;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:subModel.dateTime forKey:@"dateTime"];
[dict setValue:subModel.date forKey:@"date"];
[dict setValue:subModel.orderNo forKey:@"orderNo"];
[dict setValue:subModel.amount forKey:@"amount"];
[dict setValue:subModel.expireTimeSpan forKey:@"expireTimeSpan"];
[dict setValue:subModel.payNoticeUrl forKey:@"payNoticeUrl"];
[dict setValue:subModel.payNoticePara forKey:@"payNoticePara"];
[dict setValue:subModel.branchNo forKey:@"branchNo"];
[dict setValue:subModel.merchantNo forKey:@"merchantNo"];
[dict setValue:@"cmbpt365://callback" forKey:@"returnUrl"];
[dict setValue:subModel.clientIP forKey:@"clientIP"];
[dict setValue:subModel.cardType forKey:@"cardType"];
[dict setValue:@"" forKey:@"encrypData"];
[dict setValue:@"" forKey:@"encrypType"];
[dict setValue:@"" forKey:@"subMerchantNo"];
[dict setValue:@"" forKey:@"subMerchantName"];
[dict setValue:@"" forKey:@"subMerchantTPCode"];
[dict setValue:@"" forKey:@"subMerchantTPName"];
//2.组装大字典
NSMutableDictionary *resultDict = [NSMutableDictionary dictionary];
[resultDict setValue:@"1.0" forKey:@"version"];
[resultDict setValue:[model.sign1 uppercaseString] forKey:@"sign"];
[resultDict setValue:@"SHA-256" forKey:@"signType"];
[resultDict setValue:dict forKey:@"reqData"];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:resultDict options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString;
if (!jsonData) {
NSLog(@"%@",error);
}else{
jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
}
NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
NSRange range = {0,jsonString.length};
// 去掉字符串中的空格
[mutStr replaceOccurrencesOfString:@" " withString:@"" options:NSLiteralSearch range:range];
NSRange range2 = {0,mutStr.length};
// 去掉字符串中的换行符
[mutStr replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:range2];
NSRange range3 = {0,mutStr.length};
// 去掉字符串中的“\\”
[mutStr replaceOccurrencesOfString:@"\\" withString:@"" options:NSLiteralSearch range:range3];
return mutStr;
}
5(3)当时我就直接拿着上面的JSON加上按照文档拼接的去调用,发现根本就不跳转,找了半天原因,原来文档上面写了一句话 就是 5(2)中的JSON字符串需要做urlEncode的处理,都怪没好好读文档啊
// 当时没有调用成功的写法
NSString *json = [NSString stringWithFormat:@"cmbmobilebank://CMBLS/FunctionJump?action=gofuncid&funcid=200007&serverid=CMBEUserPay&requesttype=post&cmb_app_trans_parms_start=here&charset=utf-8&jsonRequestData=%@",5(2)中的字符串];
5(4)对 5(2)进行urlEncode的处理
// 对JSON字符串进行urlEncode 处理
- (NSString *)URLEncodedString
{
// CharactersToBeEscaped = @":/?&=;+!@#$()~',*";
// CharactersToLeaveUnescaped = @"[].";
NSString *unencodedString = self;
NSString *encodedString = (NSString *)
CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8));
return encodedString;
}
5(5)拼接最终的请求报文
// 拼接请求报文
NSString *json = [NSString stringWithFormat:@"cmbmobilebank://CMBLS/FunctionJump?action=gofuncid&funcid=200007&serverid=CMBEUserPay&requesttype=post&cmb_app_trans_parms_start=here&charset=utf-8&jsonRequestData=%@",5(4)进行urlEncode处理的字符串];
5(6)用请求报文直接调用 一网通app (如下,就可以正常调用一网通直接跳转到支付界面)
CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion < 10.0f) {
BOOL success = [[UIApplication sharedApplication] openURL:url];
if (success) {
//跳转成功
} else {
//跳转失败
}
} else {
[[UIApplication sharedApplication] openURL:url
options:@{}
completionHandler:^(BOOL success) {
if (success) {
//跳转成功
}else {
//跳转失败
}
}];
}
} else {
// 调用网页版一网通支付(后续会补充)
}
5(7)一网通支付成功的返回我们的App
1、文档上面有写,就是请求报文里面有一个 参数 "returnUrl"
2、这个是后台返回的,所以需要和后台人员约定一下,返回的这个怎么写,参照文档,3就是文档的写法
3、yunjiazheng://callback",
4、需要在自己的app info---URL Types(最下面),增加一项,在增加项的 URL Schemes 中填写 3中的 yunjiazheng (后后台约定,冒号前面写的什么,URL Schemes就需要写同样的)
5、这样就可以由一网通的app返回到我们的app了
5(8)一网通支付成功结果回调
1、我当时是在 5(6)中用userDefaults做处理的 (成功标记 1 失败标记0)
CGFloat systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion < 10.0f) {
BOOL success = [[UIApplication sharedApplication] openURL:url];
if (success) {
//跳转成功
[[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"yiwangtongPayStatus"];
} else {
//跳转失败
[[NSUserDefaults standardUserDefaults] setObject:@"0" forKey:@"yiwangtongPayStatus"];
}
} else {
[[UIApplication sharedApplication] openURL:url
options:@{}
completionHandler:^(BOOL success) {
if (success) {
//跳转成功
[[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"yiwangtongPayStatus"];
}else {
//跳转失败
[[NSUserDefaults standardUserDefaults] setObject:@"0" forKey:@"yiwangtongPayStatus"];
}
}];
}
} else {
// 调用网页版一网通支付(后续会补充)
}
2、根据通知判断,通过发送接口来判断支付结果
// 监听进入前台
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForegroundNotification) name:UIApplicationWillEnterForegroundNotification object:nil];
// 进入前台
- (void)applicationWillEnterForegroundNotification {
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"yiwangtongPayStatus"] isEqualToString:@"1"]) {
[self getYiWanyTongResult]; // 发送一网通支付成功验证接口
[[NSUserDefaults standardUserDefaults] setObject:@"0" forKey:@"yiwangtongPayStatus"];
}
}
网友评论