iOS 9.0 搜索附近Wi-Fi热点

好多人问怎么申请的就附上申请权限的邮件

申请邮件(点我跳转)

需求描述:
搜索附近的可用WIFI列表信息,包括信号强度,Mac地址

首先确定一点,要搜索附近的WIFI热点,这个功能肯定可用去实现的。

不过要去实现首先要去苹果申请一个权限

>>申请链接<<

申请页面

实现效果

实现效果
WiFi列表

创建项目

首先创建一个项目,然后对项目进行一些简单的设置:
打开Wireless Accessory Configuration这个功能(其实打开后Xcode会联网在developer网站上创建一堆的东东,我懒,所以我让Xcode帮我创建,APP IDs里面就能找到,包括描述文件,后面会讲)


项目设置

这个就是Xcode帮我自动创建的,可以看到刚才打开的功能已经开启了


Xcode自动创建

描述文件(.mobileprovision文件)

mobileprovision是要自己手动生成的,里面有一个很重要的一点就是你要先去苹果申请一个扩展权利的权限然后在把这个权利添加到描述文件里面去

创建一个描述文件


第一步

针对哪个APP的描述文件

第二步

开发者账号


第三步

需要调试的设备


第四步

然后需要添加一个Network Extension的扩展,这步很重要,需要提前申请权限

第五步

检查描述文件权利是否设置成功

创建好描述文件后可以通过命令检查权利是否添加到描述文件中去
命令在终端输入

security cms -D -i (描述文件路径)

Note:创建完成描述文件后可以手动下载下来

输出内容

这个会输出很多东西出来,我挑重要的贴出来,注意查找Entitlements这个关键词

<key>Entitlements</key>
 <dict>
  <key>keychain-access-groups</key>
  <array>
   <string>4CA5EU4K6J.*</string>  
   <string>com.apple.managed.vpn.shared</string>
  </array>
  <key>get-task-allow</key>
  <true/>
  <key>application-identifier</key>
  <string>4CA5EU4K6J.com.darren.project.app.NetworkExtensionTest</string>
  <key>com.apple.developer.team-identifier</key>
  <string>4CA5EU4K6J</string>
  <key>com.apple.external-accessory.wireless-configuration</key>
  <true/>
  <key>com.apple.developer.networking.networkextension</key>
  <array>
   <string>packet-tunnel-provider</string>
   <string>app-proxy-provider</string>
   <string>content-filter-provider</string>
  </array>
  <key>com.apple.developer.networking.HotspotHelper</key>
  <true/>
 </dict>

然后查找com.apple.developer.networking.HotspotHelper权利,如果有就说明OK

<key>com.apple.external-accessory.wireless-configuration</key> 
<true/>

开始使用HotspotHelper吧

到这描述文件应该创建的妥妥了,然后先去把描述文件搞到Xcode里面去

打开Xcode的配置:Xcode->Preferences...->Accounts->(选中你的开发者ID)->View Details...

项目配置
下载全部的描述文件(这里的描述文件和developer网站上面的是对应的)
描述文件下载

接下来还是配置,在查看HotspotHelper的官方API中有两个地方需要注意的

WARNING
The application's Info.plist must include a UIBackgroundModes array containing network-authentication.

WARNING
The application must set com.apple.developer.networking.HotspotHelper as one of its entitlements. The value of the entitlement is a boolean set to true.

意思就是说要使用这个API首先需要满足这两个条件:
1.要在Info.plist文件中添加一个key-value键值对

<key>UIBackgroundModes</key>
<array>
   <string>network-authentication</string>
</array>

Note:添加这个键值对后在项目Capabilities标签下面的Background Modes功能会自动打开

2.需要将com.apple.developer.networking.HotspotHelper 作为权利之一(因为一个app里面可以包含多个权利),也就是说app生成后通过上面的codesign命令检查app是否已经包含了该权利,并且他的值是true。

<key>com.apple.developer.networking.HotspotHelper</key>
<true/>

接下来就是干货了,直接上代码

NSMutableDictionary* options = [[NSMutableDictionary alloc] init];
    [options setObject:@"我叫谷子就是这么屌" forKey:kNEHotspotHelperOptionDisplayName];
    dispatch_queue_t queue = dispatch_queue_create("com.myapp.ex", NULL);
    //注册成功会返回一个Yes值,否则No
    BOOL returnType = [NEHotspotHelper registerWithOptions:options queue:queue handler: ^(NEHotspotHelperCommand * cmd) {
        NEHotspotNetwork* network;
        if (cmd.commandType == kNEHotspotHelperCommandTypeEvaluate || cmd.commandType ==kNEHotspotHelperCommandTypeFilterScanList) {
            for (network  in cmd.networkList) {
                NSLog(@"COMMAND TYPE After:   %ld", (long)cmd.commandType);
                NSLog(@"SSID-> %@ Mac地址-> %@ 信号强度-> %f",network.SSID,network.BSSID,network.signalStrength);
                if ([network.SSID isEqualToString:@"免费WiFi"]) {
                    double signalStrength = network.signalStrength;
                    NSLog(@"Signal Strength: %f", signalStrength);
                    [network setConfidence:kNEHotspotHelperConfidenceHigh];
                    [network setPassword:@"xxxxxxx"];
                    NEHotspotHelperResponse *response = [cmd createResponse:kNEHotspotHelperResultSuccess];
                    NSLog(@"Response CMD %@", response);
                    [response setNetworkList:@[network]];
                    [response setNetwork:network];
                    [response deliver];
                }
            }
        }
    }];

Note:需要注意的就是NEHotspotHelper提供的API里面没有主动获取WiFi列表的方法,只有一个回调方法来处理WiFi信息,也就是说这个回调什么时候执行是由系统决定的,你只能等着接收,首先你要保证注册成功,returnType等于Yes

附近WiFi列表
//Mac地址后面的*是我手动改的,请忽略
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] SSID-> 候大胡同 Mac地址-> bc:46:99:13:38:* 信号强度-> 0.246163
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] SSID-> Prestige Mac地址-> 1c:fa:68:eb:71:* 信号强度-> 0.246163
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] SSID-> MERCURY_B1232A Mac地址-> 9c:21:6a:b1:23:* 信号强度-> 0.278197
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.659 NetworkExtensionTest[3560:2083262] SSID-> TP-LINK_702 Mac地址-> 14:e6:e4:6b:50:* 信号强度-> 0.295640
2016-06-02 10:56:03.660 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.660 NetworkExtensionTest[3560:2083262] SSID-> TP-LINK_29E898 Mac地址-> 9c:21:6a:29:e8:* 信号强度-> 0.295640
2016-06-02 10:56:03.660 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.660 NetworkExtensionTest[3560:2083262] SSID-> cai Mac地址-> 8:10:79:9e:ce:* 信号强度-> 0.314027
2016-06-02 10:56:03.660 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.661 NetworkExtensionTest[3560:2083262] SSID-> 360WiFi-9E1ED3 Mac地址-> a4:56:2:9e:1e:* 信号强度-> 0.314027
2016-06-02 10:56:03.661 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.661 NetworkExtensionTest[3560:2083262] SSID-> CAYNE Mac地址-> 9c:21:6a:ff:b3:* 信号强度-> 0.418605
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] SSID-> zyfkilik Mac地址-> 40:16:7e:32:e7:* 信号强度-> 0.418605
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] SSID-> ChinaNet-9xrH Mac地址-> c4:c7:55:58:ec:* 信号强度-> 0.441479
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] SSID-> xiaoxiao Mac地址-> a8:15:4d:f7:7b:* 信号强度-> 0.511782
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] SSID-> ChinaNet-QTkm Mac地址-> 18:44:e6:75:c0:* 信号强度-> 0.625487
2016-06-02 10:56:03.662 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.663 NetworkExtensionTest[3560:2083262] SSID-> TP-LINK_7362 Mac地址-> 88:25:93:37:73:* 信号强度-> 0.625487
2016-06-02 10:56:03.663 NetworkExtensionTest[3560:2083262] COMMAND TYPE After:   1
2016-06-02 10:56:03.663 NetworkExtensionTest[3560:2083262] SSID-> 免费WiFi Mac地址-> a4:56:2:42:42:* 信号强度-> 0.932293
2016-06-02 10:56:03.663 NetworkExtensionTest[3560:2083262] Signal Strength: 0.932293

错误排查

检查app是否包含该项权利

codesign -d --ent :- (app路径)

输出内容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>application-identifier</key>
 <string>4CA5EU4K6J.com.darren.project.app.NetworkExtensionTest</string>
  //重点看下面这行
 <key>com.apple.developer.networking.HotspotHelper</key>
 <true/>
 <key>com.apple.developer.networking.networkextension</key>
 <array>
  <string>packet-tunnel-provider</string>
  <string>app-proxy-provider</string>
  <string>content-filter-provider</string>
 </array>
 <key>com.apple.developer.team-identifier</key>
 <string>4CA5EU4K6J</string>
 <key>com.apple.external-accessory.wireless-configuration</key>
 <true/>
 <key>get-task-allow</key>
 <true/>
</dict>
</plist>

如果输出结果中没有找到com.apple.developer.networking.HotspotHelper这个字段,并且值等于true,那就从回到顶部,重新在来一边

总结

刚开始有这个需求的时候觉得就是获取附近WiFi列表,虽然没搞过就觉得没啥难度,然后就找了一下相关资料,在iOS9.0以前的版本里面使用CNCopySupportedInterfaces去获取,可是在9.0以后Apple把WiFi相关的API都改成HotspotHelper了,然后看了一下API文档发现这个功能还TM需要在申请一个权限,没办法那就搞呗,先是申请API权限被拒了6次,后面是API使用的时候配置问题,反正一步一坑(对描述文件这块不太了解)。
总之API的使用很简单,分为三个部分:
1.申请API权限
2.配置项目(配置有点烦,步骤多的吓人)
3.撸代码(代码实现)

关于NEHotspotHelper的API没有啥讲的,自己看看文档喽

ps:如果权限申请下来后,邮件里面都会有一个关于权限的配置连接,英文好的可以跟着走

官方配置连接(Entitlements Troubleshooting)

权利调试问题(Debugging Entitlement Issues)

附件:

官方权利配置流程图

参考资料:

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/Hotspot_Network_Subsystem_Guide/Contents/Introduction.html#//apple_ref/doc/uid/TP40016639
https://developer.apple.com/library/ios/documentation/NetworkExtension/Reference/Network_Extension_Framework_Reference/index.html#//apple_ref/doc/uid/TP40016234
https://forums.developer.apple.com/thread/9015
https://forums.developer.apple.com/thread/11977
https://forums.developer.apple.com/thread/4906
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/Hotspot_Network_Subsystem_Guide/Contents/Introduction.html#//apple_ref/doc/uid/TP40016639-CH1-SW1
https://developer.apple.com/library/ios/documentation/NetworkExtension/Reference/Network_Extension_Framework_Reference/index.html#//apple_ref/doc/uid/TP40016234
http://www.jianshu.com/p/aa6219925c2e
http://www.jianshu.com/p/4c0a9792d82c

吃水不往挖井人非常感谢(奶油血滴子 or 经年不醉)的无私帮助

啦啦啦,就酱紫吧......(如需人工帮助请按0)

推荐阅读更多精彩内容