前戏

苹果iOS 14针对本地局域做了一些权限限制,详情见链接:developer.apple.com/videos/play…

wwdc翻译过来凑字数的

什么是本地网络?

这里的本地网络其实就是我们常说的局域网,是将设备接入路由器以后形成的网络,设备可以通过这张网络互相通信,如我们的设备发现、设备绑定、局域网优先等功能都是使用的本地网络。

从 iOS 13 开始,应用想要获得当前连接到的 Wi-Fi 名称,那就必须要获得定位权限。因为通过识别 Wi-Fi 名称, 应用就能轻松地在你和周围的人之间建立大数据网络。但是不给定位权限不代表应用就没有办法跟踪你了,因为应用可以通过本地网络里的设备进行跟踪。

为什么需要向用户申请权限?

和iOS 13获取WiFi名称需要通过定位权限类似,苹果加强了对用户隐私安全权限,这里也是类似的问题。在过去的 iOS 版本中,应用可以随意扫描本地网络中的设备,因此应用就可以很轻松地得到本地网络里所有设备的名称和 MAC 地址。MAC 地址是一种确认网络设备位置的地址,每个网卡都有一个唯一的 MAC 地址,加上 MAC 地址也具有唯一性,设备厂商会按照一定的规律分配 MAC,所以不同的局域网都是独一无二可以识别的。比方说,你从线下渠道买了个新相机,拍完照片利用相机自带的 Wi-Fi 将照片导入到手机上。这时候带有某个推广模块的应用对局域网发起了一次扫描,识别到了一个新的设备,推广模块会将相机的 MAC 地址上传了云端,进行简单的识别对比以后,很容易知道这个 MAC 地址属于相机。这样带有推广模块的应用都会在画像里给你加上「相机用户」这样的标签,当你下次打开带有同一个推广模块的购物应用时,你就会看到推荐了一堆和相机有关的东西。

那些应用需要使用本地网络?

  • 利用本地网络进行设备发现
  • 利用本地网络进行数据传输
  • 网络调试工具

影响范围

主要影响无法使用Socket或者Bonjour做一些局域网的发现,数据传输。

对局域网应用如:智能家居类,局域网游戏,网络测试工具等等。本人测试了下其实也没有那么大,因为发现这个开关,App下次启动后可能不会生效,暂时未定位原因。

怎么解决?

相信很多人都很奇怪为什么不整个权限申请或状态查询的接口,在翻了一些资料后发现,居然真的没有。 链接:developer.apple.com/forums/tags…

很无奈!

大部分应用使用局域一般使用Socket或者Bonjour做一些局域的发现,数据传输。说在调用的时候会出现code:65 desc:no route to host。这是其实就是所谓的无本地网络权限。但是我在测试时发现有时候即使是关掉本地网络权限的开关,也能正常的使用UDP、TCP。简直不敢信!难道iOS 14也会想iOS 13一开始出来一样各种坑满天飞?

这里的思路是

  • 通过接口获取本机的IP地址
  • 使用(SimplePing)来ping手机的IP

整个流程的大概耗时在0.13-0.2秒之间,大部分在0.17秒左右。可能耗时还能接受。但是不知道某些路由器是否可以设置禁止ping。如果有那就炸裂了。 下面上简单的代码

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSDictionary *router = [LDSRouterInfo getRouterInfo];
    pinger = [[SimplePing alloc] initWithHostName:router[@"ip"]];
    pinger.delegate = self;
    [self->pinger start];
    
}
- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address {
    if (timer) {
        return;
    }
    timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        [pinger sendPingWithData:nil];
    });
    dispatch_resume(timer);
}

- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber {
    NSLog(@"可以使用局域网");
}

- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error {
    if (error.code == 65) {//no route to host
        NSLog(@"不可以使用局域网");
    }
} 复制代码

友情提示

  • 调上面接口可以触发首次启动本地网络权限的系统弹窗
  • 不知道某些路由器是否可以设置禁止ping
  • 整理流程在iPhone 6sp耗时130-200毫秒之间。平均值在160毫秒左右
  • 上面代码未正式上线,本人也在测试中,请酌情使用。

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:642363427,不管你是大牛还是小白都欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!