iOS H5微信和支付寶支付的那些坑

剛?cè)肼毑痪茫拥揭粋€(gè)項(xiàng)目需求是在WebView上進(jìn)行微信支付和支付寶支付始绍。原本認(rèn)為只要將WebView加載一下拔恰,剩下的交給網(wǎng)頁處理就行了,實(shí)踐告訴我并不是那么簡單闹获。
在處理WebView的時(shí)候期犬,我仿佛遇到了WebView加載的支付的所有問題,總結(jié)遇到的問題如下:

  • 支付寶回調(diào)APP問題
  • 微信回調(diào)APP問題
  • AbsoluteURL加載為NULL問題
  • 支付寶回調(diào)回來避诽,頁面不穩(wěn)定的問題

接下來龟虎,我會(huì)一一解釋一下問題和解決過程。

一茎用、回調(diào)問題

在我們支付過程中遣总,微信支付的接口比較少,只有兩個(gè):
一個(gè)是https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb打頭的轨功,一個(gè)是weixin://wap/pay打頭的。
支付寶因?yàn)樗麄冏约鹤隽薍5支付容达,故支付的接口相對(duì)多一些古涧。

我使用過UIWebView和WKWebView兩種方式進(jìn)行加載,前提是不做任何處理使用WebView加載支付花盐,
使用UIWebView調(diào)用微信支付的時(shí)候羡滑,可以直接跳轉(zhuǎn)到App,支付成功或失敗返回到Safari里面算芯,不會(huì)回調(diào)到APP中柒昏;使用WKWebView調(diào)用微信支付的時(shí)候,則是定格在了一個(gè)空白的頁面熙揍;使用UIWebView和WKWebView加載支付寶支付的時(shí)候职祷,都會(huì)自動(dòng)加載他們支付寶自己做的H5原生頁面,但兩者都不會(huì)自動(dòng)跳轉(zhuǎn)。

由于有梆,WKWebView有著天然的優(yōu)勢是尖,蘋果官方也推薦,最后選擇WKWebView進(jìn)行處理泥耀。

在處理回調(diào)之前需要進(jìn)行一步————配置Scheme
配置Scheme一定要注意饺汹,一般情況下是公司的一個(gè)域名www.xxx.com,這個(gè)是存在于微信支付平臺(tái)配置中的痰催,如果不清楚的問后臺(tái)兜辞。

1.微信回調(diào)APP

在處理回調(diào)的過程主要是要在WebView中的URL的攔截處理,首先我們看看微信支付的兩個(gè)URL的形式:

第一個(gè)

https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wxxxxxxxx&package=xxxxxx&redirect_url=https://xxx.xxx.com?oc=ten&sn=xxxxx&userid=xxxxx&token=LWj4G5WPnHQsggPRmTqXa7/aMm1hGbsvlaCR68YTfAaQaxz7gOfN6TD7zTzWgfatJnkIS5BwiNyiK37S1mQ==

redirect_url后面的https://xxx.xxx.com/xxx是公司的返回H5頁面

第二個(gè)

weixin://wap/pay?prepayid=xxxxxx&package=xxxxx&noncestr=xxxxx&sign=27fbd4e19dfcd5773887a3867981d732

處理思路:

我們需要對(duì)這兩個(gè)URL進(jìn)行攔截加載夸溶,對(duì)第一個(gè)URL進(jìn)行攔截逸吵,攔截到之后,獲取并修改redirect_url的內(nèi)容蜘醋。redirect_url這個(gè)是控制回調(diào)的定位標(biāo)識(shí)胁塞,原來是個(gè)Https的公司鏈接,故返回的時(shí)候压语,他會(huì)自動(dòng)調(diào)用Safari啸罢。我們只要把這個(gè)地方修改成我們的Scheme://即可返回。為什么是這種形式呢胎食?我們可以做個(gè)簡單的嘗試就會(huì)明白扰才,把我們的APP的Scheme://打到Safari中,你會(huì)發(fā)現(xiàn)他會(huì)自動(dòng)調(diào)用我們的APP厕怜,同理衩匣,我們?nèi)绻赟afari中輸入Alipay://Wetchat://他會(huì)分別調(diào)用支付寶和微信APP。
另外粥航,可能還有些小伙伴會(huì)出現(xiàn)這樣的情況琅捏,APP跳回來之后,發(fā)現(xiàn)是空白頁递雀。這里推薦做這個(gè)處理柄延,將redirect_url后面的本地保存一份兒,當(dāng)回調(diào)回來之后缀程,加載公司自己的H5頁面搜吧。
最后,微信支付還需要在Header中杨凑,把Scheme://加到Referer里面滤奈,具體看代碼

//WKWebView的處理攔截的Delegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 
  //absoluteURL
    NSString *absoluteUrl = navigationAction.request.URL.absoluteString;
    absoluteUrl = [absoluteUrl URLDecodedString];
    LWLog(@"\n當(dāng)前的absoluteURL:------\n\n\n %@\n\n\n", absoluteUrl);
#pragma mark - 微信支付
    if ([absoluteUrl containsString:@"weixin://wap/pay"]) {
//打開APP
        [[UIApplication sharedApplication] openURL:navigationAction.request.URL];
        self.isWXLoad = NO;
        decisionHandler(WKNavigationActionPolicyCancel);
    } else if ([absoluteUrl containsString:@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?"] && self.isWXLoad == NO) {
        self.isWXLoad = YES;
        NSString *redirect_url = @"redirect_url=https://pay.xyyl.com/app/payreturn.html";
        if ([absoluteUrl containsString:redirect_url]) {
            //把將要回調(diào)的字符串進(jìn)行本地存儲(chǔ)
            NSRange range = [absoluteUrl rangeOfString:redirect_url];
            self.backURL = [absoluteUrl substringFromIndex:range.location+13];
            //替換
            NSString *newUrl = [absoluteUrl stringByReplacingOccurrencesOfString:redirect_url withString:[NSString stringWithFormat:@"&redirect_url=%@://", comScheme]];
            //字符串進(jìn)行替換,讓回調(diào)之后返回自己的app
            newUrl = [newUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
            NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:newUrl]];
//header中添加Referer
            newRequest.allHTTPHeaderFields = navigationAction.request.allHTTPHeaderFields;
            [newRequest setValue:[NSString stringWithFormat:@"%@://", comScheme] forHTTPHeaderField: @"Referer"];
            [webView loadRequest:newRequest];
        } else {
            NSURLRequest *request = navigationAction.request;
            NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc] init];
            newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields;
            [newRequest setValue:[NSString stringWithFormat:@"%@://", comScheme] forHTTPHeaderField: @"Referer"];
            newRequest.URL = request.URL;
            [webView loadRequest:newRequest];
        }
        decisionHandler(WKNavigationActionPolicyCancel);
    } else if ([absoluteUrl containsString:@"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?"]) {
        self.isWXLoad = NO;
       decisionHandler(WKNavigationActionPolicyAllow);
}

2.支付寶回調(diào)APP

雖然支付寶跳轉(zhuǎn)的URL較多撩满,但是我們只需要攔截的是下面這個(gè)接口即可蜒程,故相對(duì)微信略微簡單些绅你。


image.png

處理思路:

很明顯,URL的參數(shù)是個(gè)字典搞糕。同微信勇吊,這里需要處理的返回標(biāo)識(shí)是字典中的"fromAppUrlScheme"。我們需要做的操作是窍仰,將參數(shù)后面的部分轉(zhuǎn)化成字典汉规,然后,將字典fromAppUrlScheme參數(shù)換成scheme://再拼接加載新的URL即可驹吮。
值得一說的是针史,支付寶因?yàn)橛凶约旱腍5,當(dāng)我們跳轉(zhuǎn)回來之后碟狞,不會(huì)出現(xiàn)白頁情況啄枕。所以這里不需要再本地存儲(chǔ)回調(diào)回來的公司H5頁面信息了。

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    //absoluteURL
    NSString *absoluteUrl = navigationAction.request.URL.absoluteString;
    absoluteUrl = [absoluteUrl URLDecodedString];
    LWLog(@"\n當(dāng)前的absoluteURL:------\n\n\n %@\n\n\n", absoluteUrl); 
    if ([absoluteUrl containsString:@"alipay://alipayclient"]) {
        NSMutableString *param = [NSMutableString stringWithFormat:@"%@", (__bridge_transfer NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (__bridge CFStringRef)absoluteUrl, CFSTR(""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding))];
        
        NSRange range = [param rangeOfString:@"{"];
        // 截取 json 部分
        NSString *param1 = [param substringFromIndex:range.location];
        if ([param1 rangeOfString:@"\"fromAppUrlScheme\":"].length > 0) {
            id json = [LWTools dictionaryWithJsonString:param1]; //轉(zhuǎn)成 dictionary
            if (![json isKindOfClass:[NSDictionary class]]) {
                decisionHandler(WKNavigationActionPolicyAllow);
                return;
            }
            
            NSMutableDictionary *dicM = [NSMutableDictionary dictionaryWithDictionary:json];
            dicM[@"fromAppUrlScheme"] = [NSString stringWithFormat:@"%@://", comScheme];
            
            NSString *jsonStr = [LWTools convertToJsonData:dicM];  //轉(zhuǎn)成json
            
            NSString *encodedString = (NSString*) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,                           (CFStringRef)jsonStr, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8));
            
            // 只替換 json 部分
            [param replaceCharactersInRange:NSMakeRange(range.location, param.length - range.location)  withString:encodedString];
param replaceCharactersInRange:NSMakeRange(range.location, param.length - range.location)  withString:encodedString];
            
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:param]];
        }
        
        decisionHandler(WKNavigationActionPolicyCancel);
    }
    
    decisionHandler(WKNavigationActionPolicyAllow);
}
  

到此族沃,支付寶和微信的回調(diào)問題就處理完了频祝。
再次感謝這兩位iOSer的分享
H5回調(diào)參考
微信h5支付無法直接返回APP的參考

二、AbsoluteURL加載為NULL問題

我再嘮叨兩個(gè)小問題脆淹,這兩個(gè)問題可以大家也會(huì)忽視常空。

這個(gè)問題是:在我用webView加載的時(shí)候,獲取了absoluteURL之后盖溺,新建一個(gè)Request之后再次重新加載會(huì)出現(xiàn)NULL的情況漓糙。
發(fā)生的根源是:

 NSString *absoluteUrl = navigationAction.request.URL.absoluteString;
//*******萬惡之源
    absoluteUrl = [absoluteUrl URLDecodedString];

當(dāng)時(shí),因?yàn)榧虞dabsoluteUrl是那種URL編碼的形式烘嘱,像一些冒號(hào)昆禽、分號(hào)等在日志中都是%數(shù)字的形式,完全沒法操作蝇庭,所以進(jìn)行了URL編碼的處理醉鳖。那么問題來了,看似一個(gè)非常有血統(tǒng)的URL哮内,重新在NewRequest一下辐棒,下一次的加載為什么是空呢?然而牍蜂,事實(shí)證明,我們只要對(duì)URL做編碼處理之后泰涂,一旦加載absoluteUrl一定要再對(duì)URL反編譯回去鲫竞,實(shí)測有的URL可以,有的URL不可以逼蒙。

//這句話千萬不要省从绘,要不可能出錯(cuò)就很難找原因了!
newUrl = [newUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

三、支付寶回調(diào)回來僵井,頁面不穩(wěn)定的問題

項(xiàng)目測試的時(shí)候陕截,出現(xiàn)了一個(gè)問題,支付寶有一個(gè)頁面是選擇頁面:可以選擇已完成支付和繼續(xù)支付的兩個(gè)按鈕頁面批什。假設(shè)這個(gè)是頁面A农曲,然后再假設(shè)自己公司的支付結(jié)果返回頁面是頁面B。

測試多次這邊會(huì)發(fā)現(xiàn)會(huì)出現(xiàn)三種情況驻债,
-回調(diào)回來會(huì)停在頁面A上乳规;
-回調(diào)回來會(huì)在A頁面停留1、2秒跳轉(zhuǎn)B合呐,在B中進(jìn)行操作暮的;
-回調(diào)回來A頁面短暫停留到B頁面,B頁面短暫停留淌实,pop出了當(dāng)前VC冻辩。

問題主要是WKWebView的重定向問題,只要添加下面的代理方法即可:

-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    WKFrameInfo *frameInfo = navigationAction.targetFrame;
    if (![frameInfo isMainFrame]) {
        [webView loadRequest:navigationAction.request];
    }
    //
    return nil;
}

以上是我在webView中遇到的比較麻煩的問題拆祈,根據(jù)項(xiàng)目的區(qū)別大家遇到的問題或多或少也會(huì)有差別恨闪,歡迎大家在留言區(qū)評(píng)論、交流缘屹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凛剥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子轻姿,更是在濱河造成了極大的恐慌犁珠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件互亮,死亡現(xiàn)場離奇詭異犁享,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)豹休,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門炊昆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人威根,你說我怎么就攤上這事凤巨。” “怎么了洛搀?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵敢茁,是天一觀的道長。 經(jīng)常有香客問我留美,道長彰檬,這世上最難降的妖魔是什么伸刃? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮逢倍,結(jié)果婚禮上捧颅,老公的妹妹穿的比我還像新娘。我一直安慰自己较雕,他們只是感情好碉哑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著郎笆,像睡著了一般谭梗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宛蚓,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天激捏,我揣著相機(jī)與錄音,去河邊找鬼凄吏。 笑死远舅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的痕钢。 我是一名探鬼主播图柏,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼任连!你這毒婦竟也來了蚤吹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤随抠,失蹤者是張志新(化名)和其女友劉穎裁着,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拱她,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡二驰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秉沼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桶雀。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖唬复,靈堂內(nèi)的尸體忽然破棺而出矗积,到底是詐尸還是另有隱情,我是刑警寧澤敞咧,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布漠魏,位于F島的核電站,受9級(jí)特大地震影響妄均,放射性物質(zhì)發(fā)生泄漏柱锹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一丰包、第九天 我趴在偏房一處隱蔽的房頂上張望禁熏。 院中可真熱鬧,春花似錦邑彪、人聲如沸瞧毙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宙彪。三九已至,卻和暖如春有巧,著一層夾襖步出監(jiān)牢的瞬間释漆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工篮迎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留男图,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓甜橱,卻偏偏與公主長得像逊笆,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子岂傲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容