iOS实时检测网络变化,现在能做到多精准?
摘要:
下面我将为你详细介绍如何使用 NWPathMonitor,并提供一个完整的代码示例,最后还会提及一些旧方法和注意事项,核心推荐:使用 NWPathMonitor (Network... 下面我将为你详细介绍如何使用 NWPathMonitor,并提供一个完整的代码示例,最后还会提及一些旧方法和注意事项。
核心推荐:使用 NWPathMonitor (Network 框架)
NWPathMonitor 可以持续监控网络接口(如 Wi-Fi、蜂窝网络)的变化,并在网络路径(路径包括网络接口和其关联的路由)发生变化时通知你。
主要优势:
- 现代化:是 Apple 当前推荐的最佳实践。
- 信息丰富:不仅能告诉你网络是否可用,还能告诉你具体是通过什么方式连接的(Wi-Fi, Cellular, Ethernet 等),以及接口的流量是否满足要求。
- 高效:只在路径变化时才唤醒应用,非常省电。
- Swift 原生:与 Swift 语法完美结合,使用起来非常方便。
实现步骤
添加 Network 框架
在你的 Xcode 项目中,你需要确保 Network 框架已经被链接,对于现代的 iOS 项目(使用 SwiftUI 或 UIKit),这通常是自动处理的,如果需要手动添加:
- 选中你的项目 Target。
- 在 "General" 标签页下,找到 "Frameworks, Libraries, and Embedded Content"。
- 点击 号,搜索
Network.framework并添加。
创建监控器并实现逻辑
我们将创建一个 NetworkMonitor 类来封装所有网络监控的逻辑,这样可以在整个应用中方便地复用。
NetworkMonitor.swift
import Foundation
import Network
// 定义一个网络状态枚举,方便在应用中使用
enum NetworkStatus {
case connected(connectionType: ConnectionType)
case disconnected
}
enum ConnectionType {
case wifi
case cellular
case ethernet
case unknown
}
// 创建一个单例,方便全局访问
class NetworkMonitor {
static let shared = NetworkMonitor()
private let queue = DispatchQueue(label: "com.yourapp.networkmonitor")
private let monitor = NWPathMonitor()
// 使用一个属性来存储当前的网络状态,并对外提供通知
public private(set) var networkStatus: NetworkStatus = .disconnected {
didSet {
NotificationCenter.default.post(name: .networkStatusChanged, object: networkStatus)
}
}
// 自定义通知名称
extension Notification.Name {
static let networkStatusChanged = Notification.Name("networkStatusChanged")
}
private init() {
// 在私有初始化器中设置监控器的路径更新处理器
monitor.pathUpdateHandler = { [weak self] path in
guard let self = self else { return }
if path.status == .satisfied {
// 网络连接可用
let connectionType = self.getConnectionType(from: path)
self.networkStatus = .connected(connectionType: connectionType)
print("网络已连接,类型: \(connectionType)")
} else {
// 网络连接不可用
self.networkStatus = .disconnected
print("网络已断开")
}
}
}
// 开始监控
public func startMonitoring() {
monitor.start(queue: queue)
print("网络监控已启动")
}
// 停止监控 (非常重要!)
public func stopMonitoring() {
monitor.cancel()
print("网络监控已停止")
}
// 根据路径信息判断具体的连接类型
private func getConnectionType(from path: NWPath) -> ConnectionType {
if path.usesInterfaceType(.wifi) {
return .wifi
} else if path.usesInterfaceType(.cellular) {
return .cellular
} else if path.usesInterfaceType(.wiredEthernet) {
return .ethernet
} else {
return .unknown
}
}
}
在应用中使用
现在你可以在任何地方使用这个 NetworkMonitor。
在 AppDelegate 或 SceneDelegate 中启动监控
我们会在应用启动时开始监控,并在应用进入后台时停止,以节省资源。
// 在 AppDelegate.swift 或 SceneDelegate.swift 中
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 启动网络监控
NetworkMonitor.shared.startMonitoring()
// ... 其他启动代码
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// 应用即将失去焦点时停止监控
NetworkMonitor.shared.stopMonitoring()
}
func applicationDidBecomeActive(_ application: UIApplication) {
// 应用重新获得焦点时重新启动监控
NetworkMonitor.shared.startMonitoring()
}
在 SwiftUI 视图中监听网络变化
import SwiftUI
struct ContentView: View {
// 使用 @StateObject 或 @ObservedObject 来持有 NetworkMonitor
@StateObject private var networkMonitor = NetworkMonitor.shared
// 使用 State 来触发视图更新
@State private var isConnected = false
@State private var connectionType: String = "未知"
var body: some View {
VStack(spacing: 20) {
Text("网络状态")
.font(.largeTitle)
Text(isConnected ? "已连接" : "已断开")
.font(.title)
.foregroundColor(isConnected ? .green : .red)
Text("连接类型: \(connectionType)")
.font(.headline)
}
.onAppear {
// 订阅网络状态变化的通知
NotificationCenter.default.addObserver(
forName: .networkStatusChanged,
object: nil,
queue: .main
) { notification in
if let status = notification.object as? NetworkStatus {
switch status {
case .connected(let connectionType):
self.isConnected = true
switch connectionType {
case .wifi:
self.connectionType = "Wi-Fi"
case .cellular:
self.connectionType = "蜂窝网络"
case .ethernet:
self.connectionType = "有线网络"
case .unknown:
self.connectionType = "未知"
}
case .disconnected:
self.isConnected = false
self.connectionType = "无"
}
}
}
// 初始化显示
updateUI()
}
.onDisappear {
// 移除通知观察者,避免内存泄漏
NotificationCenter.default.removeObserver(self, name: .networkStatusChanged, object: nil)
}
}
private func updateUI() {
let status = networkMonitor.networkStatus
switch status {
case .connected(let connectionType):
self.isConnected = true
switch connectionType {
case .wifi: self.connectionType = "Wi-Fi"
case .cellular: self.connectionType = "蜂窝网络"
case .ethernet: self.connectionType = "有线网络"
case .unknown: self.connectionType = "未知"
}
case .disconnected:
self.isConnected = false
self.connectionType = "无"
}
}
}
其他方法(不推荐,但需了解)
使用 SCNetworkReachability (旧方法)
这是在 NWPathMonitor 出现之前的主要方法,来自 SystemConfiguration 框架。
- 缺点:
- 功能有限:只能判断“某个主机”是否可达,或者“互联网”是否可达,无法区分具体的连接类型(Wi-Fi 还是 Cellular)。
- 使用复杂:需要使用 Core Foundation 的 API,与 Swift 结合不那么优雅。
- 行为变化:在 iOS 9 之后,即使网络不可达,
isReachable也可能返回true,因此它已不再可靠。
除非你需要在非常旧的 iOS 系统版本上工作,否则强烈建议不要使用此方法。
轮询检查 (不推荐)
通过 URLSession 定期尝试连接一个固定的地址(如 https://www.apple.com)来判断网络是否可用。
- 缺点:
- 延迟高:轮询间隔设置太短会浪费电量和流量,设置太长则响应不及时。
- 效率低下:无法实时响应网络变化。
- 不准确:可能因为 DNS 解析失败或目标服务器问题而误判。
总结与最佳实践
| 方法 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|
NWPathMonitor |
实时、准确、信息丰富、省电、Swift 原生 | 需要导入 Network 框架 |
⭐⭐⭐⭐⭐ (强烈推荐) |
SCNetworkReachability |
兼容性极好(非常旧的系统) | 功能有限、行为不可靠、API 老旧 | ⭐☆☆☆☆ (仅用于遗留项目) |
| 轮询检查 | 实现简单 | 延迟高、耗电、不准确 | ☆☆☆☆☆ (不推荐) |
核心最佳实践:
- 首选
NWPathMonitor:为你的新项目使用NWPathMonitor。 - 封装成单例:创建一个
NetworkMonitor类,将其设为单例,方便在整个应用中访问。 - 使用通知中心:在
NetworkMonitor内部状态变化时,通过NotificationCenter发送通知,视图控制器或 SwiftUI 视图通过订阅通知来更新 UI,实现松耦合。 - 管理生命周期:在应用进入后台时调用
stopMonitoring(),在应用回到前台时调用startMonitoring(),以避免不必要的资源消耗。 - 处理错误:虽然
NWPathMonitor本身很稳定,但始终要考虑网络不可用的情况,并相应地禁用需要网络的功能或显示友好的提示。
文章版权及转载声明
作者:咔咔本文地址:https://jits.cn/content/1564.html发布于 2025-11-02
文章转载或复制请以超链接形式并注明出处杰思科技・AI 股讯



还没有评论,来说两句吧...