阅读 577

iOS支付宝微信h5支付无法返回App解决方案

由于app购买的是虚拟商品,原生接入支付宝微信支付会有苹果审核风险,故采用h5接入支付。

存在的问题:
微信支付成功无法返回app,而是打开了Safari
支付宝支付成功还是停留在了支付宝

1.微信支付
  1. 微信后台配置授权域名,如 http: //aaa.bbb.com
  2. 在App工程配置中添加 URL Schemes: aaa.bbb.com (必须与域名保持一致
  3. 拦截WKWebView代理方法
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURL *url = navigationAction.request.URL;
    if ([url.absoluteString hasPrefix:@"weixin://"]) {
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            [[UIApplication sharedApplication] openURL:url];
        }
    }
    NSString *kWXPay_url = @"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"; //微信下单url
    NSString *referer = @"aaa.bbb.com://"; //与scheme、微信配置的授权域名 保持一致
    
    if ([url.absoluteString containsString:kWXPay_url]) {
        NSDictionary *headers = [navigationAction.request allHTTPHeaderFields];
        BOOL hasReferer = [referer isEqualToString:[headers objectForKey:@"Referer"]];
        if (hasReferer) { //已经设置了
            decisionHandler(WKNavigationActionPolicyAllow);
        } else {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSURL *url = [navigationAction.request URL];
                    NSDictionary *dic = [url bf_queryDictionary];
                    if ([dic.allKeys containsObject:@"redirect_url"]) {
                        self.redirect_url = dic[@"redirect_url"]; //保存redirect_url,用于刷新支付结果
                    }
                    NSString *urlStr = [NSString stringWithFormat:@"%@?prepay_id=%@&package=%@",kWXPay_url,dic[@"prepay_id"],dic[@"package"]];
                    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
                    [request setHTTPMethod:@"GET"];
                    [request setValue:referer forHTTPHeaderField: @"Referer"];
                    [self.webView loadRequest:request];
                });
            });
            decisionHandler(WKNavigationActionPolicyCancel);
        }
        return;
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}

//监听app回到前台事件
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];

- (void)handleWillEnterForeground {
    if (self.redirect_url) {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.redirect_url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
    [self.webView loadRequest:request];
        self.redirect_url = nil;
    }
}

//记得移除监听
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
复制代码

说明:

  • 拦截跳转微信的url,用 [[UIApplication sharedApplication] openURL:url] 打开,才会跳转微信客户端
  • 拦截微信下单地址 kWXPay_url,设置请求头的 Referer ,格式为 scheme://
  • 去掉url参数里的回调地址redirect_url,否则支付成功还是会打开Safari。同时保存redirect_url地址,当支付成功时监听app回到前台的事件,刷新webView更新支付状态。
2.支付宝

支付宝相对于微信要简单的多,只需要拦截跳转支付宝的url,将 fromAppUrlScheme 替换为自己的scheme(如aaa),再用 [[UIApplication sharedApplication] openURL:url] 打开即可。 (后端和h5都说fromAppUrlScheme的值他们改不了,所以由客户端拦截替换)

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURL *url = navigationAction.request.URL;
    if ([url.absoluteString hasPrefix:@"alipay://"] ||
        [url.absoluteString hasPrefix:@"alipays://"]) {
        
        //替换scheme为aaa
        NSString *newUrl = [url.absoluteString stringByReplacingOccurrencesOfString:@"fromAppUrlScheme%22%3A%22alipays" withString:@"fromAppUrlScheme%22%3A%22aaa"];
        if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:newUrl]]) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:newUrl]];
        }
    }
    decisionHandler(WKNavigationActionPolicyAllow);
 }
复制代码

补充

从url获取参数字典的方法

@implementation NSURL (URLQuery)

- (NSDictionary *)bf_queryDictionary {
    return self.query.bf_URLQueryDictionary;
}

@end


@implementation NSString (URLQuery)

- (NSDictionary *)bf_URLQueryDictionary
{
    NSMutableDictionary *mute = @{}.mutableCopy;
    for (NSString *query in [self componentsSeparatedByString:@"&"]) {
        NSArray *components = [query componentsSeparatedByString:@"="];
        if (components.count == 0) {
            continue;
        }
        NSString *key = [components[0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        id value = nil;
        if (components.count == 1) {
            // key with no value
            value = [NSNull null];
        }
        if (components.count == 2) {
            value = [components[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            // cover case where there is a separator, but no actual value
            value = [value length] ? value : [NSNull null];
        }
        if (components.count > 2) {
            NSString *prefixStr = [NSString stringWithFormat:@"%@=",components[0]];
            value = [[query substringFromIndex:prefixStr.length] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        }
        if (value == nil || value == [NSNull null]) {
            continue;
        } else {
            mute[key] = value;
        }
    }
    return mute.count ? mute.copy : nil;
}
@end
复制代码
文章分类
iOS
文章标签