Reachability — 一个基于SystemConfiguration框架构建的iOS和macOS库,可以检查互联网连接的可用性并跟踪其变化。根据Apple Developer Documentation (2025),Reachability使用SCNetworkReachability进行异步网络监控。Reachability库长期以来一直是iOS项目的标准,直到原生NWPathMonitor的出现。
要点
Reachability — 是Apple的一个示例库,演示了使用SystemConfiguration框架进行网络监控。源代码作为示例发布在Apple Developer Documentation中,但社区已将其接受为iOS项目中检查连接的标准工具。
该库基于SCNetworkReachability工作——来自SystemConfiguration的C函数,评估远程主机或IP地址的可达性。创建Reachability时,指定主机名(如google.com)或IP地址,库会异步检查该主机是否可通过设备当前的网络接口访问。
Reachability的流行度归功于其简单性:只需创建实例,通过NotificationCenter订阅通知,并监听kReachabilityChangedNotification。作为响应,应用程序接收到状态:NotReachable、ReachableViaWiFi或ReachableViaWWAN(移动数据)。
Reachability首次出现在iPhone OS 2(2008)中,与SystemConfiguration框架一起。在十年间,它是iOS中唯一的原生网络监控方式。随iOS 12和Network框架的发布,Apple推荐NWPathMonitor作为替代品,但Reachability仍然受支持。
许多第三方封装——AFNetworking、Alamofire、AshleyDodd/Reachability.swift——使用SCNetworkReachability内部机制。这些库添加了便捷的Swift/Objective-C接口、状态缓存和线程安全的回调,保持相同的SystemConfiguration基础。
Reachability的主要机制——SCNetworkReachabilityCreateWithName函数,为指定的主机创建跟踪对象。然后调用SCNetworkReachabilityGetFlags——同步检查,返回带有当前网络状态的SCNetworkReachabilityFlags位码。
对于异步监控,使用SCNetworkReachabilitySetCallback,注册C回调函数。当主机可达性状态改变时,回调在当前的RunLoop上执行。Reachability将这个C回调封装到Objective-C方法中,并通过NotificationCenter发送通知。
import SystemConfiguration
class Reachability {
private var reachabilityRef: SCNetworkReachability?
init?(hostname: String) {
reachabilityRef = SCNetworkReachabilityCreateWithName(
nil, hostname
)
}
func checkReachability() -> Bool {
var flags = SCNetworkReachabilityFlags()
SCNetworkReachabilityGetFlags(
reachabilityRef!, &flags
)
return isReachable(with: flags)
}
private func isReachable(with flags: SCNetworkReachabilityFlags) -> Bool {
let reachable = flags.contains(.reachable)
let connectionRequired = flags.contains(.connectionRequired)
return reachable && !connectionRequired
}
}
SCNetworkReachabilityFlags——编码网络状态的位码。kSCNetworkReachabilityFlagsReachable标志表示主机可达。kSCNetworkReachabilityFlagsConnectionRequired——需要建立通信才能连接。标志的组合确定应用程序是否可以发送数据。
附加标志:kSCNetworkReachabilityFlagsIsWWAN——通过移动网络连接(iOS),kSCNetworkReachabilityFlagsInterventionRequired——需要用户干预(如VPN)。Reachability考虑这些标志以确定接口类型。
在iOS应用程序中使用Reachability的标准模式包括创建实例、订阅通知以及对状态变化做出反应。下面的示例展示了与NotificationCenter的集成,用于在网络变化时更新UI。
import Reachability
import UIKit
class ViewController: UIViewController {
var reachability: Reachability?
override func viewDidLoad() {
super.viewDidLoad()
reachability = Reachability(hostname: "google.com")
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged),
name: .reachabilityChanged,
object: nil
)
reachability?.startNotifier()
}
@objc func reachabilityChanged(notification: Notification) {
if let reachability = notification.object as? Reachability {
switch reachability.connection {
case .wifi:
print("通过Wi-Fi连接")
case .cellular:
print("通过移动网络连接")
case .unavailable:
print("未连接")
}
}
}
}
在执行HTTP请求之前,可以同步检查网络可用性:reachability.connection != .unavailable。这不能保证请求成功(服务器可能不可用),但可以避免定然失败的请求并改善用户体验——应用程序在离线模式下不显示加载圆圈。
为了更精确的检查,将Reachability与URLSession超时结合。如果Reachability显示可达,但请求在超时时间内未执行——问题可能出在服务器端或限制网关。在这种情况下,可以向用户显示服务器不可用的消息。
Reachability区分三种主要连接状态:Wi-Fi、移动数据(WWAN)和不可用。WWAN包括所有类型的移动通信——2G、3G、4G/LTE、5G。该库不提供WWAN内的详细信息,因此区分4G和5G需要CoreTelephony。
| 状态 | SCNetwork标志 | 描述 |
|---|---|---|
| ReachableViaWiFi | Reachable + !IsWWAN | 通过Wi-Fi网络连接,可访问主机 |
| ReachableViaWWAN | Reachable + IsWWAN | 通过移动网络连接(2G-5G) |
| NotReachable | !Reachable | 主机无法通过任何接口访问 |
| ConnectionRequired | Reachable + ConnectionRequired | 需要建立连接(VPN、PPPoE) |
Reachability不区分Ethernet、VPN隧道或multipath连接——所有非WWAN接口都被分类为Wi-Fi。这一局限性与SystemConfiguration的架构有关,它在基本分类之外不提供有关网络接口的详细信息。
要确定移动通信的具体类型(4G vs 5G),需要来自CoreTelephony的CTTelephonyNetworkInfo。将Reachability与CoreTelephony结合可以让应用程序选择内容质量:在5G下播放4K流媒体,在4G/LTE下播放HD,在3G下播放SD或仅播放音频。
Apple建议在所有新项目中将Reachability替换为NWPathMonitor,从iOS 12开始。主要原因是NWPathMonitor是现代Network框架的一部分,用Swift编写,支持Combine,并提供关于网络路径的详细信息,无需C兼容性。
迁移过程包括将SCNetworkReachability替换为NWPathMonitor,从NotificationCenter迁移到pathUpdateHandler closure或Combine publisher。网络状态处理的算法和逻辑保持不变——仅监控API发生变化。
protocol NetworkMonitorProtocol {
var isReachable: Bool { get }
var connectionType: ConnectionType { get }
func startMonitoring()
func stopMonitoring()
}
enum ConnectionType {
case wifi, cellular, ethernet, unavailable
}
// 使用NWPathMonitor的现代实现
class ModernNetworkMonitor: NetworkMonitorProtocol {
private let monitor = NWPathMonitor()
private let queue = DispatchQueue("Network")
private var currentPath: NWPath?
var isReachable: Bool {
currentPath?.status == .satisfied
}
func startMonitoring() {
monitor.pathUpdateHandler = { [weak self] path in
self?.currentPath = path
}
monitor.start(on: queue)
}
func stopMonitoring() {
monitor.cancel()
}
}
对于基础支持iOS 12+的项目,将Reachability完全替换为NWPathMonitor。对于支持iOS 11的项目,使用条件编译#available(iOS 12, *),将NWPathMonitor作为主要方案,Reachability作为备用。这样可以逐步迁移,而不会丢失对旧设备的支持。
迁移的主要优势是网络路径的详细信息。NWPathMonitor不仅报告“可用/不可用”,还提供每个接口的类型、成本、优先级、代理和VPN支持。这为开发人员提供了更多数据,以将应用程序的行为适应当前网络条件。
常见问题
基于SCNetworkReachability的Reachability从iPhone OS 2(iOS 2)开始可用。该库在所有iOS版本上都可以工作,包括当前版本。局限性不涉及操作系统版本,而是信息的详细程度——在旧版本上没有 4G 和 5G 的区分。
Reachability使用SCNetworkReachability——一种系统服务,在不发送数据包的情况下,在网络堆栈层面评估主机的可达性。Ping发送ICMP数据包并消耗流量,还可能被防火墙拦截。Reachability更快更安全,适合频繁检查。
可以,Reachability通过ObservableObject或Combine在SwiftUI中工作。将其封装到订阅了NotificationCenter的类中,并通过@Published发布状态。对于新的SwiftUI项目,我们建议使用带Combine publisher的NWPathMonitor来实现View的响应式更新。
Reachability检查SCNetworkReachabilityFlags位码中的kSCNetworkReachabilityFlagsIsWWAN标志。如果该标志被设置——通过移动网络(WWAN)连接,否则且主机可达——通过Wi-Fi连接。这是不使用CoreTelephony区分类型的唯一方法。
SCNetworkReachability在网络层检查主机的可达性,但不保证高层协议的工作。可能的原因:限制网关、DNS拦截、代理服务器或防火墙。Reachability是第一层过滤,但不能替代真正的HTTP请求。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。