连接性 6.1.1

连接性 6.1.1

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布上次发布2023年9月
SPM支持 SPM

Ross Butler 维护。



连接性 6.1.1

  • 作者:
  • Ross Butler

Connectivity

Build Status Version Carthage compatible Maintainability License Twitter Reviewed by Hound

连接性是对Apple的Reachability的包装,提供了一种可靠的方式来衡量是否可以连接到互联网,而Reachability本身只能表示是否存在可能允许连接的接口。

连接性的目标是为了解决iOS设备连接到没有互联网连接的WiFi网络的问题(称为captive portal问题)。这种情况很常见,例如连接到需要用户注册后才能使用的公共WiFi网络。连接性可以检测这种情况,让您能够相应地做出反应。

要了解更多关于如何使用连接性的信息,请查看关键演示文稿、阅读博客文章,或查看下面的目录。

特性

  • 设备加入网络时检测captive portals。
  • 检测连接到没有互联网访问的路由器。
  • 通知互联网连接的变化。
  • 轮询连接性检查可以在需要恒定网络连接的地方执行(可选)。
  • 通过Connectivity.Publisher提供Combine支持。

Connectivity 6.0.0 新特性

  • 增加了设置用于访问端点时使用的授权头部的功能(感谢 Nils Bergmann - 参考 #73)。
  • iOS 基础部署目标更新到 iOS 11.0。

更多详情请见 CHANGELOG.md

超连接

如果您不需要支持 Objective-C 或 iOS 13 之前的 iOS 版本,则可能需要考虑使用 Hyperconnectivity(Connectivity 的分支项目),它删除了对这些的支持,以选择现代、优雅的语法。有关两个框架的比较,请参阅 此处


Hyperconnectivity logo

OpenConnectivity

Connectivity 和 Hyperconnectivity 都支持 Combine,但如果您在一个 Combine 不可用的环境中工作,例如支持 iOS 13 之前的版本,则可以使用 OpenCombine

OpenConnectivity 在 Connectivity 中扩展了一个与 OpenCombine 兼容的发布工具,以允许您在 Combine 本身不可用的环境中使用 Combine 语法。

安装

确保您包含了苹果的 Reachability 头文件和实现文件(Reachability.h 和 Reachability.m)以使用。

使用苹果的 Reachability 受到 苹果的许可协议约束。

Cocoapods

CocoaPods是一个将依赖集成到您Xcode工作区的依赖管理器。要使用Ruby gems安装它,请运行以下命令:

gem install cocoapods

要使用Cocoapods安装Connectivity,只需将以下行添加到您的Podfile中:

pod "Connectivity"

然后运行以下命令:

pod install

有关更多信息,请参见这里

Carthage

Carthage是一种可以在项目中手动集成的依赖管理器,它生成二进制文件。您可以使用以下命令通过Homebrew安装:

brew update
brew install carthage

要使用Carthage将Connectivity集成到您的项目中,请将以下行添加到项目的Cartfile中:

github "rwbutler/Connectivity"

在macOS Terminal中运行 carthage update --platform iOS 以构建框架,然后拖动Connectivity.framework到您的Xcode项目中。

有关更多信息,请参见这里

Swift Package Manager

Xcode 11支持Swift Package Manager。要在Xcode 11中将Connectivity添加到项目中,请在文件菜单中选择Swift Packages,然后选择添加Package依赖

将提示输入包仓库URL,它是:

https://github.com/rwbutler/connectivity

验证URL后,Xcode会提示您选择是否将特定分支、提交或版本释放拉入项目。

Xcode 11 Package Options

继续下一步,在那里您将被要求选择要将包产品集成到目标中的包。将有一个名为Connectivity的单个包产品,应预先选中。确保您的应用程序目标已从对话框最右侧的列中选择,然后单击“完成”以完成集成。

Xcode 11 Add Package

它的工作原理

iOS采用了一个由无线宽带联盟(Wireless Broadband Alliance,https://www.wballiance.com/)发布的协议——无线互联网服务提供商漫游协议(WISPr 2.0,https://www.wballiance.com/glossary/),它定义了智能客户端通过接入网关( Αν_DIRECTORY access gateway)接口,描述了如何使用通用访问方法对用户进行认证,通用访问方法中,门户网关(captive portal)向用户提供登录页面。

用户必须通过网页浏览器注册或提供登录凭据,以便使用RADIUS或其他提供集中认证、授权和计帐(AAA,https://en.wikipedia.org/wiki/AAA_(computer_security))协议的方法来获取对网络的访问权限。

为了检测连接到具有门户网关的Wi-Fi网络,iOS与苹果提供的多个端点进行通信——例如https://www.apple.com/library/test/success.html。每个端点都托管一个小的HTML页面,其形式如下

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
	<TITLE>Success</TITLE>
</HEAD>
<BODY>
	Success
</BODY>
</HTML>

如果iOS在下载这个小HTML页面时发现它包含了上面提到的Success这个词,那么它就知道有互联网连接可用。然而,如果门户网关提供了一个登录页面,那么Success这个词将不会出现,iOS将会意识到网络连接被门户网关劫持了,并将打开一个浏览器窗口,允许用户登录或注册。

苹果托管了这些页面,以便如果其中任何一个页面失效,还可以通过检查多个替换方案来确定是否存在连接,或者我们的连接是否因为门户网关的存在而被阻止。不幸的是,iOS没有向开发者提供任何框架,让他们可以使用操作系统对门户网关的感知能力。

Connectivity是一个开源框架,它包装了Reachability,并努力复现iOS检测门户网关的方法。当Reachability检测到Wi-Fi或蜂窝网络连接时,Connectivity将联系多个端点以确定是否存在真正的互联网连接或者一个门户网关是否在拦截连接。这种方法也可以用来确定iOS设备是否连接到没有互联网访问功能的Wi-Fi路由器。

Connectivity提供了一个尽可能接近Reachability的接口,以便开发者熟悉。这包括提供startNotifier()stopNotifier()方法来开始检查互联网连接的变化。一旦启动了通知器,您可以通过使用status属性(类似于Reachability的currentReachabilityStatus)进行同步查询,或者通过在默认的通知中心注册observed通知kNetworkConnectivityChangedNotification(在Swift中通过Notification.Name.ConnectivityDidChange访问)进行异步查询——类似于Reachability的通知kNetworkReachabilityChangedNotification

默认情况下,Connectivity会联系iOS已经使用的多个端点,但建议将这些端点由开发者通过追加到connectivityURLs属性来替换(或者至少补充)。通过设置successThreshold属性,可以进一步进行自定义,它决定了必须在与端点通信时显示成功的检查的端点百分比,以便得出连接存在的结论。默认值指定了必须与50%的URL通信才能进行成功的连接检查。这是因为默认提供了两个连接URL,所以只需要一个连接检查成功即可——如果您需要更严格的检查,请考虑增加这个阈值。

使用

有关如何使用连接性的示例,请参阅示例目录中的sample应用。

回调

要开始使用连接性,只需实例化一个实例,并分配一个要在连接性检测到您已连接到互联网、断开连接或两者都为以下模式时调用的闭包

let connectivity: Connectivity = Connectivity()

let connectivityChanged: (Connectivity) -> Void = { [weak self] connectivity in
     self?.updateConnectionStatus(connectivity.status)
}

connectivity.whenConnected = connectivityChanged
connectivity.whenDisconnected = connectivityChanged

func updateConnectionStatus(_ status: Connectivity.ConnectivityStatus) {

    switch status {
      case .connected:
	    case .connectedViaWiFi:
	    case .connectedViaWiFiWithoutInternet:
	    case .connectedViaCellular:
	    case .connectedViaCellularWithoutInternet:
	    case .notConnected:
    }
        
}

然后要开始监听连接性的变化,请调用

connectivity.startNotifier()

完成时,请记得调用connectivity.stopNotifier()

组合

连接性通过提供Connectivity.Publisher支持Combine,允许客户端订阅并接收互联网连接状态变化的通知。

提供的sample应用包括CombineViewController.swift,展示了如何使用连接性框架,例如。

let publisher = Connectivity.Publisher(
    configuration:
					.init()
          .configureURLSession(.default)
)

注意:当使用ConnectivityPublisher时,您不需要调用startNotifier - 这将在订阅时自动为您处理。

配置

可以通过在Connectivity对象上直接设置相关属性来配置该框架,例如。

let connectivity = Connectivity()
connectivity.pollingInterval = 5
connectivity.expectedResponseString = "Success"
connectivity.validationMode = .containsExpectedResponseString

Connectivity 5.2.0引入了一种新的流畅接口来配置框架,通过将ConnectivityConfiguration对象传递给Connectivity初始化器。

let connectivity = Connectivity(
    configuration: .init()
                .configurePolling(interval: 5)
                .configureResponseValidation(.containsExpectedResponseString, expected: "Success")
)

一次性检查

有时你只想作为一次性检查连接状态。要做到这一点,创建一个连接对象,然后按照以下方式检查状态属性:

let connectivity = Connectivity()

connectivity.checkConnectivity { connectivity in

	switch connectivity.status {
		case .connected: 
			break
		case .connectedViaWiFi:
			break
		case .connectedViaWiFiWithoutInternet:
			break
		case .connectedViaCellular:
			break
		case .connectedViaCellularWithoutInternet:
			break
		case .notConnected:
			break
	}

}

如果你只对某些类型连接感兴趣,可以直接检查以下Connectivity对象的属性:

var isConnectedViaCellular: Bool

var isConnectedViaWiFi: Bool
    
var isConnectedViaCellularWithoutInternet: Bool

var isConnectedViaWiFiWithoutInternet: Bool

连接URL

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

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

网络框架

从版本2.0.0开始,Connectivity提供使用新的Network框架的选项,该框架适用于运行iOS 12或更高版本的设备。为此,将framework属性设置为.network(默认值为.systemConfiguration):

let connectivity = Connectivity()
connectivity.framework = .network

在iOS 12以下,Connectivity将默认使用传统行为,即使用Reachability(SystemConfiguration.framework)确定网络接口的可用性。

有关更多信息,请参阅CHANGELOG.md。

通知

如果你希望使用通知来观察连接状态的变化,可以在默认的NotificationCenter上添加观察者

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

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

轮询

在一些情况下,您可能需要不断了解网络连接状态的变化,因此可能希望启用轮询。启用后,连接性将不会在可到达性状态变化时等待,而是每10秒轮询一次连接性URL(此值可通过设置pollingInterval属性的值进行配置)。只有在网络连接状态发生变化时,才会调用ConnectivityDidChange通知以及分配给whenConnectedwhenDisconnected属性的闭包。

要启用轮询:

connectivity.isPollingEnabled = true
connectivity.startNotifier()

记得在完成后调用stopNotifier()

SSL

从Connectivity 1.1.0开始,默认设置使用HTTPS作为连接URL。如果您的应用程序不使用App Transport Security,并且您还想使用HTTP URL以及HTTPS URL,则将isHTTPSOnly设置为false或实例化连接对象时将shouldUseHTTPS设置为false,如下所示*

let connectivity = Connectivity(shouldUseHTTPS: false)

*注意,如果您未先在应用程序的Info.plist中设置NSAllowsArbitraryLoads标志,则不会设置此属性。

阈值

为了设置成功连接所需的成功连接数,设置successThreshold属性。该值指定为百分比,表示成功连接的百分比,即在connectivityURLs属性中设置了四个连接URL且指定了75%的阈值时,必须有三个检查成功,以便认为应用程序已连接。

connectivity.successThreshold = Connectivity.Percentage(75.0)

响应验证

有三种不同的验证模式可用于检查响应内容,这些是

  • .containsExpectedResponseString - 检查响应是否包含expectedResponseString属性定义的预期响应。
  • .equalsExpectedResponseString - 检查响应是否等于expectedResponseString属性定义的预期响应。
  • .matchesRegularExpression - 检查响应是否匹配由expectedResponseRegEx属性定义的正则表达式。
  • .custom - 允许设置自定义响应验证器。如果指定了此验证模式,则必须在 Connectivity 对象的 responseValidator 属性上提供一个实现 ConnectivityResponseValidator 协议的类型作为值。

提供以下验证器:

  • ConnectivityResponseStringEqualityValidator:确定响应字符串是否与期望的字符串相等。
  • ConnectivityResponseContainsStringValidator:确定响应字符串是否包含期望的字符串。
  • ConnectivityResponseRegExValidator:确定响应字符串是否匹配给定的正则表达式。

已知问题

调用者负责保留 Connectivity 对象

请确保任何使用此框架的实现在整个使用期间(例如作为实例变量)都保持对 Connectivity 对象的强引用。如果在回调调用之前释放对象,则结果将是不确定的。

模拟器问题

在报告错误之前,请确保您已在物理设备上进行测试,因为在模拟器上,iOS 框架不会正确报告网络适配器状态的变化,特别是当从未连接转换为已连接状态时。在实际设备上,此行为是正确的。将 pollWhileOfflineOnly = true 设置为解决问题。

作者

Ross Butler

许可协议

此项目可在MIT许可协议下使用。更多详情请查看LICENSE文件

附加软件

控件

AnimatedGradientView
AnimatedGradientView

框架

  • Cheats - 为现代iOS应用提供的复古作弊代码。
  • Connectivity - 改进了 Reachability,用于在iOS应用程序中确定网络连接。
  • FeatureFlags - 允许开发者配置功能标志,通过捆绑的或远程托管的JSON配置文件运行多个A/B或MVT测试。
  • FlexibleRowHeightGridLayout - 设计用于支持动态字体的UICollectionView网格布局,允许每一行的尺寸根据内容调整。
  • Hyperconnectivity - 用Swift编写、使用 Combine 编写的现代替代方案 Reachability,优雅的方式。它是Connectivity框架的一个分支。
  • Skylark - 使用Gherkin语法编写的Cucumber场景的完全Swift BDD测试框架。
  • TailorSwift - 一组有用的Swift Core Library / Foundation框架扩展。
  • TypographyKit - 支持动态字体,在iOS上提供一致的且可访问的视觉风格。
  • Updates - 自动检测应用更新并温柔地提示用户更新。
Cheats Connectivity FeatureFlags 超级连接 Skylark TypographyKit Updates
Cheats Connectivity FeatureFlags Hyperconnectivity Skylark TypographyKit Updates

工具

  • 清除DerivedData - 通过在终端中键入 cdd,快速清除你的DerivedData目录的实用工具。
  • Config Validator - Config Validator校验并上传你的配置文件,并在CI过程中清除你的CDN缓存。
  • IPA Uploader - 将你的应用上传到TestFlight和App Store。
  • 调色板 - 使你的TypographyKit颜色集在Xcode界面构建器中可用。
Config Validator IPA Uploader 调色板
Config Validator IPA Uploader Palette