為你的App增加WIFI認證檢測,讓使用者體驗更加絲滑

譚真發表於2018-07-20

前言

前段時間在上海坐地鐵時連線了花生地鐵WIFI,開啟QQ音樂開始聽歌,QQ音樂居然給了我一個”WIFI認證提醒”的彈窗,點選認證就跳轉到了花生地鐵WIFI的認證頁,之後順利聯網成功,體驗非常爽。作為一名iOS開發,不禁思考這個是怎麼做到的呢?忘記WIFI重新連線後,開啟手機裡各個應用輪番測試一遍,發現QQ音樂、QQ、QQ空間三個應用都做了比較好的WIFI認證提示:

成功提示.png

而其它的大應用如微信、手淘、支付寶、釘釘、美團、點評、愛奇藝、百度地圖等則都沒有給出認證提醒,而是提示我檢查網路設定等,說明許多App都沒重視到這個細節,而其實現在這種場景還是很多的,比如花生地鐵WIFI、i-Shanghai、i-hangzhou、alibaba-guest和其它許多公共場所的WIFI,還是有必要做一個優化~

失敗提示.png

關於Captive Portal

經過一番調研,這種需認證才能使用的WIFI,使用的是Captive Portal機制,中文通常譯作“強制主頁”或“強制登入門戶”,一個Captive Portal是一個Web登入頁面,通常由網路運營商或閘道器在使用者能夠正常訪問網際網路之前攔截使用者的請求並將一個強制登入或認證主頁呈現(通常是通過瀏覽器)給使用者。該頁面可能要求使用者輸入認證資訊、支付、接受某些條款或者其他使用者授權等,隨後使用者才能被授權訪問網際網路。該技術廣泛用於移動和個人寬頻服務,包括有線電視、商業WiFi、家庭熱點等,也可用於訪問企業和住宅區有線網路。詳細可參看wiki:https://en.wikipedia.org/wiki/Captive_portal

大多數需認證WIFI實現Captive Portal是通過HTTP重定向的方式,也有一些是通過DNS劫持或ICMP重定向的方式。

如何檢測Captive Portal

iOS和Android系統其實早就實現了Captive Portal的檢測機制,只是有一些WIFI會繞過這樣機制。就需要我們額外再做一次檢測了。

詳細可參看:
關於Apple的Captive Network Assistant
Bypasses Apple Captive Network Assistant Login in iOS 7

根據Captive Portal的實現方式和特點,我們有以下兩種常用檢測方法:( 歡迎補充~ )

1. 判斷網頁的host是否完全變了

由於連線了需認證WIFI後,通過瀏覽器訪問任何網頁都會得到Captive Portal頁面,所以對於iOS應用,一個比較簡單的檢測方法是用WKWebView載入某一個網頁,在decidePolicyForNavigationAction代理方法裡,拿到navigationAction.request.URL看host是不是完全變了,如果完全變了即可判斷當前WIFI需要認證。

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    decisionHandler(WKNavigationActionPolicyAllow);
    
    self.trueUrl = navigationAction.request.URL;
    if (self.openTestMode) {
        // 測試用 這個url是上海花生地鐵wifi的認證頁,連上上海花生地鐵wifi後,未認證時訪問所有網頁都會被重定向到該地址
        self.trueUrl= [NSURL URLWithString:@"http://portal.wifi8.com/wifiapp"];
    }
    if ([self.trueUrl.host containsString:@"baidu.com"]) {
        if (_networkCheckComplection) {
            _networkCheckComplection(NO);
            _networkCheckComplection = nil;
        }
    } else { // 網頁被重定向到了self.trueUrl,wifi需要認證
        if (_networkCheckComplection) {
            _networkCheckComplection(YES);
            _networkCheckComplection = nil;
        }
        
        if (_needAlert) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"WI-FI認證提醒" message:@"檢測到當前WI-FI需要認證才能使用,請嘗試去認證網路" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"認證", nil];
            [alert show];
            _needAlert = NO;
        }
    }
}

Android端的檢測也可以採用這樣的方式,具體可參看google的文件:https://developer.android.com/reference/java/net/HttpURLConnection.html ,其中提到的判斷機制如下:

圖片.png

有一點需要注意的是,判斷host完全相等不是特別合適,比如在WKWebView裡訪問http://www.baidu.com ,可能會被重定向到http://m.baidu.com ,這樣則不屬於WIFI需要認證的情況。

2. 訪問特定網頁,判斷HTTP狀態碼

也可以通過判斷HTTP狀態碼的方式來檢測Captive Portal。比如訪問google提供的一個空白網頁http://clients1.google.com/generate_204 ,如果返回的HTTP狀態碼是204,則可判斷當前網路無需認證,否則需要提醒使用者認證網路。

詳細可參看:
關於Android的captive portal

檢測Captive Portal的iOS版Demo

基於判斷host的方式,我寫了一個檢測Captive Portal的小Demo放在了github,其中用於Captive Portal檢測的工具類是CaptivePortalCheck,沒有任何外部依賴,即拿即用,歡迎嘗試~

文中內容如有不對,歡迎指正~

貼上圖片3.png


相關文章