廢話很少說,直接說重點php
微信官方提醒:H5支付不建議在APP端使用,如須要在APP中使用微信支付,請接APP支付,文檔詳見微信支付開發文檔html
場景:公司業務須要,在移動端App中引入了微信H5支付
邏輯,支付流程Android
沒問題,可是在iOS
端出現了支付成功/失敗以後打開了Safari
,並無直接返回App
的問題。前端
如下爲解決方案:web
首先在網頁中H5調起微信時,能夠獲取到H5發出的支付連接爲https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=************&package=*********&redirect_url=http://pay.*********.com/phonepay/wxsuccess.jsp
此連接會發起支付,而後打開微信App支付頁面,支付以後返回App,這個流程在Android
中是沒有問題的,可是在iOS
端支付以後確莫名其妙的打開了Safari
,Safari
顯示的界面爲redirect_url
參數對應的http://pay.*********.com/phonepay/wxsuccess.jsp
連接界面。api
注意:此處連接中的
redirect_url
是微信支付以後的結果界面,若是在此連接中拼接了redirect_url
,那麼Safari
是必定會被打開的,若是前端拼接了此地址,那麼可讓前端來對iOS
端區別操做,不拼接redirect_url
。微信
若是前端處理起來比較麻煩,或者不肯意作處理,那麼只能移動端(iOS)來手動將這部分參數截取app
最終,iOS端發起支付的H5連接爲https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=************&package=*********
,僅僅只是這樣還不行,這個時候連接打開會報錯jsp
此時,還須要一步操做:async
在項目中配置Schemes爲pay.***.com
微信支付
注意:此處的
pay.***.com
,爲微信H5支付註冊時配置的受權域名
而後在UIWebView的代理-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
中添加如下代碼:
/*
此處省略了從
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=************&package=*********&redirect_url=http://pay.*********.com/phonepay/wxsuccess.jsp
連接中刪除redirect_url的代碼
*/
/*
將刪除了redirect_url的支付連接,頭部添加Referer信息,以便微信支付以後能夠返回app
此處作連接的前綴判斷是爲了防止在其餘連接中加入Referer信息
*/
NSDictionary *headers = [request allHTTPHeaderFields];
NSString *preStr = @"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb";
if (![[headers objectForKey:@"Referer"] isEqualToString:@"pay.***.com://"] && [request.URL.absoluteString hasPrefix:preStr]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [request URL];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[req setHTTPMethod:@"GET"];
[req setValue:@"pay.***.com://" forHTTPHeaderField:@"Referer"];
[self->webView loadRequest:req];
});
});
return YES;
}
複製代碼
解釋: 若是連接中拼接了
redirect_url
,那麼系統會用Safari
打開此連接,將此連接相關配置刪除以後,在請求頭部添加Referer
以後,那麼將會打開Referer
對應的連接。因爲咱們這裏給Referer
配置的pay.***.com://
協議,以前已經在App中註冊了Schemes
,那麼在Safari
打開此協議時將會直接打開App
,而且沒有中間Safari
跳轉的過程(關於此處請自行搜索iOS 如何使用Safari打開App
).
到此,支付邏輯能夠返回App了,那麼可能還會有疑問,個人redirect_url
對應的支付結果界面如何展現呢。
關於redirect_url
,微信支付開發文檔有以下介紹
總的來講:使用redirect_url
返回支付結果界面的時機本就沒法精確掌控。因此根據微信此處介紹,能夠有兩種方案解決:
UIWebView
,跳轉支付結果界面redirect_url
因爲,咱們支付成功失敗以後都是同一個界面,因此採用了第一種方案,五秒以後刷新
最終代碼以下:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
/*
此處省略了從
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=************&package=*********&redirect_url=http://pay.*********.com/phonepay/wxsuccess.jsp
連接中刪除redirect_url的代碼
*/
/*
將刪除了redirect_url的支付連接,頭部添加Referer信息,以便微信支付以後能夠返回app
此處作連接的前綴判斷是爲了防止在其餘連接中加入Referer信息
*/
NSDictionary *headers = [request allHTTPHeaderFields];
NSString *preStr = @"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb";
if (![[headers objectForKey:@"Referer"] isEqualToString:@"pay.***.com://"] && [request.URL.absoluteString hasPrefix:preStr]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [request URL];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[req setHTTPMethod:@"GET"];
[req setValue:@"pay.***.com://" forHTTPHeaderField:@"Referer"];
[self->webView loadRequest:req];
});
});
return YES;
}
/*
從打開微信支付開始,五秒以後刷新webView界面(redirect_url本就不靠譜,沒法精確)
weixin://wap/pay 爲最終調起微信支付時的協議開頭
*/
if ([request.URL.absoluteString hasPrefix:@"weixin://wap/pay"]) {
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
[self->webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pay.***.com/phonepay/wxsuccess.jsp"]]];
});
return YES;
}
}
複製代碼