iOS-APP實現(xiàn)微信H5支付總結(jié)

微信H5支付流程

1、發(fā)起下單請求(調(diào)用統(tǒng)一下單接口)注:交易類型trade_type=MWEB

2丁稀、統(tǒng)一下單接口返回支付相關(guān)參數(shù)給商戶后臺邓了,如支付跳轉(zhuǎn)url(參數(shù)名“mweb_url”),商戶通過mweb_url調(diào)起微信支付中間頁拔恰。如:https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx27142704550165900edae5270331515985&package=600759311&redirect_url=http%3a%2f%2www.baidu.com

3褪尝、中間頁進行H5權(quán)限的校驗闹获,安全性檢查(具體錯誤見微信官方文檔

4、如果權(quán)限校驗成功河哑,微信支付中間頁會發(fā)起支付請求避诽。請求完畢跳到回調(diào)頁面(由redirect_url決定)。APP需要在webView中監(jiān)聽這個請求璃谨,打開微信進行支付沙庐。如:weixin://wap/pay?prepayid%3Dwx2718114258281033efb8751f1574826586&package=2965581453&noncestr=1545905512&sign=cb0f6dbd067549a04aada9c3eef09aac

5、微信支付完畢跳回APP。

Referer和redirect_url說明

HTTP Referer是header的一部分轨功,當瀏覽器向web服務器發(fā)起請求的時,一般會帶上Referer容达,告訴服務器我是從哪個頁面鏈接過來古涧。微信中間頁會對Referer進行校驗,非安全域名將不能正常加載花盐。
redirect_url是微信中間頁喚起微信支付之后羡滑,頁面重定向的地址。中間頁喚起微信支付后會跳轉(zhuǎn)到指定的redirect_url算芯。并且微信APP在支付完成時柒昏,也是通過redirect_url回調(diào)結(jié)果,redirect_url一般是一個頁面地址熙揍,所以微信支付完成會打開Safari瀏覽器职祷。本文通過修改redirect_url,實現(xiàn)微信支付完畢跳回當前APP届囚。

注意:微信會校驗Referer(來源)和redirect_url(目標)是否是安全域名有梆。如果不傳redirect_url,微信會將Referer當成redirect_url意系,喚起支付之后會重定向到Referer對應的頁面泥耀。

建議帶上redirect_url。

代碼實現(xiàn)

1蛔添、info.plist配置scheme

需要將微信H5支付的安全域名配置成scheme,微信支付完成會通過這個scheme跳轉(zhuǎn)回APP痰催。

<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

再shouldStartLoadWithRequest:方法里面攔截微信中間頁(以“https://wx.tenpay.com”開頭的請求)夸溶,截取redirect_url,如果redirect_url已經(jīng)被替換成scheme不攔截,如果沒有被替換凶硅,攔截請求蜘醋,保存當前的redirect_url。創(chuàng)建一個新的微信中間頁請求咏尝,將redirect_url替換成“安全域名://”(微信支付完畢會通過openURL打開當前APP压语,如果不替換redirect_url,微信支付完畢會打開Safari瀏覽器。)编检。設(shè)置“Referer”為安全域名(微信會校驗Referer胎食,不是安全域名會加載失敗),重新load請求允懂。

//這個referer和安全域名以及配置在info.plist中scheme一致
 NSString *referer = [NSString stringWithFormat:@"%@://",wxScheme];
        if ([newUrl rangeOfString:@"https://wx.tenpay.com"].location != NSNotFound) {
            //截取redirect_url對應的值
            NSDictionary *params = [HJStringHelper getUrlParam:newUrl];
            NSString *backUrl = params[@"redirect_url"];
            if ([backUrl isEqualToString:referer]) {
            //截取redirect_url被替換成referer,不攔截
                return YES;
            }else{
                //記錄當前的redirectUrl厕怜,并攔截請求
                self.redirectUrl = [HJStringHelper decodeURL:backUrl];
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSRange range = [newUrl rangeOfString:@"redirect_url="];
                    NSString *reqUrl;
                    if (range.length>0) {
                        reqUrl = [newUrl substringToIndex:range.location+range.length];
                        reqUrl = [reqUrl stringByAppendingString:referer];
                    }else{
                        reqUrl = [newUrl stringByAppendingString:[NSString stringWithFormat:@"&redirect_url=%@",referer]];
                    }
                    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:reqUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
                    //設(shè)置授權(quán)域名
                    [request setValue:referer forHTTPHeaderField:@"Referer"];
                    [self.webView loadRequest:request];
                });
                return NO;
            }
        }

2、攔截微信中間頁中打開微信請求

微信中間頁加載成功后,會收到一個打開微信的請求粥航,用openURL:打開這個url實現(xiàn)跳轉(zhuǎn)到微信支付琅捏。

 if([newUrl rangeOfString:@"weixin://wap/pay"].location != NSNotFound){
            if ([[UIApplication sharedApplication] canOpenURL:url]) {
                if (@available(iOS 10.0, *)){
                    [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
                }else{
                    [[UIApplication sharedApplication] openURL:url];
                }
            }else{
            }
            return NO;
        }

3、加載重定向地址

微信中間頁跳轉(zhuǎn)到微信時递雀,會將頁面從定向到redirect_url柄延,由于redirect_url被我們修改為scheme,所以需要攔截這個非法的scheme請求,替換成記錄下的redirect_url缀程。

 if([newUrl isEqualToString:referer]){
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.redirectUrl) {
                    //注意搜吧,這個地方需要對redirectUrl解碼,因為截取的redirectUrl被完全編碼了杨凑,需要先解碼才能加載
                    self.redirectUrl = [HJStringHelper decodeURL:self.redirectUrl];
                    
                    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[HJStringHelper encodeURL:self.redirectUrl]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
                    [self.webView loadRequest:request];
                    self.redirectUrl = nil;
                }
            });
            return NO;
        }

完整代碼如下

以UIWebView為例

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    //添加微信支付功能
    NSURL *url = [request URL];
    NSString *newUrl = url.absoluteString;
    //獲取微信安全域名
    NSString *wxScheme = [h5WXPayScheme copy];
    if (wxScheme.length>0) {
  //使用安全域名拼接referer
        NSString *referer = [NSString stringWithFormat:@"%@://",wxScheme];
        if ([newUrl rangeOfString:@"https://wx.tenpay.com"].location != NSNotFound) {
            
            NSDictionary *params = [HJStringHelper getUrlParam:newUrl];
            NSString *backUrl = params[@"redirect_url"];
            if ([backUrl isEqualToString:referer]) {
                return YES;
            }else{
                self.redirectUrl = [HJStringHelper decodeURL:backUrl];
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSRange range = [newUrl rangeOfString:@"redirect_url="];
                    NSString *reqUrl;
                    if (range.length>0) {
                        reqUrl = [newUrl substringToIndex:range.location+range.length];
                        reqUrl = [reqUrl stringByAppendingString:referer];
                    }else{
                        reqUrl = [newUrl stringByAppendingString:[NSString stringWithFormat:@"&redirect_url=%@",referer]];
                    }
                    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:reqUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
                    //設(shè)置授權(quán)域名
                    [request setValue:referer forHTTPHeaderField:@"Referer"];
                    [self.webView loadRequest:request];
                });
                return NO;
            }
        }else if([newUrl rangeOfString:@"weixin://wap/pay"].location != NSNotFound){
            if ([[UIApplication sharedApplication] canOpenURL:url]) {
                if (@available(iOS 10.0, *)){
                    [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
                }else{
                    [[UIApplication sharedApplication] openURL:url];
                }
            }else{
                
            }
            return NO;
        }else if([newUrl isEqualToString:referer]){
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.redirectUrl) {
                    
                    self.redirectUrl = [HJStringHelper decodeURL:self.redirectUrl];
                    
                    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[HJStringHelper encodeURL:self.redirectUrl]] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
                    [self.webView loadRequest:request];
                    self.redirectUrl = nil;
                }
            });
            return NO;
        }
    }
    return [super webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
}

還有一篇文章講的是H5支付封裝滤奈,H5支付不僅可以在網(wǎng)頁上使用,原生也可以調(diào)用撩满。具體內(nèi)容見:iOS-H5支付(微信蜒程、支付寶)原生封裝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伺帘,隨后出現(xiàn)的幾起案子搞糕,更是在濱河造成了極大的恐慌,老刑警劉巖曼追,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窍仰,死亡現(xiàn)場離奇詭異,居然都是意外死亡礼殊,警方通過查閱死者的電腦和手機驹吮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晶伦,“玉大人碟狞,你說我怎么就攤上這事』榕悖” “怎么了族沃?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泌参。 經(jīng)常有香客問我脆淹,道長,這世上最難降的妖魔是什么沽一? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任盖溺,我火速辦了婚禮,結(jié)果婚禮上铣缠,老公的妹妹穿的比我還像新娘烘嘱。我一直安慰自己昆禽,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布蝇庭。 她就那樣靜靜地躺著醉鳖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哮内。 梳的紋絲不亂的頭發(fā)上盗棵,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音牍蜂,去河邊找鬼。 笑死泰涂,一個胖子當著我的面吹牛鲫竞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逼蒙,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼从绘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了是牢?” 一聲冷哼從身側(cè)響起僵井,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驳棱,沒想到半個月后批什,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡社搅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年驻债,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片形葬。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡合呐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笙以,到底是詐尸還是另有隱情淌实,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布猖腕,位于F島的核電站拆祈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏倘感。R本人自食惡果不足惜缘屹,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侠仇。 院中可真熱鬧轻姿,春花似錦犁珠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至豹休,卻和暖如春炊昆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背威根。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工凤巨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人洛搀。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓敢茁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親留美。 傳聞我的和親對象是個殘疾皇子彰檬,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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