A modern, type-safe, actor-based network path monitoring utility for Apple platforms.
NetworkPathMonitor provides an easy and safe way to observe network connectivity changes using Swift Concurrency, AsyncStream, callbacks, and notifications.
- 🚦 Real-time network status monitoring based on
NWPathMonitor - 🧑💻 Actor isolation for thread safety (Swift Concurrency)
- 🌀 AsyncStream support for async/await style observation
- 🛎️ Callback and NotificationCenter support
- ⏳ Debounce mechanism to avoid frequent updates
- 📊 Rich NetworkPath with sequence tracking and update reasons
- 🛠️ Simple API, easy integration
- Swift 5.10 or later
- iOS 13.0+, macOS 10.15+, tvOS 13.0+, watchOS 6.0+, visionOS 1.0+
Add the following to your Package.swift:
.package(url: "https://github.com/codingiran/NetworkPathMonitor.git", from: "0.0.1")Or use Xcode:
File > Add Packages... and enter the repository URL.
import NetworkPathMonitor
let monitor = NetworkPathMonitor()
await monitor.fire()
// Check current status
let isConnected = await monitor.isPathSatisfied
// Stop monitoring
await monitor.invalidate()import NetworkPathMonitor
let monitor = NetworkPathMonitor()
await monitor.fire()
Task {
for await path in await monitor.pathUpdates {
print("Network status changed: \(path.status)")
print("Is first update: \(path.isFirstUpdate)")
print("Update reason: \(path.updateReason)")
}
}import NetworkPathMonitor
let monitor = NetworkPathMonitor()
await monitor.pathOnChange { path in
print("Network changed: \(path.status)")
print("Is first update: \(path.isFirstUpdate)")
print("Update reason: \(path.updateReason)")
}
await monitor.fire()import NetworkPathMonitor
let observer = NotificationCenter.default.addObserver(
forName: NetworkPathMonitor.networkStatusDidChangeNotification,
object: nil,
queue: .main
) { notification in
if let newPath = notification.userInfo?["newPath"] as? NetworkPath {
print("Network status changed to: \(newPath.status)")
print("Is first update: \(newPath.isFirstUpdate)")
print("Update reason: \(newPath.updateReason)")
}
}You can set a debounce interval to avoid frequent updates:
let monitor = NetworkPathMonitor(debounceInterval: .seconds(1.0)) // 1 second debounceNetworkPathMonitor uses a convenient Interval enum for specifying debounce intervals:
// Different interval types
let monitor1 = NetworkPathMonitor(debounceInterval: .nanoseconds(500_000_000)) // 0.5 seconds
let monitor2 = NetworkPathMonitor(debounceInterval: .milliseconds(500)) // 0.5 seconds
let monitor3 = NetworkPathMonitor(debounceInterval: .seconds(0.5)) // 0.5 seconds
let monitor4 = NetworkPathMonitor(debounceInterval: .minutes(1)) // 1 minute
let monitor5 = NetworkPathMonitor(debounceInterval: .hours(1)) // 1 hourNetworkPathMonitor now provides rich sequence tracking capabilities through the NetworkPath type. Each path update includes sequence information and update reasons:
let monitor = NetworkPathMonitor()
await monitor.fire()
Task {
for await path in await monitor.pathUpdates {
// Check if this is the first update after initial connection
if path.isFirstUpdate {
print("First network update received")
}
// Access the previous path for comparison
if let previousPath = path.sequence.previousPath {
print("Previous status: \(previousPath.status)")
print("Previous interfaces: \(previousPath.usedInterfaces.names)")
}
// Get update reason
switch path.updateReason {
case .initial:
print("Initial path when monitor started")
case .physicalChange:
print("Physical network interface changed")
case .uncertain:
print("Network status changed for uncertain reason")
}
}
}.initial: The path is the initial path when the monitor is started.physicalChange: The path has changed due to a physical interface change (e.g., switching from WiFi to Cellular).uncertain: The reason for the update is uncertain (e.g., network configuration changes)
Each path update has a sequence index that increments with each update:
print("Sequence index: \(path.sequence.index)")
print("Is initial path: \(path.sequence.isInitial)")init(queue: DispatchQueue = ..., debounceInterval: Interval = .zero)queue: The dispatch queue for the underlying NWPathMonitor.debounceInterval: Debounce interval using convenient Interval enum. Default is .zero (no debounce).
isActive: Whether monitoring is active.currentPath: The latestNetworkPath.isPathSatisfied: Whether the current path is satisfied (connected).
fire(): Start monitoring.invalidate(): Stop monitoring.pathOnChange(_:): Register a callback for path changes.pathUpdates: AsyncStream of NetworkPath updates.
MIT License. See LICENSE for details.
Contributions are welcome! Please open issues or submit pull requests.