Apple基础(Xcode③-Singbox Core)

brew install go

open ~/.bash_profile

export PATH=”$PATH:$(go env GOPATH)/bin”

先确保工具链完整

go install github.com/sagernet/gomobile/cmd/gomobile@v0.1.4 go install github.com/sagernet/gomobile/cmd/gobind@v0.1.4

gomobile init -v # 关键:-v 会打印详细日志

官方其实有现成的入口,不需要手写 gomobile

# 在源码根目录执行

make lib_install # 安装 gomobile 专用 fork

make lib_ios # 官方脚本会自动修补导出

xcframework successfully written out to: /Users/m/Desktop/sing-box-1.11.0/Libbox.xcframework

✅ 它到底是什么?

一个 Xcode 支持的二进制框架包

内部包含 ios-arm64(真机) ios-arm64_x86_64-simulator(模拟器)

你在 NetworkExtension 里 import Libbox 就能调用 sing-box 的 C/Go API 拖进 Xcode ▸ Embed & Sign 即可使用

如果之前创建过一个相同的项目,然后又删了重新创建这个相同id的项目就会爆错。

同一个 Bundle ID(com.your.vlessdemo 及其子 ID)之前已经注册过,被你手动删掉后,Apple 后台其实还占着坑,导致新的工程下载不到有效的 Provisioning Profile,于是签名时报 “code object is not signed at all”。

彻底清掉旧 ID(要等 24 h)

登录 developer.apple.com → Certificates, IDs & Profiles → Identifiers

在右上角 搜索框 输入 com.your.vlessdemo

如果还能看到旧 ID → 点击 → Delete

24 小时后才能重新注册同名 ID,不推荐。

✅ 1️⃣ 系统 → PacketTunnelProvider

触发点:用户在 iOS 设置里点击“启动”。
iOS 系统会自动调用:

PacketTunnelProvider.startTunnel(options:)

✅ 2️⃣ PacketTunnelProvider → LibboxNewService

startTunnel 里,你把 4 样东西交给 LibboxNewService

// configStr   : 剧本(json)
// platform    : 舞台管理员(PlatformInterface)
// &err        : 错误指针
let svc = LibboxNewService(configStr, platform, &err)

此时 Libbox(sing-box 引擎) 内部会保存这个 platform 对象,但不会立刻用到它

✅ 3️⃣ Libbox 内部 → PlatformInterface.openTun

sing-box 启动后,需要建立 TUN 虚拟网卡,于是它主动调用你实现的:

PlatformInterface.openTun(_ options:ret0_:)
参数 含义
options sing-box 想要的 IP、路由、MTU 等需求
ret0_ 一个返回指针,你必须把 TUN 的文件描述符写进去

✅ 4️⃣ openTun 内部 → iOS 系统

openTun 里,你用 iOS 系统 API 完成三件事:

创建网络设置

let settings = NEPacketTunnelNetworkSettings(...)
settings.mtu = ...
settings.dnsSettings = ...
settings.ipv4Settings = ...
settings.ipv4Settings?.includedRoutes = ...

把设置写入系统

try runBlocking { try await tunnel.setTunnelNetworkSettings(settings) }

把 TUN 文件描述符返回给 sing-box

let tunFd = tunnel.packetFlow.value(forKeyPath: "socket.fileDescriptor") as? Int32 ?? LibboxGetTunnelFileDescriptor()
fd.pointee = tunFd   // ← 写回给 sing-box

✅ 5️⃣ sing-box 收到文件描述符后

sing-box 拿到 tunFd,就可以:

从 TUN 读 IP 数据包(用户 App 发出的流量)

做代理/路由处理

把结果再写回 TUN

✅ 6️⃣ 用户关闭 VPN 时

系统调用:

PacketTunnelProvider.stopTunnel(with:completionHandler:)

你在里面:

try? service?.close()   // 通知 sing-box 关机
completionHandler()     // 告诉系统“我已清理完毕”

✅ 完整“谁调谁”链路图

iOS 系统
   │ 1️⃣ startTunnel
   ▼
PacketTunnelProvider
   │ 2️⃣ LibboxNewService(config, platform)
   ▼
sing-box 引擎
   │ 3️⃣ platform.openTun(options, &fd)
   ▼
PlatformInterface
   │ 4️⃣ setTunnelNetworkSettings(settings)
   ▼
iOS 网络栈
   │ 5️⃣ 返回 tunFd 给 sing-box
   ▼
sing-box 开始转发流量

架构详解 – 新手小白版

📋 文件职责分工

1️⃣ PacketTunnelProvider.swift – 总经理

class PacketTunnelProvider: NEPacketTunnelProvider {
    // "总指挥"
}

主要职责:

🎯 启动连接:startTunnel() – 接收iOS系统的启动命令

📁 准备工作环境:创建工作目录、缓存目录

⚙️ 初始化sing-box:调用LibboxSetup()设置Go运行环境

📖 读取配置:获取VLESS服务器配置、分流规则

🔧 创建服务:调用LibboxNewService()创建代理服务

🛑 停止:stopTunnel() – 清理资源

代码流程:

startTunnel() {
    1. 创建工作目录
    2. 调用 LibboxSetup() 
    3. 读取配置文件
    4. 创建 PlatformInterface
    5. 调用 LibboxNewService(配置, PlatformInterface)
    6. 启动服务
}

2️⃣ PlatformInterface.swift – 技术顾问

class PlatformInterface: NSObject, LibboxPlatformInterfaceProtocol {
    // 这是iOS系统和Go代码的"翻译官"
}

主要职责:

🌐 网络设置:openTun() – 设置TUN接口、DNS、路由

🔌 系统桥梁:让Go代码能调用iOS系统功能

📝 日志输出:writeLog() – 转发sing-box日志到iOS

🚫 功能适配:禁用iOS不支持的功能

核心方法:

func openTun() {
    1. 设置DNS服务器 (8.8.8.8)
    2. 配置IPv4地址和路由
    3. 应用网络设置到iOS系统
    4. 获取TUN接口文件描述符
    5. 返回给Go代码使用
}

💡 关键设计思想

🎯 为什么需要PlatformInterface?

Go语言限制:Go代码无法直接调用iOS系统API

沙盒隔离:NetworkExtension有严格的权限限制

系统集成:需要设置DNS、路由、TUN接口等iOS特有功能

🔄 为什么分成两个文件?

职责分离:总经理管大局,技术顾问管细节

代码复用:PlatformInterface可以给其他项目复用

维护方便:网络设置相关代码集中在一起

🎉 总结

这个架构巧妙地解决了Go语言sing-box与iOS NetworkExtension的兼容性问题:

PacketTunnelProvider:iOS的标准入口,负责整体流程控制

PlatformInterface:iOS与Go的桥梁,提供系统级功能

Libbox:强大的网络代理引擎,处理实际的流量转发

通过这种设计,成功实现了国内IP走代理,国外IP直连的智能分流!🚀

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容