Token导航 LogoToken导航

Agent Skill · 研究检索

axiom-network-framework-ref(Axiom 网络框架参考)

axiom-network-framework-ref 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

axiom-network-framework-ref 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为操作浏览器;许可证为 MIT,第三方扫描有提醒项,按安装量在研究检索类的 73,675 个 Skill 里排第 23,454。

总安装 4,268周安装 171GitHub Stars 873下载 1,382核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:axiom-network-framework-ref(Axiom 网络框架参考)
来源仓库:https://github.com/charleswiltgen/axiom
仓库路径:skills/axiom-network-framework-ref
安装命令:
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-network-framework-ref
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-network-framework-ref

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

提供 Network.framework 的现代网络 API 完整参考,取代传统 Berkeley sockets。适用于建立智能连接、支持 TLS 1.3、用户态网络及无缝移动切换的场景。覆盖 NWConnection(iOS 12-25)向 NetworkConnection(iOS 26+)的结构化并发迁移指南。

安装前应确认目标 iOS 版本范围,并注意异步编程模型从 completion handler 向 async/await 的演进。建议结合实际网络问题场景查阅对应章节,避免误用为 HTTP REST API 的首选方案。

来源仓库内路径:skills/axiom-network-framework-ref

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-network-fra…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要操作浏览器,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

axiom-network-framework-ref 怎么安装?

在终端执行 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-network-framework-ref。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

axiom-network-framework-ref 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

axiom-network-framework-ref 需要什么权限?

权限级别是操作浏览器。该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

axiom-network-framework-ref 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

axiom-network-framework-ref 用的人多吗?

公开数据是累计安装 4,268 次,近一周安装 171 次,下载 1,382 次,GitHub 873 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

axiom-network-framework-ref 安全吗?

第三方扫描有提醒项,说明存在需要人工确认的行为。安装前请打开源码看清它读了什么、联网到哪里。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。

先想清楚的地方

  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
axiom-network-framework-ref

Axiom 网络框架参考 · 本页

4,268873操作浏览器MIT有提醒

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Network.framework API Reference

Overview

Network.framework is Apple's modern networking API that replaces Berkeley sockets, providing smart connection establishment, user-space networking, built-in TLS support, and seamless mobility. Introduced in iOS 12 (2018) with NWConnection and evolved in iOS 26 (2025) with NetworkConnection for structured concurrency.

Evolution timeline
  • 2018 (iOS 12) NWConnection with completion handlers, deprecates CFSocket/NSStream/SCNetworkReachability
  • 2019 (iOS 13) User-space networking (30% CPU reduction), TLS 1.3 default
  • 2025 (iOS 26) NetworkConnection with async/await, TLV framing built-in, Coder protocol, Wi-Fi Aware discovery
Key capabilities
  • Smart connection establishment Happy Eyeballs (IPv4/IPv6 racing), proxy evaluation (PAC), VPN detection, WiFi Assist fallback
  • User-space networking ~30% lower CPU usage vs sockets, memory-mapped regions, reduced context switches
  • Built-in security TLS 1.3 by default, DTLS for UDP, certificate pinning support
  • Mobility Automatic network transition handling (WiFi ↔ cellular), viability notifications, Multipath TCP
  • Performance ECN (Explicit Congestion Notification), service class marking, TCP Fast Open, UDP batching
When to use vs URLSession
  • URLSession HTTP, HTTPS, WebSocket, simple TCP/TLS streams → Use URLSession (optimized for these)
  • Network.framework UDP, custom protocols, low-level control, peer-to-peer, gaming, streaming → Use Network.framework
Related Skills
  • Use axiom-networking for anti-patterns, common patterns, pressure scenarios
  • Use axiom-networking-diag for systematic troubleshooting of connection failures

When to Use This Skill

Use this skill when:

  • Planning migration from BSD sockets, CFSocket, NSStream, or SCNetworkReachability
  • Understanding API differences between NWConnection (iOS 12-25) and NetworkConnection (iOS 26+)
  • Implementing all 12 WWDC 2025 examples (TLS connection, TLV framing, Coder protocol, NetworkListener, Wi-Fi Aware)
  • Choosing protocols (TCP, UDP, TLS, QUIC) for your use case
  • Peer-to-peer discovery setup with NetworkBrowser and Wi-Fi Aware
  • Optimizing performance with user-space networking, batching, pacing
  • Migrating from completion handlers to async/await (NWConnection → NetworkConnection)

API Evolution

Timeline

YeariOS VersionKey Features
2018iOS 12NWConnection, NWListener, NWBrowser introduced
2019iOS 13User-space networking (30% CPU reduction), TLS 1.3 default
2021iOS 15WebSocket support in URLSession
2025iOS 26NetworkConnection (async/await), TLV framing, Coder protocol, Wi-Fi Aware

NWConnection (iOS 12-25) vs NetworkConnection (iOS 26+)

FeatureNWConnection (iOS 12-25)NetworkConnection (iOS 26+)
Async modelCompletion handlersasync/await structured concurrency
State updatesstateUpdateHandler callbackstates AsyncSequence
Sendsend(content:completion:) callbacktry await send(content) suspending
Receivereceive(minimumIncompleteLength:maximumLength:completion:)try await receive(exactly:) suspending
FramingManual or custom NWFramerTLV built-in (TLV {TLS()})
CodableManual JSON encode/decodeCoder protocol (Coder(MyType.self, using:.json))
MemoryRequires [weak self] in all closuresNo [weak self] needed (Task cancellation automatic)
Error handlingCheck error in completionthrows with natural propagation
State machineCallbacks on state changesfor await state in connection.states
DiscoveryNWBrowser (Bonjour only)NetworkBrowser (Bonjour + Wi-Fi Aware)
Recommendation
  • New apps targeting iOS 26+: Use NetworkConnection (cleaner, safer)
  • Apps supporting iOS 12-25: Use NWConnection (backward compatible)
  • Migration: Both APIs coexist, migrate incrementally

NetworkConnection (iOS 26+) Complete Reference

4.1 Creating Connections

NetworkConnection uses declarative protocol stack composition.

Example 1: Basic TLS Connection (WWDC 4:04)
import Network

// Basic connection with TLS (TCP and IP inferred)
let connection = NetworkConnection(
    to: .hostPort(host: "www.example.com", port: 1029)
) {
    TLS()
}

// Send and receive with async/await
public func sendAndReceiveWithTLS() async throws {
    let outgoingData = Data("Hello, world!".utf8)
    try await connection.send(outgoingData)

    let incomingData = try await connection.receive(exactly: 98).content
    print("Received data: \(incomingData)")
}
Key points
  • TLS() infers TCP() and IP() automatically
  • No explicit connection.start() needed (happens on first send/receive)
  • Async/await eliminates callback nesting
Example 2: Custom IP Options (WWDC 4:41)
// Customize IP fragmentation
let connection = NetworkConnection(
    to: .hostPort(host: "www.example.com", port: 1029)
) {
    TLS {
        TCP {
            IP()
                .fragmentationEnabled(false) // Disable IP fragmentation
        }
    }
}
When to customize IP
  • .fragmentationEnabled(false) — For protocols that handle fragmentation themselves (QUIC)
  • .ipVersion(.v6) — Force IPv6 only (testing)
Example 3: Custom Parameters (WWDC 5:07)
// Constrained paths (low data mode) + custom IP
let connection = NetworkConnection(
    to: .hostPort(host: "www.example.com", port: 1029),
    using: .parameters {
        TLS {
            TCP {
                IP()
                    .fragmentationEnabled(false)
            }
        }
    }
    .constrainedPathsProhibited(true) // Don't use cellular in low data mode
)
Common parameters
  • .constrainedPathsProhibited(true) — Respect low data mode
  • .expensivePathsProhibited(true) — Don't use cellular/hotspot
  • .multipathServiceType(.handover) — Enable Multipath TCP
Endpoint Types
// Host + Port
.hostPort(host: "example.com", port: 443)

// Service (Bonjour)
.service(name: "MyPrinter", type: "_ipp._tcp", domain: "local.", interface: nil)

// Unix domain socket
.unix(path: "/tmp/my.sock")
Protocol Stack Composition
// TLS over TCP (most common)
TLS()

// QUIC (TLS + UDP, multiplexed streams)
QUIC()

// UDP (datagrams)
UDP()

// TCP (stream, no encryption)
TCP()

// WebSocket over TLS
WebSocket {
    TLS()
}

// Custom framing
TLV {
    TLS()
}

4.2 State Machine

NetworkConnection transitions through these states:

setup
  ↓
preparing (DNS, TCP handshake, TLS handshake)
  ↓
┌─ waiting (no network, retrying)
│    ↓
└→ ready (can send/receive)
     ↓
  failed (error) or cancelled
Monitoring States
// Option 1: Async sequence (monitor in background)
Task {
    for await state in connection.states {
        switch state {
        case .preparing:
            print("Connecting...")
        case .waiting(let error):
            print("Waiting for network: \(error)")
        case .ready:
            print("Connected!")
        case .failed(let error):
            print("Failed: \(error)")
        case .cancelled:
            print("Cancelled")
        @unknown default:
            break
        }
    }
}
Key states
  • .preparing DNS lookup, TCP SYN, TLS handshake
  • .waiting No network available, framework retries automatically
  • .ready Connection established, can send/receive
  • .failed Unrecoverable error (server refused, TLS failed, timeout)
  • .cancelled Task cancelled or connection.cancel() called

4.3 Send/Receive Patterns

Send: Basic
let data = Data("Hello".utf8)
try await connection.send(data)
Receive: Exact Byte Count (WWDC 7:30)
// Receive exactly 98 bytes
let incomingData = try await connection.receive(exactly: 98).content
print("Received \(incomingData.count) bytes")
Receive: Variable Length (WWDC 8:29)
// Read UInt32 length prefix, then read that many bytes
let remaining32 = try await connection.receive(as: UInt32.self).content
guard var remaining = Int(exactly: remaining32) else { throw MyError.invalidLength }

while remaining > 0 {
    let chunk = try await connection.receive(atLeast: 1, atMost: remaining).content
    remaining -= chunk.count
    // Process chunk...
}
receive() variants
  • receive(exactly: n) — Wait for exactly n bytes
  • receive(atLeast: min, atMost: max) — Get between min and max bytes
  • receive(as: UInt32.self) — Read fixed-size type (network byte order)

4.4 TLV Framing (iOS 26+)

TLV (Type-Length-Value) solves message boundary problem on stream protocols (TCP/TLS).

Format
  • Type: UInt32 (message identifier)
  • Length: UInt32 (message size, automatic)
  • Value: Message bytes
Example: GameMessage with TLV (WWDC 11:06, 11:24, 11:53)
import Network

// Define message types
enum GameMessage: Int {
    case selectedCharacter = 0
    case move = 1
}

struct GameCharacter: Codable {
    let character: String
}

struct GameMove: Codable {
    let row: Int
    let column: Int
}

// Connection with TLV framing
let connection = NetworkConnection(
    to: .hostPort(host: "www.example.com", port: 1029)
) {
    TLV {
        TLS()
    }
}

// Send typed message
public func sendWithTLV() async throws {
    let characterData = try JSONEncoder().encode(GameCharacter(character: "🐨"))
    try await connection.send(characterData, type: GameMessage.selectedCharacter.rawValue)
}

// Receive typed message
public func receiveWithTLV() async throws {
    let (incomingData, metadata) = try await connection.receive()

    switch GameMessage(rawValue: metadata.type) {
    case .selectedCharacter:
        let character = try JSONDecoder().decode(GameCharacter.self, from: incomingData)
        print("Character selected: \(character)")
    case .move:
        let move = try JSONDecoder().decode(GameMove.self, from: incomingData)
        print("Move: row=\(move.row), column=\(move.column)")
    case .none:
        print("Unknown message type: \(metadata.type)")
    }
}
Benefits
  • Message boundaries preserved (send 3 messages → receive exactly 3)
  • Type-safe message handling (enum-based routing)
  • Minimal overhead (8 bytes per message: type + length)
When to use
  • Mixed message types (chat + presence + typing)
  • Existing protocols using TLV
  • Need message boundaries without heavy framing

4.5 Coder Protocol (iOS 26+)

Coder eliminates manual JSON encoding/decoding boilerplate.

Example: GameMessage with Coder (WWDC 12:50, 13:13, 13:53)
import Network

// Define message types as Codable enum
enum GameMessage: Codable {
    case selectedCharacter(String)
    case move(row: Int, column: Int)
}

// Connection with Coder
let connection = NetworkConnection(
    to: .hostPort(host: "www.example.com", port: 1029)
) {
    Coder(GameMessage.self, using: .json) {
        TLS()
    }
}

// Send Codable directly (no encoding needed!)
public func sendWithCoder() async throws {
    let selectedCharacter: GameMessage = .selectedCharacter("🐨")
    try await connection.send(selectedCharacter)
}

// Receive Codable directly (no decoding needed!)
public func receiveWithCoder() async throws {
    let gameMessage = try await connection.receive().content // Returns GameMessage!

    switch gameMessage {
    case .selectedCharacter(let character):
        print("Character selected: \(character)")
    case .move(let row, let column):
        print("Move: (\(row), \(column))")
    }
}
Supported formats
  • .json — JSON encoding (human-readable, widely compatible)
  • .propertyList — Property list (faster, smaller)
Benefits
  • No JSON boilerplate (~50 lines → ~10 lines)
  • Type-safe (compiler catches message structure changes)
  • Automatic framing (handles message boundaries)
When to use
  • App-to-app communication (you control both ends)
  • Prototyping (fastest time to working code)
  • Type-safe protocols
When NOT to use
  • Interoperating with non-Swift servers
  • Need custom wire format
  • Performance-critical (prefer manual encoding for control)

4.6 NetworkListener (iOS 26+)

Listen for incoming connections with automatic subtask management.

Example: Listening for Connections (WWDC 15:16)
import Network

// Listener with Coder protocol
public func listenForIncomingConnections() async throws {
    try await NetworkListener {
        Coder(GameMessage.self, using: .json) {
            TLS()
        }
    }.run { connection in
        // Each connection gets its own subtask
        for try await (gameMessage, _) in connection.messages {
            switch gameMessage {
            case .selectedCharacter(let character):
                print("Player chose: \(character)")
            case .move(let row, let column):
                print("Player moved: (\(row), \(column))")
            }
        }
    }
}
Key features
  • Automatic subtask per connection (no manual Task management)
  • Structured concurrency (all subtasks cancelled when listener exits)
  • connection.messages async sequence for receiving
Listener configuration
// Specify port
NetworkListener(port: 1029) { TLS() }

// Let system choose port
NetworkListener { TLS() }

// Bonjour advertising
NetworkListener(service: .init(name: "MyApp", type: "_myapp._tcp")) { TLS() }

4.7 NetworkBrowser & Wi-Fi Aware (iOS 26+)

Discover endpoints on local network or nearby devices.

Example: Wi-Fi Aware Discovery (WWDC 17:39)
import Network
import WiFiAware

// Browse for nearby paired Wi-Fi Aware devices
public func findNearbyDevice() async throws {
    let endpoint = try await NetworkBrowser(
        for: .wifiAware(.connecting(to: .allPairedDevices, from: .ticTacToeService))
    ).run { endpoints in
        .finish(endpoints.first!) // Use first discovered device
    }

    // Make connection to the discovered endpoint
    let connection = NetworkConnection(to: endpoint) {
        Coder(GameMessage.self, using: .json) {
            TLS()
        }
    }
}
Wi-Fi Aware features
  • Peer-to-peer without infrastructure (no WiFi router needed)
  • Automatic discovery of paired devices
  • Low latency, axiom-high throughput
  • iOS 26+ only
Browse descriptors
// Bonjour
.bonjour(type: "_http._tcp", domain: "local")

// Wi-Fi Aware (all paired devices)
.wifiAware(.connecting(to: .allPairedDevices, from: .myService))

// Wi-Fi Aware (specific device)
.wifiAware(.connecting(to: .pairedDevice(identifier: deviceID), from: .myService))

NWConnection (iOS 12-25) Complete Reference

5.1 Creating Connections

NWConnection uses completion handlers (pre-async/await).

Basic TLS Connection (WWDC 2018 lines 133-166)
import Network

// Create connection
let connection = NWConnection(
    host: NWEndpoint.Host("mail.example.com"),
    port: NWEndpoint.Port(integerLiteral: 993),
    using: .tls // TCP inferred
)

// Handle connection state changes
connection.stateUpdateHandler = { [weak self] state in
    switch state {
    case .ready:
        print("Connection established")
        self?.sendData()

    case .waiting(let error):
        print("Waiting for network: \(error)")
        // Show "Waiting..." UI, don't fail immediately

    case .failed(let error):
        print("Connection failed: \(error)")

    case .cancelled:
        print("Connection cancelled")

    default:
        break
    }
}

// Start connection
connection.start(queue: .main)

Critical Always use [weak self] in stateUpdateHandler to prevent retain cycles.

Custom Parameters
// Create custom parameters
let parameters = NWParameters.tls

// Prohibit expensive networks
parameters.prohibitExpensivePaths = true // Don't use cellular/hotspot

// Prohibit constrained networks
parameters.prohibitConstrainedPaths = true // Respect low data mode

// Require IPv6
parameters.requiredInterfaceType = .wifi
parameters.ipOptions.version = .v6

let connection = NWConnection(host: "example.com", port: 443, using: parameters)

5.2 State Handling

NWConnection state machine (same as NetworkConnection):

setup → preparing → waiting/ready → failed/cancelled
State handling best practices
connection.stateUpdateHandler = { [weak self] state in
    guard let self = self else { return }

    switch state {
    case .preparing:
        // DNS lookup, TCP SYN, TLS handshake in progress
        self.updateUI(.connecting)

    case .waiting(let error):
        // Network unavailable or blocked
        // DON'T fail immediately, framework retries automatically
        print("Waiting: \(error.localizedDescription)")
        self.updateUI(.waiting)

    case .ready:
        // Connection established, can send/receive
        self.updateUI(.connected)
        self.startSending()

    case .failed(let error):
        // Unrecoverable error after all retry attempts
        print("Failed: \(error.localizedDescription)")
        self.updateUI(.failed)

    case .cancelled:
        // connection.cancel() called
        self.updateUI(.disconnected)

    default:
        break
    }
}

5.3 Send/Receive with Callbacks

Send with Pacing (WWDC 2018 lines 320-341)
// Send with contentProcessed callback for pacing
func sendData() {
    let data = Data("Hello, world!".utf8)

    connection.send(content: data, completion: .contentProcessed { [weak self] error in
        if let error = error {
            print("Send error: \(error)")
            return
        }

        // contentProcessed = network stack consumed data
        // NOW send next chunk (pacing)
        self?.sendNextData()
    })
}

contentProcessed callback Invoked when network stack consumes your data (equivalent to when blocking socket call would return). Use this for pacing to avoid buffering excessive data.

Receive with Exact Byte Count
// Receive exactly 10 bytes
connection.receive(minimumIncompleteLength: 10, maximumLength: 10) { [weak self] (data, context, isComplete, error) in
    if let error = error {
        print("Receive error: \(error)")
        return
    }

    if let data = data {
        print("Received \(data.count) bytes")
        // Process data...

        // Continue receiving
        self?.receiveMore()
    }
}
Receive parameters
  • minimumIncompleteLength: Minimum bytes before callback (1 = return any data)
  • maximumLength: Maximum bytes per callback
  • For "exactly n bytes": Set both to n

5.4 UDP Batching (WWDC 2018 lines 343-347)

Batch sending for 30% CPU reduction.
// UDP connection
let connection = NWConnection(
    host: NWEndpoint.Host("game-server.example.com"),
    port: NWEndpoint.Port(integerLiteral: 9000),
    using: .udp
)

connection.start(queue: .main)

// Batch multiple datagrams
func sendVideoFrames(_ frames: [Data]) {
    connection.batch {
        for frame in frames {
            connection.send(content: frame, completion: .contentProcessed { error in
                if let error = error {
                    print("Send error: \(error)")
                }
            })
        }
    }
    // All sends batched into ~1 syscall
    // Result: 30% lower CPU usage vs individual sends
}

Without batch 100 datagrams = 100 syscalls = high CPU With batch 100 datagrams = ~1 syscall = 30% lower CPU (measured with Instruments)


5.5 NWListener (WWDC 2018 lines 233-293)

Accept incoming connections.

import Network

// Create listener on port 1029
let listener = try NWListener(using: .tcp, on: 1029)

// Advertise Bonjour service
listener.service = NWListener.Service(name: "MyApp", type: "_myapp._tcp")

// Handle service registration
listener.serviceRegistrationUpdateHandler = { update in
    switch update {
    case .add(let endpoint):
        if case .service(let name, let type, let domain, _) = endpoint {
            print("Advertising: \(name).\(type)\(domain)")
        }
    default:
        break
    }
}

// Handle new connections
listener.newConnectionHandler = { [weak self] newConnection in
    print("New connection from: \(newConnection.endpoint)")

    newConnection.stateUpdateHandler = { state in
        if case .ready = state {
            print("Client connected")
            self?.handleClient(newConnection)
        }
    }

    newConnection.start(queue: .main)
}

// Handle listener state
listener.stateUpdateHandler = { state in
    switch state {
    case .ready:
        print("Listener ready on port \(listener.port ?? 0)")
    case .failed(let error):
        print("Listener failed: \(error)")
    default:
        break
    }
}

// Start listening
listener.start(queue: .main)

5.6 NWBrowser (Bonjour Discovery)

Discover services on local network.

import Network

// Browse for Bonjour services
let browser = NWBrowser(
    for: .bonjour(type: "_http._tcp", domain: nil),
    using: .tcp
)

// Handle discovered services
browser.browseResultsChangedHandler = { results, changes in
    for result in results {
        switch result.endpoint {
        case .service(let name, let type, let domain, _):
            print("Found service: \(name).\(type)\(domain)")

            // Connect to this service
            let connection = NWConnection(to: result.endpoint, using: .tcp)
            connection.start(queue: .main)

        default:
            break
        }
    }
}

// Handle browser state
browser.stateUpdateHandler = { state in
    switch state {
    case .ready:
        print("Browser ready")
    case .failed(let error):
        print("Browser failed: \(error)")
    default:
        break
    }
}

// Start browsing
browser.start(queue: .main)

Mobility & Network Transitions

Connection Viability (WWDC 2018 lines 453-463)

Viability = connection can send/receive data (has valid route).

connection.viabilityUpdateHandler = { isViable in
    if isViable {
        print("✅ Connection viable (can send/receive)")
    } else {
        print("⚠️ Connection not viable (no route)")
        // Don't tear down immediately, may recover
        // Show UI: "Connection interrupted"
    }
}
When viability changes
  • Walk into elevator (WiFi signal lost) → not viable
  • Walk out of elevator (WiFi returns) → viable again
  • Switch WiFi → cellular → not viable briefly → viable on cellular

Best practice Don't tear down connection on viability loss. Framework will recover when network returns.

Better Path Available (WWDC 2018 lines 464-477)

Better path = alternative network with better characteristics.

connection.betterPathUpdateHandler = { betterPathAvailable in
    if betterPathAvailable {
        print("📶 Better path available (e.g., WiFi while on cellular)")
        // Consider migrating to new connection
        self.migrateToNewConnection()
    }
}
Scenarios
  • Connected on cellular, walk into building with WiFi → better path available
  • Connected on WiFi, WiFi quality degrades, cellular available → better path available
Migration pattern
func migrateToNewConnection() {
    // Create new connection
    let newConnection = NWConnection(host: host, port: port, using: parameters)

    newConnection.stateUpdateHandler = { [weak self] state in
        if case .ready = state {
            // New connection ready, switch over
            self?.currentConnection?.cancel()
            self?.currentConnection = newConnection
        }
    }

    newConnection.start(queue: .main)

    // Keep old connection until new one ready
}

Multipath TCP (WWDC 2018 lines 480-487)

Automatically migrate between networks without application intervention.

let parameters = NWParameters.tcp
parameters.multipathServiceType = .handover // Seamless network transition

let connection = NWConnection(host: "example.com", port: 443, using: parameters)
Multipath TCP modes
  • .handover — Seamless handoff between networks (WiFi ↔ cellular)
  • .interactive — Use multiple paths simultaneously (lowest latency)
  • .aggregate — Use multiple paths simultaneously (highest throughput)
Benefits
  • Automatic network transition (no viability handlers needed)
  • No connection interruption when switching networks
  • Fallback to single-path if MPTCP unavailable

NWPathMonitor (WWDC 2018 lines 489-496)

Monitor network state changes (replaces SCNetworkReachability).

import Network

let monitor = NWPathMonitor()

monitor.pathUpdateHandler = { path in
    if path.status == .satisfied {
        print("✅ Network available")

        // Check interface types
        if path.usesInterfaceType(.wifi) {
            print("Using WiFi")
        } else if path.usesInterfaceType(.cellular) {
            print("Using cellular")
        }

        // Check if expensive
        if path.isExpensive {
            print("⚠️ Expensive path (cellular/hotspot)")
        }

    } else {
        print("❌ No network")
    }
}

monitor.start(queue: .main)
Use cases
  • Show "No network" UI when path.status ==.unsatisfied
  • Disable high-bandwidth features when path.isExpensive
  • Adjust quality based on interface type
When to use
  • Global network state monitoring
  • When "waiting for connectivity" isn't enough
  • Need to know available interfaces before connecting
When NOT to use
  • Checking before connecting (use waiting state instead)
  • Per-connection monitoring (use viability handlers instead)

Security Configuration

TLS Version

// iOS 13+ requires TLS 1.2+ by default
let tlsOptions = NWProtocolTLS.Options()

// Allow TLS 1.2 and 1.3
tlsOptions.minimumTLSProtocolVersion = .TLSv12

// Require TLS 1.3 only
tlsOptions.minimumTLSProtocolVersion = .TLSv13

let parameters = NWParameters(tls: tlsOptions)
let connection = NWConnection(host: "example.com", port: 443, using: parameters)

Certificate Pinning

// Production-grade certificate pinning
let tlsOptions = NWProtocolTLS.Options()

sec_protocol_options_set_verify_block(
    tlsOptions.securityProtocolOptions,
    { (metadata, trust, complete) in
        // Get server certificate
        let serverCert = sec_protocol_metadata_copy_peer_public_key(metadata)

        // Compare with pinned certificate
        let pinnedCertData = Data(/* your pinned cert */)
        let serverCertData = SecCertificateCopyData(serverCert) as Data

        if serverCertData == pinnedCertData {
            complete(true) // Accept
        } else {
            complete(false) // Reject (prevents MITM attacks)
        }
    },
    .main
)

let parameters = NWParameters(tls: tlsOptions)

Certificate Pinning + Corporate Proxies

Corporate networks often use TLS inspection proxies that present their own certificates. Strict pinning breaks these environments.

Strategy: Pin against the public key (SPKI) rather than the full certificate, and provide a configuration escape hatch:

sec_protocol_options_set_verify_block(
    tlsOptions.securityProtocolOptions,
    { (metadata, trust, complete) in
        // 1. Check if system trusts the certificate chain (handles corporate CAs)
        let secTrust = sec_trust_copy_ref(trust).takeRetainedValue()
        SecTrustEvaluateAsyncWithError(secTrust, .main) { _, result, _ in
            guard result else { complete(false); return }

            // 2. If pinning enabled, also verify public key
            if PinningConfig.isEnabled {
                let serverKey = SecTrustCopyKey(secTrust)
                let matches = pinnedKeys.contains { $0 == serverKey }
                complete(matches)
            } else {
                complete(true) // System trust only (enterprise mode)
            }
        }
    },
    .main
)

Rules:

  • Always validate system trust first (SecTrustEvaluateAsyncWithError) — this respects enterprise-installed root CAs
  • Use public key pinning over certificate pinning (survives cert rotation)
  • Provide a managed configuration (MDM profile or app config) to disable pinning in enterprise environments
  • Pin at least 2 keys (current + backup) to survive rotation

Cipher Suites

let tlsOptions = NWProtocolTLS.Options()

// Specify allowed cipher suites
tlsOptions.tlsCipherSuites = [
    tls_ciphersuite_t(rawValue: 0x1301), // TLS_AES_128_GCM_SHA256
    tls_ciphersuite_t(rawValue: 0x1302), // TLS_AES_256_GCM_SHA384
]

// iOS defaults to secure modern ciphers, only customize if required

Performance Optimization

User-Space Networking (WWDC 2018 lines 409-441)

Automatic on iOS/tvOS. Network.framework moves TCP/UDP stack into your app process.

Benefits
  • ~30% lower CPU usage (measured with Instruments)
  • No kernel→userspace copy (memory-mapped regions)
  • Reduced context switches
Legacy vs User-Space
Traditional SocketsUser-Space Networking
Packet → driver → kernel → copy → userspacePacket → driver → memory-mapped region → userspace (no copy)
100 datagrams = 100 syscalls100 datagrams = ~1 syscall (with batching)
~30% higher CPUBaseline CPU

WWDC demo Live UDP video streaming showed 30% CPU difference (sockets vs Network.framework).

ECN for UDP (WWDC 2018 lines 365-378)

Explicit Congestion Notification for smooth UDP transmission.

// Create IP metadata with ECN
let ipMetadata = NWProtocolIP.Metadata()
ipMetadata.ecnFlag = .congestionEncountered // Or .ect0, .ect1

// Attach to send context
let context = NWConnection.ContentContext(
    identifier: "video_frame",
    metadata: [ipMetadata]
)

connection.send(content: data, contentContext: context, completion: .contentProcessed { _ in })
ECN flags
  • .ect0 / .ect1 — ECN-capable transport
  • .congestionEncountered — Congestion notification received

Benefits Network can signal congestion without dropping packets.

Service Class (WWDC 2018 lines 379-388)

Mark traffic priority.

// Connection-wide service class
let parameters = NWParameters.tcp
parameters.serviceClass = .background // Low priority

let connection = NWConnection(host: "example.com", port: 443, using: parameters)

// Per-packet service class (UDP)
let ipMetadata = NWProtocolIP.Metadata()
ipMetadata.serviceClass = .realTimeInteractive // High priority (voice)

let context = NWConnection.ContentContext(identifier: "voip", metadata: [ipMetadata])
connection.send(content: audioData, contentContext: context, completion: .contentProcessed { _ in })
Service classes
  • .background — Low priority (large downloads, sync)
  • .default — Normal priority
  • .responsiveData — Interactive data (API calls)
  • .realTimeInteractive — Time-sensitive (voice, gaming)

TCP Fast Open (WWDC 2018 lines 389-406)

Send initial data in TCP SYN packet (saves round trip).

let parameters = NWParameters.tcp
parameters.allowFastOpen = true

let connection = NWConnection(host: "example.com", port: 443, using: parameters)

// Send initial data BEFORE calling start()
let initialData = Data("GET / HTTP/1.1\r\n".utf8)
connection.send(
    content: initialData,
    contentContext: .defaultMessage,
    isComplete: false,
    completion: .idempotent // Data is safe to replay
)

// Now start connection (initial data sent in SYN)
connection.start(queue: .main)

Benefits Reduces connection establishment time by 1 RTT. Requirements Data must be idempotent (safe to replay if SYN retransmitted).


Migration Strategies

From BSD Sockets to NWConnection

BSD SocketsNWConnectionNotes
socket() + connect()NWConnection(host:port:using:) + start()Non-blocking by default
send() / sendto()connection.send(content:completion:)Async callback
recv() / recvfrom()connection.receive(min:max:completion:)Async callback
bind() + listen()NWListener(using:on:)Automatic port binding
accept()listener.newConnectionHandlerCallback per connection
getaddrinfo()Use NWEndpoint.Host(hostname)DNS automatic
SCNetworkReachabilityconnection.stateUpdateHandler waiting stateNo race conditions
setsockopt()NWParametersType-safe options
Migration example
Before (blocking sockets)
int sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, &addr, addrlen); // BLOCKS
send(sock, data, len, 0);
After (NWConnection)
let connection = NWConnection(host: "example.com", port: 443, using: .tls)
connection.stateUpdateHandler = { state in
    if case .ready = state {
        connection.send(content: data, completion: .contentProcessed { _ in })
    }
}
connection.start(queue: .main)

From URLSession StreamTask to NetworkConnection

When to migrate
  • Need UDP (StreamTask only supports TCP)
  • Need custom protocols
  • Need low-level control
When to STAY with URLSession
  • HTTP/HTTPS (URLSession optimized for this)
  • WebSocket support
  • Built-in caching, cookies
Migration example
Before (URLSession StreamTask)
let task = URLSession.shared.streamTask(withHostName: "example.com", port: 443)
task.resume()
task.write(Data("Hello".utf8), timeout: 10) { _ in }
After (NetworkConnection iOS 26+)
let connection = NetworkConnection(to: .hostPort(host: "example.com", port: 443)) { TLS() }
try await connection.send(Data("Hello".utf8))

From NWConnection to NetworkConnection

Benefits of migration
  • Async/await (no callback nesting)
  • No [weak self] needed
  • TLV framing built-in
  • Coder protocol for Codable types
Migration mapping
NWConnectionNetworkConnection
connection.stateUpdateHandler = {}for await state in connection.states {}
connection.send(content:completion:)try await connection.send(content)
connection.receive(min:max:completion:)try await connection.receive(exactly:)
Manual JSONCoder(MyType.self, using:.json)
Custom framerTLV {TLS()}
[weak self] everywhereNo [weak self] needed
Migration example
Before (NWConnection)
connection.stateUpdateHandler = { [weak self] state in
    if case .ready = state {
        self?.sendData()
    }
}

func sendData() {
    connection.send(content: data, completion: .contentProcessed { [weak self] error in
        self?.receiveData()
    })
}
After (NetworkConnection)
Task {
    for await state in connection.states {
        if case .ready = state {
            try await connection.send(data)
            let received = try await connection.receive(exactly: 10).content
        }
    }
}

Testing Checklist

Before shipping networking code:

Device Testing

  • Tested on real device (not just simulator)
  • Tested on multiple iOS versions (12, 15, 26)
  • Tested on iPhone and iPad (different network characteristics)

Network Conditions

  • WiFi (home network)
  • Cellular (disable WiFi)
  • Airplane Mode → WiFi (test waiting state)
  • WiFi → cellular transition (walk out of building)
  • Cellular → WiFi transition (walk into building)
  • Weak signal (basement, elevator)
  • Network Link Conditioner (100ms latency, 3% packet loss)

Network Types

  • IPv4-only network
  • IPv6-only network (some cellular carriers)
  • Dual-stack (IPv4 + IPv6)
  • Corporate VPN active
  • Personal hotspot (expensive path)

Performance

  • Connection establishment < 500ms (check logs)
  • Using batch for UDP (verify with Instruments)
  • Using contentProcessed for pacing (check send timing)
  • Profiled with Instruments Network template
  • CPU usage acceptable (< 10% for networking)
  • Memory stable (no leaks, check [weak self])

Error Handling

  • Handling.waiting state (show "Waiting..." UI)
  • Handling.failed state (specific error messages)
  • TLS handshake errors logged
  • Timeout handling (don't wait forever)
  • User-facing errors actionable ("Check network" not "POSIX 61")

iOS 26+ Features (if using NetworkConnection)

  • Using TLV framing if need message boundaries
  • Using Coder protocol if sending Codable types
  • Using NetworkListener instead of NWListener
  • Using NetworkBrowser for Wi-Fi Aware if peer-to-peer

API Quick Reference

NetworkConnection (iOS 26+)

// Create connection
NetworkConnection(to: .hostPort(host: "example.com", port: 443)) { TLS() }

// Send
try await connection.send(data)

// Receive
try await connection.receive(exactly: n).content

// States
for await state in connection.states { }

// TLV framing
NetworkConnection(to: endpoint) { TLV { TLS() } }

// Coder protocol
NetworkConnection(to: endpoint) { Coder(MyType.self, using: .json) { TLS() } }

// Listener
NetworkListener { TLS() }.run { connection in }

// Browser
NetworkBrowser(for: .wifiAware(...)).run { endpoints in }

NWConnection (iOS 12-25)

// Create connection
let connection = NWConnection(host: "example.com", port: 443, using: .tls)

// State handler
connection.stateUpdateHandler = { [weak self] state in }

// Start
connection.start(queue: .main)

// Send
connection.send(content: data, completion: .contentProcessed { [weak self] error in })

// Receive
connection.receive(minimumIncompleteLength: min, maximumLength: max) { [weak self] data, context, isComplete, error in }

// Viability
connection.viabilityUpdateHandler = { isViable in }

// Better path
connection.betterPathUpdateHandler = { betterPathAvailable in }

// Cancel
connection.cancel()

NWListener (iOS 12-25)

let listener = try NWListener(using: .tcp, on: 1029)
listener.newConnectionHandler = { newConnection in }
listener.start(queue: .main)

NWBrowser (iOS 12-25)

let browser = NWBrowser(for: .bonjour(type: "_http._tcp", domain: nil), using: .tcp)
browser.browseResultsChangedHandler = { results, changes in }
browser.start(queue: .main)

NWPathMonitor

let monitor = NWPathMonitor()
monitor.pathUpdateHandler = { path in }
monitor.start(queue: .main)

Resources

WWDC: 2018-715, 2025-250

Docs: /network, /network/nwconnection, /network/networkconnection

Skills: axiom-networking, axiom-networking-diag


Last Updated 2025-12-02 Status Production-ready reference from WWDC 2018 and WWDC 2025 Coverage NWConnection (iOS 12-25), NetworkConnection (iOS 26+), all 12 WWDC 2025 code examples

平台分布

Claude Code

27.3%
按下载量换算377

Codex

23.2%
按下载量换算321

OpenCode

17.8%
按下载量换算246

Antigravity

12.61%
按下载量换算174

Cursor

8.6%
按下载量换算119

windsurf

3.92%
按下载量换算54

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。

继续浏览同类 Skills