在iOS 12+上检测Internet访问

我最近写了一篇有关iOS如何在显示允许用户登录或注册的Web视图之前如何检测连接到新Wi-Fi网络的强制门户的文章。 对于大多数在酒店,酒吧或咖啡厅等处连接到公共Wi-Fi网络的人来说,这种情况很熟悉。如果您还不了解其工作原理,请 在iOS上解决强制门户问题 提供了这篇文章的有用背景。

多年来,Apple的Reachability示例代码一直被用作检测第三方iOS应用程序中网络访问的实际起点。 在Cocoapods.org上进行的快速搜索将显示一长串库,这些库重写了此代码时考虑了许多因素,例如ARC支持或Swift兼容性。

WWDC在2018年6月推出了从iOS 12起可用的Network框架,其中包括NWPathMonitor类。 此类为我们提供了一种监控网络状态变化的方法,而不必包含第三方库/ Apple示例代码。

为了利用NWPathMonitor类,只需导入Network框架,然后创建一个NWPathMonitor实例:

 让监视器= NWPathMonitor() 

如果仅对特定网络适配器(例如Wi-Fi)中的状态更改感兴趣,则可以使用init(requiredInterfaceType:)初始化程序并提供NWInterface.InterfaceType作为实例来指定要监视实例化NWPathMonitor对象的网络适配器。参数例如

 让监视器= NWPathMonitor(requiredInterfaceType:.wifi) 

您需要确保在某个地方保留对该对象的引用(例如使用强属性),否则您可能会发现,当ARC释放NWPathMonitor对象时,分配给您的回调将停止调用。

可以监视的接口类型包括:

  • cellular
  • loopback
  • other (针对虚拟或不确定网络类型)
  • wifi
  • wiredEthernet

要通知状态更改,您需要为pathUpdateHandler属性分配一个回调,只要网络接口中发生状态更改(例如,您的电话从蜂窝网络移动到Wi-Fi网络),就会调用该回调。 然后,无论何时发生状态更改,都会返回一个NWPath实例,可以查询该实例以确定我们是否已连接,如下所示:

  monitor.pathUpdateHandler = { 
如果path.status == .satisfied {
打印(“已连接”)
}
}

使用无参数初始化程序与使用指定网络适配器的初始化程序会影响是否satisfied.返回的NWPath对象的status属性satisfied. 例如,如果您选择监视蜂窝网络适配器,但是Wi-Fi适配器发生状态更改(例如,您的电话连接到Wi-Fi网络),则您的回调将不会被调用,并且路径的状态将unsatisfied (可以使用currentPath属性随时访问NWPathMonitor的路径),因为未使用指定的接口连接设备。 因此,如果您只是想知道是否存在连接,无论是Wi-Fi还是蜂窝网络,那么最好坚持使用无参数初始化器。

有趣的是-虽然NWPath对象是iOS 12中作为Network框架的一部分而新增的,但实际上,自iOS 9起, NWPath对象已作为NWPath一部分使用(有一些细微差别)。

可以查询返回的NWPath对象,以了解有关设备网络适配器状态的大量信息。 更有趣的属性之一是isExpensive ,它返回是否认为网络接口使用昂贵(例如,蜂窝数据计划)昂贵。 我们还可以找出该路径是否支持DNS,IPv4或IPv6。 如果我们需要找出哪个接口更改了状态并触发了回调,则可以调用usesInterfaceType方法:

  let isCellular:Bool = path.usesInterfaceType(.cellular) 

使用NWPathMonitor与使用其他iOS API(例如CLLocationManager )有点相似,因为我们需要调用start方法以开始接收更新,然后在完成后调用stop对应项。 NWPathMonitorstart方法要求我们为对象提供一个队列以执行其工作:

  let queue = DispatchQueue.global(qos:.background)monitor.start(队列:队列) 

监视完状态变化后,我们只需在其上调用cancel() 。 请注意,目前,一旦我们在NWPathMonitor上调用了cancel ,就无法再次启动它。 相反,我们需要实例化一个新的NWPathMonitor实例。

请注意,如果在调用start之前访问NWPathMonitorcurrentPath属性,则该属性将为nil 。 实际上,如果您打印返回到更新闭包的路径,如下所示:

  monitor.pathUpdateHandler = { 
打印(路径)
}

然后将打印如下内容:

 可选(满意(满足路径要求),界面:en0,范围,ipv4,ipv6,dns) 

这表明此处和currentPath属性返回的NWPath是可选的,尽管API并未这样指出(我们可以推断返回的NWPath引用是桥接到Swift的Objective-C指针)。

强制门户是在连接到公共Wi-Fi热点时显示的网页,通常用于在授予Internet访问(或访问其他网络资源)之前强制登录,注册或付款。 在上一篇博客文章中,我写了一篇关于从应用程序开发人员使用Reachability的角度来看,它看起来好像可以访问Internet的信息,实际上并不是因为服务于强制门户。 这可能导致应用程序无法正常运行甚至崩溃—可能是因为该应用程序希望从RESTful API获得一些JSON,但实际上却从强制门户收到了一些HTML。

NWPathMonitor知道NWPathMonitor是否在检测真正的Internet连接方面提高了ReachabilityNWPath.Status枚举确实提供了三种情况- satisfiedunsatisfiedNWPath.Status 。 不幸的是,如果我们看一下较旧的NWPathStatus框架,虽然开发人员文档并没有说明每种情况的用法,但原始的NWPathStatus对象提供了satisfiable的案例,其中确实包含一些文档:

该路径当前不满足,但是在尝试连接时可能变得满足。 这可能是由于未激活诸如VPN或蜂窝数据连接之类的服务所致。

在较早的NWPathStatus对象中, NWPathStatus情况似乎NWPathStatus

好消息是, NWPathMonitor通常仅在协商强制门户之后(即,在呈现Web视图并且用户登录之后)才报告该路径是可满足的。在没有强制门户向用户呈现操作表的地方提出了提供选项“ 不使用Internet使用其他网络” 。 如果用户选择使用不使用Internet,则即使没有Internet访问,也将satisfied NWPathMonitor返回的路径状态。

通过对Charles代理进行的一些试验,我发现除非选择“不使用Internet” ,否则在我阻止Wi-Fi网络初始连接时, NWPath不会正确地报告NWPathStatussatisfied 。 但是,如果恢复了Internet连接,但随后又将其断开了,则不会检测到该问题,并且路径状态也不会从“ satisfied更改为“ satisfied 。 例如,如果用户仅在火车或酒店上花了一个小时的互联网访问费用,就可能发生这种情况。

连接性是根据MIT许可提供的开放源代码框架,该框架致力于复制iOS固有的检测强制门户的方式。 它允许使用Reachability在iOS 8+上准确检测到真正的Internet连接,这意味着我们可以使用它来检测NWPathMonitor不可用以及在iOS 12上的Internet访问可用性,而在连接12时,可以使用Connectivity来提供更高的准确性单独使用NWPathMonitor

最近,对NWPathMonitor支持已添加到可使用iOS 12或更高版本的Connectivity中。 如果将framework属性设置为network则将使用新的Network框架代替SystemConfiguration框架( Reachability )来观察网络适配器中的状态更改。

 让连接=连接() 
Connectivity.framework = .network

在网络适配器中的状态更改之后,“连接性”执行许多检查以确定是否可以访问Internet。 提供了一个轮询选项,该选项可用于重新验证是否即使在没有发生状态更改的情况下,是否也如此频繁地访问Internet(如果需要)。 这可以通过设置isPollingEnabled = true并为pollingInterval以秒为单位指定适当的值来pollingInterval

Network框架引入了一些很棒的新类,其中包括NWPathMonitor ,可用于观察iOS 12及更高版本上设备的网络适配器中的状态变化。 在用户与强制门户进行了交互之后,它报告了一条satisfied的路径,但没有检测到随后失去的Internet访问。 连接性可用于为支持NWPathMonitor版本iOS的应用程序提供向后兼容性,并且比单独使用NWPathMonitor时具有更高的准确性。

优点

  • 苹果官方支持。
  • 无需包含第三方代码-只需在iOS 12中链接Network.framework
  • 在协商强制门户后,将NWPathStatus报告为“ satisfied

缺点

  • 无法在iOS 12之前使用,这意味着如果您需要支持iOS的早期版本,那么您会很不幸。
  • 缺少文档-例如,请参阅https://developer.apple.com/documentation/network/nwpathmonitor。
  • 无法检测到强制门户以及其他在最初成功建立连接后Internet连接断开的情况。

在MIT许可下, 可以在 GitHub上 找到开放源连接, 并且与 Cocoapods 和Carthage 兼容