現在很多公司都在做免費WIFI,車站、公交、地鐵、餐廳,只要是人員密集流動的地方就有WIFI,免費WIFI從最初的網頁認證方式也逐漸向客戶端認證方式偏移。本文主要討論iOS認證上網的解決方案。
iOS端WIFI應用的相關開發,主要存在以下問題:
iOS系統WIFI相關的接口很少,大部分接口都是私有接口
在設備連接上WIFI,沒有通過路由器認證前,如果關閉iOS自動彈出的Portal頁面,iPhone的WIFI會自動斷開
如何禁止iOS系統自動彈Portal頁面
公共WIFI的名稱確定及不確定時的處理辦法
本文主要討論在使用公開的API,即可以提交到App Store的應用。
1. 獲取網卡IP
+ (NSString *)localIPAddress { NSString *localIP = nil; struct ifaddrs *addrs; if (getifaddrs(&addrs)==0) { const struct ifaddrs *cursor = addrs; while (cursor != NULL) { if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0) { NSString *name = [NSString stringWithUTF8String:cursor->ifa_name]; if ([name isEqualToString:@"en0"]) // Wi-Fi adapter { localIP = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)]; break; } } cursor = cursor->ifa_next; } freeifaddrs(addrs); } return localIP; }
2. 獲取網卡信息
- (NSDictionary *)getWIFIDic { CFArrayRef myArray = CNCopySupportedInterfaces(); if (myArray != nil) { CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0)); if (myDict != nil) { NSDictionary *dic = (NSDictionary*)CFBridgingRelease(myDict); return dic; } } return nil; } - (NSString *)getBSSID { NSDictionary *dic = [self getWIFIDic]; if (dic == nil) { return nil; } return dic[@"BSSID"]; } - (NSString *)getSSID { NSDictionary *dic = [self getWIFIDic]; if (dic == nil) { return nil; } return dic[@"SSID"]; }
**注意事項**
在實際測試時,獲取網卡信息**getWIFIDic**方法,在部分路由器上耗時很長(10秒以上),如果直接放在主線程中,會導致界面卡死。在認證相關的應用中,會根據網卡上的BSSID(例如:以特定3d:e6:c3開頭的即為本公司架設網絡)來判斷是否屬於本公司的路由。SSID、BSSID若為應用啟動時必須獲取的信息(我們公司的應用,就是這種),這個時候怎樣處理呢?
放在異步線程,獲取到網卡信息再初使化界面,這種方法依然會導致在某些路由器下初次打開界面超長時間的等待,我們的處理方法是,如果3秒內能夠獲取到相應的配置信息,直接根據配置信息初使化界面,在超過3秒時,給予默認的假WIFI信息,初使化界面。異步線程獲取到真實的配置信息後,再重新更新界面。
1. Portal禁止彈出與WIFI自動關閉的問題
正常情況,用戶使用iPhone手機連接帶有Portal認證的路由器,在連接成功後,iOS系統會在已有列表中隨機選擇連接指定的網址(例如:www.itools.info)以測試當前路由器是否需要Portal認證。在需要Portal認證的網絡,系統會彈出Portal頁面,這個時候,如果用關掉portal頁面,或者直接切換到其它應用,WIFI網絡會直接自動斷開(根本不給客戶端認證機會^_^)。
我們的解決辦法是路由器白名單,讓路由器放行所有Portal測試的IP,以下為測試的域名:
www.appleiphonecell.com captive.apple.com www.itools.info www.ibook.info www.airport.us www.thinkdifferent.us
對應的IP地址:
23.207.103.91 23.33.54.18 23.44.167.91 23.67.183.91 96.7.103.91 23.42.71.91 23.34.105.211 23.59.167.91 23.42.184.50 23.47.232.190 23.77.23.91 23.194.87.91 23.61.91.190 23.218.12.50 23.2.38.95 23.46.135.91 172.225.213.179 218.205.66.94 23.64.251.249 23.58.250.189
將以上所有IP加到路由器的白名單中,即可解決iPhone斷開WIFI的問題,但是同時也不自動彈出Portal頁面了,用戶打開浏覽器才會重定向到Portal頁面。
2. WIFI名確定解決方法
如果公司部署的公共WIFI名確定的情況,就比較簡單了,不需要配置上述白名單也可以保證WIFI不斷開,具體辦法是,在程序啟動時,向iOS系統注冊SSID,方法如下:
- (void)registerNetwork:(NSString *)ssid { NSString *values[] = {ssid}; CFArrayRef arrayRef = CFArrayCreate(kCFAllocatorDefault,(void *)values, (CFIndex)1, &kCFTypeArrayCallBacks); if( CNSetSupportedSSIDs(arrayRef)) { NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces(); CNMarkPortalOnline((__bridge CFStringRef)(ifs[0])); NSLog(@"%@", ifs); } }
蘋果對於WIFI這塊公開的API非常少,在開發公共WIFI應用時會遇到各種問題,上面是在使用非私有API的一些解決方案,如果大家有更優的辦法,歡迎留言分享。如果公司有企業賬號可以通過調用私有API的辦法來處理大部分需求。
原文地址:一葉博客