解决iOS上的强制门户问题

在iOS开发中,检测Internet连接的实际方法是利用Apple的Reachability示例代码。 但是,“可达性”实际上无法检测是否存在连通性, 只是可以使用可能允许连接的接口

考虑一个应用程序用户使用公共Wi-Fi热点的情况,这要求用户在建立Internet连接(例如在您当地的星巴克分行)之前通过强制门户注册或同意服务条款。 该设备似乎已连接到Wi-Fi网络,但对数据的任何请求都将失败,直到用户同意Wi-Fi热点的服务条款或注册为新用户为止(取决于热点的要求)。 在这种情况下,可到达性将返回一个响应,指示即使实际上没有真正的Internet连接也可以使用Wi-Fi。

这可能会引起混乱,因为您的应用程序在连接到该热点时会表现为在线状态,因为可访问性检查将表明存在Wi-Fi连接。 同时,您的应用尝试从Internet检索数据的尝试将失败。 反过来,这可能会导致在App Store上的评论不佳。

那么,如何确保我们的应用程序具有真正的Internet连接? 事实证明,iOS已经可以解决此问题。

iOS采用了由无线宽带联盟发布的称为无线互联网服务提供商漫游(WISPr 2.0)的协议。 该协议定义了“智能客户端访问网关”接口,该接口描述了如何使用通用访问方法对访问公共IEEE 802.11(Wi-Fi)网络的用户进行身份验证,其中强制门户向用户显示登录页面。

然后,用户必须通过Web浏览器注册或提供登录凭据,才能使用RADIUS或其他提供集中式身份验证,授权和计费(AAA)的协议来授予对网络的访问权限。

为了检测到它已通过强制门户连接到Wi-Fi网络,iOS与Apple托管的许多端点进行了联系-例如https://www.apple.com/library/test/success.html。 。 每个端点都托管一个表单的小HTML页面:

   


成功


成功

如果在下载此HTML小页面时,iOS发现它包含如上所述的Success一词,则它知道Internet连接可用。 但是,如果强制性门户网站显示登录页面,则不会显示Success字样,iOS将意识到网络连接已被强制性门户网站劫持,并将显示一个浏览器窗口,允许用户登录或注册。

Apple托管了许多这样的页面,因此如果其中一个页面出现故障,可以检查许多后备以确定是否存在连接或是否存在强制门户网站阻止了我们的连接。 不幸的是,iOS没有向开发人员公开任何框架,这使我们无法利用操作系统对强制门户的了解。

连接是MIT许可下可用的开放源代码框架,该框架包装了Reachability,并努力复制iOS检测强制门户的方法。 当“可达性”检测到Wi-Fi或WWAN连接时,“连接性”会与许多终结点联系,以确定是否存在真正的Internet连接,或者俘虏门户是否正在拦截连接。 此方法还可用于确定iOS设备是否连接到无法访问Internet的Wi-Fi路由器。

连接性提供了一个尽可能接近可到达性的接口,以便习惯使用可到达性的开发人员熟悉它。 这包括提供方法startNotifier()stopNotifier()来开始检查Internet连接的更改。 通知程序启动后,您可以使用status属性(类似于Reachability的currentReachabilityStatus )同步查询当前的连接状态,也可以通过向默认NotificationCenter注册观察者kNetworkConnectivityChangedNotification通知来异步查询当前的连接状态(在Swift中,可以通过Notification.Name.ConnectivityDidChange访问Notification.Name.ConnectivityDidChange )-与可达性通知kNetworkReachabilityChangedNotification相似。

默认情况下,Connectivity与iOS已使用的许多端点进行联系,但建议通过附加到connectivityURLs属性,由开发人员托管的端点来补充这些端点。 通过设置successThreshold属性,可以进一步进行自定义,该属性确定已联系端点的百分比,必须得出成功检查才能得出存在连接的结论。 缺省值指定所联系的URL的75%必须成功完成连接检查。

要开始使用Connectivity,只需实例化一个实例,并指定一个在Connectivity检测到您已连接到Internet,断开连接时或在以下两种情况下调用的闭包即可:

 让连通性:Connectivity = Connectivity()let ConnectivityChanged:(Connectivity)-> Void = { 
self?.updateConnectionStatus(connectivity.status)
} connectivity.whenConnected = ConnectivityChanged
Connectivity.whenDisconnected = ConnectivityChangedfunc updateConnectionStatus(_ status:Connectivity.ConnectivityStatus){开关状态{
case .connectedViaWiFi:
case.connectedViaWiFiWithoutInternet:
case .connectedViaWWAN:
case.connectedViaWWAN没有互联网:
case .notConnected:
}

}

然后开始监听连接性呼叫中的更改:

  Connectivity.startNotifier() 

完成后,请记住调用connectivity.stopNotifier()

有时,您只想一次性检查连接状态。 为此,实例化一个Connectivity对象,然后检查status属性,如下所示:

  let Connectivity = Connectivity()switch Connectivity.status {case .connectedViaWiFi: 

case.connectedViaWiFiWithoutInternet:

case .connectedViaWWAN:

case.connectedViaWWAN没有互联网:

case .notConnected:

}

或者,如果您仅对某些类型的连接感兴趣,则可以直接检查Connectivity对象的以下属性:

  var isConnectedViaWWAN:Boolvar isConnectedViaWiFi:Bool 

var isConnectedViaWWAN不带Internet:Boolvar isConnectedViaWiFi不带Internet:Bool

在使用startNotifier()开始连接检查之前,可以通过Connectivity对象的Connectivity属性设置要用来检查连接性的URL。

  Connectivity.connectivityURLs = [URL(string:“ https://www.apple.com/library/test/success.html”)!] 

如果您更喜欢使用通知来观察连接性的变化,则可以在默认的NotificationCenter上添加一个观察器:

NotificationCenter.default.addObserver(_:selector:name:object:)

侦听Notification.Name.ConnectivityDidChange ,接收到的通知的object属性将包含Connectivity对象,您可以使用该对象来查询连接状态。

在某些情况下,可能需要不断了解连接状态的变化,因此可能希望启用轮询。 如果启用,“连接性”将不等待“可达性”状态的更改,而是每10秒轮询一次连接URL(此值是可配置的)。 将发出ConnectivityDidChange通知,并且仅在发生连接状态更改的情况下才调用whenConnected / whenDisconnected关闭。

要启用轮询:

  Connectivity.isPollingEnabled = true 
Connectivity.startNotifier()

从Connectivity 1.1.0开始,将HTTPS用作连接URL是默认设置。 如果您的应用未使用App Transport Security,并且希望使用HTTP URL和HTTPS URL,则在实例化Connectivity对象时,将shouldUseHTTPS设置为false或将shouldUseHTTPS设置为false ,如下所示:*:

 让连接=连接(shouldUseHTTPS:假) 

*请注意,如果您尚未在应用程序的Info.plist中首先设置NSAllowsArbitraryLoads标志,则不会设置该NSAllowsArbitraryLoads

若要设置被视为成功连接所需的成功连接数,请设置successThreshold属性。 该值指定为指示成功连接百分比的百分比,即,如果在connectivityURLs属性中设置了四个连接URL且指定了75%的阈值,则必须成功完成四项检查中的三项才能将我们的应用视为已连接:

  Connectivity.successThreshold = Connectivity.Percentage(75.0) 

连接性模仿了iOS检测强制门户的方法,并通过熟悉的界面向开发人员展示了此功能。 能够可靠地检测到更细微的情况,例如将iOS设备连接到没有Internet访问的Wi-Fi路由器,这使应用程序开发人员可以为用户提供更好的信息并开发更强大的在线功能。


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

如果您发现本文有趣,则后续文章“ 在iOS 12+上检测Internet访问” 介绍了如何使用iOS 12中引入的网络框架代替可到达性。