現在很多公司都在做免費WIFI,車站、公交、地鐵、餐廳,只要是人員密集流動的地方就有WIFI,免費WIFI從最初的網頁認證方式也逐漸向客戶端認證方式偏移。本文主要討論IOS認證上網的解決方案。IOS端WIFI應用的相關開發,主要存在以下問題
1.IOS系統WIFI相關的接口很少,大部分接口都是私有接口
2.在設備連接上WIFI,沒有通過路由器認證前,如果關閉IOS自動彈出的Portal頁面,Iphone的WIFI會自動斷開
3.如何禁止IOS系統自動彈Portal頁面
4.公共WIFI的名稱確定及不確定時的處理辦法
本文主要討論在使用公開的API,即可以提交到App Store的應用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
+ (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;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
- (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信息,初使化界面。異步線程獲取到真實的配置信息後,再重新更新界面。
正常情況,用戶使用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頁面。
如果公司部署的公共WIFI名確定的情況,就比較簡單了,不需要配置上述白名單也可以保證WIFI不斷開,具體辦法是,在程序啟動時,向IOS系統注冊SSID,方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
- (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的辦法來處理大部分需求。