iOS-手机银行API移动端对接

一、app配置银行Scheme

银行Scheme 银行名称
cmbmobilebank 招商银行
cmbnetpay 招商银行
com.icbc.iphoneclient 工商银行
ccbmbsylunionpay 建设银行
ccbmbswebunionpay 建设银行
bocpay 中国银行
bankabc 农业银行
paesuperbank 平安银行
cmbc 民生银行
cebbank 光大银行
credit 广发银行
citicbankpay 中信银行

二、跳转银行方式

1、app跳转网银

判断是否安装银行app

- (BOOL)openBanAppWithAppScheme:(NSString *)scheme
{
    NSURL *url = [NSURL URLWithString:scheme];
    BOOL isCanOpen = [[UIApplication sharedApplication] canOpenURL:url];
    if (isCanOpen) {
#ifdef NSFoundationVersionNumber_iOS_10_0
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
        }];
#else
        [[UIApplication sharedApplication] openURL:url];
#endif
        [self goBackToRoot];
    }else
    {
        [[BFMobileQuickPayAlertView sharedInstance] showAlertController:self title:nil message:@"请下载APP" cancelTitle:@"确定" actionBlock:^(NSInteger buttonTag) {
        } otherButtonTitles:nil, nil];
        return YES;
    }
    return isCanOpen;
}

判断打开app还是h5支付

- (void)openBankWithParams:(id)params reqUrl:(NSString *)reqUrl orderId:(NSString *)orderId
{
    if ([reqUrl hasPrefix:@"https://"] || [reqUrl hasPrefix:@"http://"]) {
        //h5链接 走WKWebView
        NSMutableArray *paramsMutable = [NSMutableArray arrayWithArray:params];
        if ([self.selectedModel.functionId isEqualToString:gsBank_debit]||[self.selectedModel.functionId isEqualToString:gsBank_credit]) {
// 工商银行特殊处理
            NSURL *url = [NSURL URLWithString:@"com.icbc.iphoneclient://"];
            BOOL isCanOpen = [[UIApplication sharedApplication] canOpenURL:url];
            if (isCanOpen) {
                [paramsMutable addObject:@{@"fieldName":@"clientType",@"filedValue":@"1"}];
            }else
            {
                [paramsMutable addObject:@{@"fieldName":@"clientType",@"filedValue":@"0"}];
            }
        }
        BFMobileQuickPayWebViewController *webVC = [BFMobileQuickPayWebViewController new];
        webVC.urlString = reqUrl;
        webVC.postParams = paramsMutable;
        webVC.bankPay = YES;
        [self.navigationController pushViewController:webVC animated:YES];
    }else
    {
        //唤醒app
        if ([params count]>0) {
            //app柜台
            NSDictionary *paramsDict = params[0];
            NSString *fieldName = paramsDict[@"fieldName"];
            NSString *filedValue = paramsDict[@"filedValue"];
            NSString * charaters = @"?!@#$^&%*+,:;='\"`<>()[]{}/\\| ";
            NSCharacterSet * set = [[NSCharacterSet characterSetWithCharactersInString:charaters] invertedSet];
            filedValue = [filedValue stringByAddingPercentEncodingWithAllowedCharacters:set];;
            if ([self.selectedModel.functionId isEqualToString:paBank_debit]||[self.selectedModel.functionId isEqualToString:paBank_credit]) {
// 平安银行兼容处理
                NSString *url = @"https%3A%2F%2Fb.pingan.com.cn%2Fpay%2Fpeps%2Fgateway%2Fkoudai-payment.html";
                reqUrl = [NSString stringWithFormat:@"paesuperbank://?url=%@&extra=1&AD=0&%@=%@",url,fieldName,filedValue];
            }else
            {
                reqUrl = [NSString stringWithFormat:@"%@&%@=%@",reqUrl,fieldName,filedValue];
            }
        }
        if (![self openBanAppWithAppScheme:reqUrl]) {
            BFMobileQuickPayWebViewController *webVC = [BFMobileQuickPayWebViewController new];
            webVC.urlString = reqUrl;
            webVC.postParams = params;
            webVC.bankPay = YES;
            [self.navigationController pushViewController:webVC animated:YES];
        }
    }
}

2、内置H5打开银行付款页面

表单提交JS

#define POST_JS @"function my_post(path, params) {\
var method = \"POST\";\
var form = document.createElement(\"form\");\
form.setAttribute(\"method\", method);\
form.setAttribute(\"action\", path);\
for(var key in params){\
    if (params.hasOwnProperty(key)) {\
        var hiddenFild = document.createElement(\"input\");\
        hiddenFild.setAttribute(\"type\", \"hidden\");\
        hiddenFild.setAttribute(\"name\", key);\
        hiddenFild.setAttribute(\"value\", params[key]);\
    }\
    form.appendChild(hiddenFild);\
}\
document.body.appendChild(form);\
form.submit();\
}"

打开WKWebView
//self.urlString self.postParams都是 下单返回的网联 银联参数
//加载H5

-(void)loadWebView
{
    [BFMobileQuickPayWebViewController clear];
    if (self.urlString.length==0) {
        return;
    }
    self.urlString = [NSString URLEncodedString:self.urlString];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:self.urlString]
                                                  cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                              timeoutInterval:5];
    [_webView loadRequest:request];
    NSArray *array = (NSArray *)self.postParams;
    NSMutableDictionary *jsonRequestData = @{}.mutableCopy;
    for (NSDictionary *paramsDict in array) {
        NSString *fieldName = paramsDict[@"fieldName"];
        NSString *filedValue = paramsDict[@"filedValue"];
        [jsonRequestData setObject:filedValue forKey:fieldName];
    }
    if (jsonRequestData.count>0) {
        // 要传递的参数,(在开发中可以字典转成json字符串即可)
        NSString *jsonString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:jsonRequestData options:NSJSONWritingPrettyPrinted error:nil] encoding:NSUTF8StringEncoding];
        jsonString = [jsonString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
        jsonString = [jsonString stringByReplacingOccurrencesOfString:@" " withString:@""];

        NSString * dataStr = jsonString;
        // 发送的地址
        // 最终要执行的JS代码
        NSString * js = [NSString stringWithFormat:@"%@my_post(\"%@\", %@)",POST_JS,self.urlString,dataStr];
        DebugLog(@"js = %@",js);
        // 执行JS代码
        [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
            if (!error) { // 成功
                DebugLog(@"post成功:%@",response);
            } else { // 失败
                DebugLog(@"post失败:%@",error);
            }
        }];
    }
}

3、H5跳转APP支付

在WKWebView代理里面进行操作

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    DebugLog(@"请求的地址是:%@",navigationAction.request.URL.absoluteString);
    if ([navigationAction.request.URL.absoluteString rangeOfString:@"http://gwrecv.baofoo.com/b2cbank/page/nucc"].location != NSNotFound) {
        //返回商户
        [self goBack];
        decisionHandler(WKNavigationActionPolicyCancel);
    }else if ([navigationAction.request.URL.absoluteString rangeOfString:@"https://mobile.abchina.com"].location != NSNotFound&&[navigationAction.request.URL.absoluteString rangeOfString:@"TOKEN="].location != NSNotFound)
{
农行特殊处理 需要提前引入农行的sdk
        NSString *tokenString = @"";
        NSArray *array = [navigationAction.request.URL.absoluteString componentsSeparatedByString:@"?"];
        if (array.count>1) {
            tokenString = array[1];
            NSArray *tokenArray = [tokenString componentsSeparatedByString:@"="];
            if (tokenArray.count>1) {
                NSString *TokenID = tokenArray[1];
                if ([[ABCAppCaller sharedAppCaller] isABCePayAvailable:@"bankabc://"]) {
                    [[ABCAppCaller sharedAppCaller] callBankABC:@"bankabc" param:[NSString stringWithFormat:@"CallbackID=mobile_quick_pay_app_demo&TokenID=%@&Method=pay",TokenID]];//如果已安装掌银则调起掌银,两个参数分别为掌银的URL标示以及送的参数,参数格式参考标准url传参格式
                    [self goBack];
                }
            }
        }
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    else if (([navigationAction.request.URL.absoluteString rangeOfString:@"cmbnetpay://"].location != NSNotFound)||([navigationAction.request.URL.absoluteString rangeOfString:@"ccbmbswebunionpay://"].location != NSNotFound)||([navigationAction.request.URL.absoluteString rangeOfString:@"bocpay://"].location != NSNotFound)||([navigationAction.request.URL.absoluteString rangeOfString:@"com.icbc.iphoneclient://"].location != NSNotFound)||([navigationAction.request.URL.absoluteString rangeOfString:@"cebbank://"].location != NSNotFound))
    {
        BOOL isCanOpen = [[UIApplication sharedApplication] canOpenURL:navigationAction.request.URL];
        if (isCanOpen) {
#ifdef NSFoundationVersionNumber_iOS_10_0
            kWeakSelf(self)
            [[UIApplication sharedApplication] openURL:navigationAction.request.URL options:@{} completionHandler:^(BOOL success) {
                kStrongSelf(self)
            }];
#else
            [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
#endif
            [self goBack];
        }
        decisionHandler(WKNavigationActionPolicyCancel);
    }
    else
    {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}

安卓-手机银行API移动端对接

1.需要单独判断是否安装APP,如果已安装则跳转APP,如果未安装则需要通过WebView进行加载处理。
2.WebView加载处理,(农业银行需要再Webview中特殊处理)跳转逻辑由银行H5进行处理。

一.通用Webview加载

1.WebView加载需要对返回参数进行处理,然后通过表单模式提交

/**
 * 加载H5
 * @param bankWebBean
 * @param intentRequestWay
 */
private void loadUrl(BankWebBean bankWebBean,String intentRequestWay){
    Map<String, String> map = new HashMap<>();
    map.put(bankWebBean.getFieldName(), bankWebBean.getFiledValue());
    String vaule = JsonUtils.toJsondisableHtmlEscaping(map);
    showProgess();
    if (intentRequestWay.equals("GET")) {
        wvShow.loadUrl(intentUrl + "?" + intentParams);//get请求
    } else if (intentRequestWay.equals("POST")) {
        wvShow.loadUrl("javascript:" + Constants.H5FormSubmit);
        wvShow.loadUrl("javascript:my_post('" + intentUrl + "','" + vaule + "')");
    } else {
        Toast.makeText(this, "请求方式参数错误", Toast.LENGTH_SHORT).show();
    }
}

public static final String H5FormSubmit  = "function my_post(path, params) {\n" +
        "var datas = JSON.parse(params);\n" +
        "var method = \"POST\";\n" +
        "var form = document.createElement(\"form\");\n" +
        "form.setAttribute(\"method\", method);\n" +
        "form.setAttribute(\"action\", path);\n" +
        "form.setAttribute(\"enctype\", \"application/x-www-fom-urlencoded\");\n" +
        "for(var key in datas){\n" +
        "    if (datas.hasOwnProperty(key)) {\n" +
        "        var hiddenFild = document.createElement(\"input\");\n" +
        "        hiddenFild.setAttribute(\"type\", \"hidden\");\n" +
        "        hiddenFild.setAttribute(\"name\", key);\n" +
        "        hiddenFild.setAttribute(\"value\", datas[key]);\n" +
        "    }\n" +
        "    form.appendChild(hiddenFild);\n" +
        "}\n" +
        "document.body.appendChild(form);\n" +
        "form.submit();\n" +
        "}";

2.在webview shouldOverrideUrlLoading中判断url是否为Http或者 https开头,如果是继续加载,如果不是,则跳转通过Uri跳转原生

二.农业银行

跳转农行APP需提前报备,相关报备信息请查看农业银行快e付报备模板.xlsx

1.引入农行jar包 bankabccaller.jar
2.再shouldINterceptRequest中拦截判断,然后跳转

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
    if (request.getUrl().toString().contains("http://gwrecv.baofoo.com/b2cbank/page/nucc")) {
        finishCurrentActivity();
    }
    String url = request.getUrl().toString();
    if (url.contains("https://mobile.abchina.com") &&   //判断农业银行跳转
            url.contains("TOKEN=")) {
        JumpToBankApp.jumpToABCAPP(activity,request.getUrl().toString());
    }
    return super.shouldInterceptRequest(view, request);
}


/**
 * H5判断农行跳转
 * @param url
 */
public static void jumpToABCAPP(Activity activity,String url){
    if (JumpToBankApp.isABCAppInstaller(activity)) {  //农行逻辑处理
        String tokenId = url.split("=")[1];
        BankABCCaller.startBankABC(activity,
                activity.getPackageName(),
                "com.baofu.mobilequickpay.ui.activity.MobileBankPayActivity",
                "pay",
                tokenId);
        activity.setResult(EnvConfig.MOBILE_BANK_PAY_RESULT_CODE);
        activity.finish();
    }
}

/**
 * 判断农行是否安装
 * @param context
 * @return
 */
public static boolean isABCAppInstaller(Context context){
    /**
     * 判断手机上是否具备调起农行掌银的条件
     */
    if (BankABCCaller.isBankABCAvaiable((Activity) context)) {
        return true;
    } else {//客户手机未安装农行掌银APP的处理逻辑,由第三方APP自行实现
        return false;
    }
}

三.招商银行

1.根据包名判断是否安装app

public static boolean checkApkExist(Context context, String packageName){
    PackageManager manager = context.getPackageManager();
    List<PackageInfo> pkgList = manager.getInstalledPackages(0);
    for (int i = 0; i < pkgList.size(); i++) {
        PackageInfo pI = pkgList.get(i);
        if (pI.packageName.equalsIgnoreCase(packageName))
            return true;
    }
    return false;
}

2.如果已安装APP则通过跳转外部浏览器跳转招商APP

public static void callBankApp(Activity context,String url) {
    try {
        Intent intent = new Intent();
        Uri data = Uri.parse(url);
        intent.setData(data);
        intent.setAction("android.intent.action.VIEW");
        context.startActivityForResult(intent, EnvConfig.MOBILE_NATIVE_BANK_PAY_REQUEST_CODE);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3.未安装APP
跳转webview打开地址

四.平安银行

1.根据包名判断是否安装平安银行APP(同招商银行判断方式)
2.已安装,跳转平安银行app(跳转方式同招商银行)
平安银行跳转路径已经参数需要重新组装

public static String assemblyPingAnUrl(MobileBankPayResponse response){
    String pingAnURL = "paesuperbank://?url=https%3A%2F%2Fb.pingan.com.cn%2Fpay%2Fpeps%2Fgateway%2Fkoudai-payment.html&extra=1&AD=0&";
    for(int i = 0;i<response.getReqParams().size();i++){
        if(i == response.getReqParams().size()-1){
            pingAnURL = pingAnURL+response.getReqParams().get(i).getFieldName()+
                    "="+ URLEncoder.encode(response.getReqParams().get(i).getFiledValue());
        }else{
            pingAnURL = pingAnURL+response.getReqParams().get(i).getFieldName()+"="+
                    URLEncoder.encode(response.getReqParams().get(i).getFiledValue())+"&";
        }
    }
    return pingAnURL;
}

3.未安装通过webview加载

作者:xiaofeng  创建时间:2023-06-12 19:45
最后编辑:xiaofeng  更新时间:2024-09-19 18:06