一、公共WIFI综述
现在很多公司都在做免费WIFI,车站、公交、地铁、餐厅,只要是人员密集流动的地方就有WIFI,免费WIFI从最初的网页认证方式也逐渐向客户端认证方式偏移。本文主要讨论IOS认证上网的解决方案。
IOS端WIFI应用的相关开发,主要存在以下问题
1.IOS系统WIFI相关的接口很少,大部分接口都是私有接口
2.在设备连接上WIFI,没有通过路由器认证前,如果关闭IOS自动弹出的Portal页面,Iphone的WIFI会自动断开
3.如何禁止IOS系统自动弹Portal页面
4.公共WIFI的名称确定及不确定时的处理办法
本文主要讨论在使用公开的API,即可以提交到App Store的应用。
二、基础信息获取
1.获取网卡IP
<code class="language-ruby hljs " style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-color: transparent !important;">
+ (<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *)localIPAddress
{
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *localIP = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>;
struct ifaddrs *addrs;
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (getifaddrs(&addrs)==<span class="hljs-number" style="box-sizing: border-box; color: rgb(0, 136, 0);">0</span>) {
const struct ifaddrs *cursor = addrs;
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">while</span> (cursor != <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NULL</span>) {
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (cursor->ifa_addr->sa_family == <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">AF_INET</span> && (cursor->ifa_flags & <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">IFF_LOOPBACK</span>) == <span class="hljs-number" style="box-sizing: border-box; color: rgb(0, 136, 0);">0</span>)
{
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *name = [<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> <span class="hljs-symbol" style="box-sizing: border-box;">stringWithUTF8String:</span>cursor->ifa_name];
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> ([name <span class="hljs-symbol" style="box-sizing: border-box;">isEqualToString:</span>@<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"en0"</span>])
{
localIP = [<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> <span class="hljs-symbol" style="box-sizing: border-box;">stringWithUTF8String:</span>inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)];
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">break</span>;
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> localIP;
}</code>
2.获取网卡信息
<code class="language-ruby hljs " style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-color: transparent !important;">- (<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSDictionary</span> *)getWIFIDic
{
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFArrayRef</span> myArray = <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CNCopySupportedInterfaces</span>();
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (myArray != <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>) {
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFDictionaryRef</span> myDict = <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CNCopyCurrentNetworkInfo</span>(<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFArrayGetValueAtIndex</span>(myArray, <span class="hljs-number" style="box-sizing: border-box; color: rgb(0, 136, 0);">0</span>));
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (myDict != <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>) {
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSDictionary</span> *dic = (<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSDictionary</span>*)<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFBridgingRelease</span>(myDict);
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> dic;
}
}
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>;
}
- (<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *)getBSSID
{
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSDictionary</span> *dic = [<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">self</span> getWIFIDic];
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (dic == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>) {
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>;
}
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> dic[@<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"BSSID"</span>];
}
- (<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *)getSSID
{
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSDictionary</span> *dic = [<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">self</span> getWIFIDic];
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (dic == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>) {
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">nil</span>;
}
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> dic[@<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"SSID"</span>];
}
</code>
注意事项
在实际测试时,获取网卡信息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,方法如下:
<code class="language-ruby hljs " style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-color: transparent !important;">
- (void)<span class="hljs-symbol" style="box-sizing: border-box;">registerNetwork:</span>(<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *)ssid
{
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSString</span> *values[] = {ssid};
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFArrayRef</span> arrayRef = <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFArrayCreate</span>(kCFAllocatorDefault,(void *)values,
(<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFIndex</span>)<span class="hljs-number" style="box-sizing: border-box; color: rgb(0, 136, 0);">1</span>, &kCFTypeArrayCallBacks);
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span>( <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CNSetSupportedSSIDs</span>(arrayRef)) {
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSArray</span> *ifs = (__bridge_transfer id)<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CNCopySupportedInterfaces</span>();
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CNMarkPortalOnline</span>((__bridge <span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">CFStringRef</span>)(ifs[<span class="hljs-number" style="box-sizing: border-box; color: rgb(0, 136, 0);">0</span>]));
<span class="hljs-constant" style="box-sizing: border-box; color: rgb(136, 0, 0);">NSLog</span>(@<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"%@"</span>, ifs);
}
}
</code>
四、总结
苹果对于WIFI这块公开的API非常少,在开发公共WIFI应用时会遇到各种问题,上面是在使用非私有API的一些解决方案,如果大家有更优的办法,欢迎留言分享。如果公司有企业账号可以通过调用私有API的办法来处理大部分需求。
苹果iOS设备公共WiFi应用开发解决方案
本文讨论了iOS端WiFi应用的相关开发,包括获取网卡信息、认证过程中的问题解决,如禁止Portal禁止弹出与WIFI自动关闭的问题,以及WIFI名确定的解决方法。提供了针对这些问题的解决方案,并分享了在实际测试时的注意事项。
1784

被折叠的 条评论
为什么被折叠?



