Cordova H5打包APP调用微信支付返回APP
2020-07-14 本文已影响0人
小二郎_Ejun
APP的调用通过scheme,流程如下:
1、info.plist配置scheme
需要将微信H5支付的安全域名配置成scheme,微信支付完成会通过这个scheme跳转回APP。
根据微信后台的微信H5支付配置APP的schemes,传过去的redirect_url微信会做安全校验。所以用schemes作为redirect_url可以通过微信的安全校验。并且微信支付完毕,会通过redirect_url回调。所以用schemes替换redirect_url,这样微信支付后就能跳回APP,否则打开的就是Safari浏览器加载这个redirect_url。
根据微信H5支付的安全域名配置APP的schemes,比如安全域名是aa.baidu.com。APP的schemes就是aa.baidu,com.redirect_url为aa.baidi.com://.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>wxPay</string>
<key>CFBundleURLSchemes</key>
<array>
<string>微信scheme(安全域名)</string> </array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>wechat</string>
<string>weixin</string>
</array>
2、拦截微信中间页,截取redirect_url,并修改redirect_url,重新加载
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *wxScheme = @"pay.xslp.cn";
NSString *referer = [NSString stringWithFormat:@"%@://",wxScheme];
NSString *urlString = [request.URL absoluteString];
//与js交互
if ([webView.request.URL.absoluteString isEqualToString:@"http://t-tcp.xs815.com/sbc.html#/class"]) {
NSString *func = @"window.isApp()";
NSString *str = [webView stringByEvaluatingJavaScriptFromString:func];
NSLog(@"%@", str);
}
NSLog(@"%@", urlString);
BOOL shouldLoad = YES;
if ([urlString containsString:@"alipay://alipayclient/"]) {
//调起支付宝支付
[[UIApplication sharedApplication] openURL:request.URL options:@{} completionHandler:nil];
return NO;
}
//由微信支付返回到APP回调
if ([urlString hasPrefix:wxScheme]) {
NSRange range = [urlString rangeOfString:wxScheme];
if (range.location != NSNotFound) {
NSString *lastUrlString = [urlString substringFromIndex:range.location+range.length];
urlString = [@"https" stringByAppendingString:lastUrlString];
NSURL * url = [NSURL URLWithString:urlString];
NSURLRequest *tmpRequest = [[NSURLRequest alloc] initWithURL:url];
[webView loadRequest:tmpRequest];
return NO;
}
}
// 此处为最初方案,拦截生成订单接口添加平台参数,然后重新加载
// if ([urlString isEqualToString:@"https://pay.xslp.cn/index.php/User/Payment/pay"]) {
//
// NSData *data = request.HTTPBody;
//
//
// NSString *params = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(@"%@", params);
//
// if ([params containsString:@"platform=ios"]) {
// return YES;
// }
// NSURL *url = [NSURL URLWithString:urlString];
// NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
// // 如果有webMethod并且是POST,则POST方式组合提交
// [requestM setHTTPMethod:@"POST"];
// NSString *body = nil;
// body = [NSString stringWithFormat:@"%@&platform=ios",params];
// [requestM setHTTPBody: [body dataUsingEncoding: NSUTF8StringEncoding]];
//
// NSLog(@"%@",body);
// urlString = [urlString stringByAppendingFormat:@"%@&platform=ios",params];
//
// [webView loadRequest:requestM];
// return NO;
//
// }
if ([[request.URL absoluteString] containsString:@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb"]) {
//https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx141510111101428929331aef1977552000&package=1029873265&redirect_url=https%3A%2F%2Fpay.xslp.cn%2Findex.php%2FUser%2FPayment%2Fjump
//weixin://wap/pay?prepayid%3Dwx2317173862758252dcad00251141517400&package=1136975133&noncestr=1592903981&sign=4d26d96740bc8240197aa215c4137180
NSRange range = [urlString rangeOfString:@"redirect_url="];
if (range.location != NSNotFound) {
NSString *url = [urlString substringToIndex:range.location+range.length];
NSString *subString = [urlString substringFromIndex:range.location+range.length];
//判断URL是否修改,使返回App
if (redirectUrl && [subString isEqualToString:redirectUrl]) {
redirectUrl = nil;
return YES;
}
subString = [subString substringFromIndex:5];
subString = [wxScheme stringByAppendingString:subString];
redirectUrl = subString;
urlString = [url stringByAppendingString:subString];
NSMutableURLRequest *tmpRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
//设置授权域名
[tmpRequest setValue:referer forHTTPHeaderField:@"Referer"];
[webView loadRequest:tmpRequest];
return NO;
}
}
if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
}
VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL);
if (shouldLoad) {
// When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then
// mainDocumentURL != URL even though it's a top-level navigation.
BOOL isDevToolsRefresh = (request == webView.request);
BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]];
if (isTopLevelNavigation) {
// Ignore hash changes that don't navigate to a different page.
// webView.request does actually update when history.replaceState() gets called.
if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) {
NSString* prevURL = [self evalForCurrentURL:webView];
if ([prevURL isEqualToString:[request.URL absoluteString]]) {
VerboseLog(@"Page reload detected.");
} else {
VerboseLog(@"Detected hash change shouldLoad");
return shouldLoad;
}
}
switch (_state) {
case STATE_WAITING_FOR_LOAD_FINISH:
// Redirect case.
// We expect loadCount == 1.
if (_loadCount != 1) {
NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount);
}
break;
case STATE_IDLE:
case STATE_IOS5_POLLING_FOR_LOAD_START:
case STATE_CANCELLED:
// Page navigation start.
_loadCount = 0;
_state = STATE_WAITING_FOR_LOAD_START;
break;
default:
{
NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state];
NSLog(@"%@", description);
_loadCount = 0;
_state = STATE_WAITING_FOR_LOAD_START;
NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description};
NSError* error = [[NSError alloc] initWithDomain:@"CDVUIWebViewDelegate" code:1 userInfo:errorDictionary];
[self webView:webView didFailLoadWithError:error];
}
}
} else {
// Deny invalid URLs so that we don't get the case where we go straight from
// webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount).
shouldLoad = shouldLoad && [self shouldLoadRequest:request];
}
VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount);
}
return shouldLoad;
}