Files
pangolin/client/ios/Runner/AppDelegate.swift
T
wangjia c84b6ea7da merge: maestro/tsk_iP5-_Ztq5THx [桥接 API 面 Channel 契约 + 三端原生骨架] [tsk_rcNKc3GQHBUd]
合并冲突补救:原分支从 merge base 7871512 分叉,仅修改 client/ 目录,
与 main 新增的 server/(apierr/idgen/CONVENTIONS.md) 完全不重叠,
无真实文件冲突,手动应用 feature branch 的全部 client/ 改动。

client 侧新增:
- lib/bridge/vpn_bridge.dart      — Dart↔原生通道契约(冻结)
- lib/bridge/vpn_bridge_mock.dart — 假内核,UI 联调用
- lib/bridge/kernel_process.dart  — 桌面子进程管理接口
- ios/PacketTunnel/{Info.plist,PacketTunnelProvider.swift} — NEPacketTunnel 骨架
- ios/Runner/VpnManager.swift     — NETunnelProviderManager 封装
- android/.../PangolinVpnService.kt — VpnService 骨架
- android/.../VpnEventBus.kt      — Application 级状态总线
- test/bridge/vpn_bridge_mock_test.dart — 桥接层单元测试

client 侧修改:
- android/.../MainActivity.kt    — 注册三通道(MethodChannel + 2×EventChannel)
- android/.../AndroidManifest.xml — 声明 FOREGROUND_SERVICE + PangolinVpnService
- ios/Runner/AppDelegate.swift   — 注册通道 + VpnManager 初始化
- ios/Runner/Info.plist          — 新增 NSVPNUsageDescription
- ios/Runner.xcodeproj/project.pbxproj — 添加 PacketTunnel extension target
- lib/widgets/connect_button.dart — VpnStatus 迁移到 bridge/vpn_bridge.dart
- lib/widgets/home_shell.dart    — error 状态 UI 分支补全
2026-06-13 14:58:38 +08:00

99 lines
3.9 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// AppDelegate.swift Flutter
//
// lib/bridge/vpn_bridge.dart
// MethodChannel : pangolin/vpn
// EventChannel : pangolin/vpn/status VpnStatusStreamHandler
// EventChannel : pangolin/vpn/stats VpnStatsStreamHandler
//
// VpnManager.shared NETunnelProviderManager NEVPNStatus
import UIKit
import Flutter
import NetworkExtension
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
guard let controller = window?.rootViewController as? FlutterViewController else {
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
let messenger = controller.binaryMessenger
// MethodChannel
let vpnChannel = FlutterMethodChannel(name: "pangolin/vpn", binaryMessenger: messenger)
vpnChannel.setMethodCallHandler { [weak self] call, result in
self?.handleVpnMethod(call: call, result: result)
}
// EventChannel: status
FlutterEventChannel(name: "pangolin/vpn/status", binaryMessenger: messenger)
.setStreamHandler(VpnStatusStreamHandler.shared)
// EventChannel: stats
FlutterEventChannel(name: "pangolin/vpn/stats", binaryMessenger: messenger)
.setStreamHandler(VpnStatsStreamHandler.shared)
// VPN
VpnManager.shared.loadFromPreferences { error in
if let error = error {
NSLog("VpnManager: loadFromPreferences error: %@", error.localizedDescription)
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// MethodChannel handler
private func handleVpnMethod(call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "start":
let configJson = call.arguments as? String ?? "{}"
VpnManager.shared.start(configJson: configJson) { error in
if let error = error {
result(FlutterError(
code: "START_FAILED",
message: error.localizedDescription,
details: nil
))
} else {
result(nil)
}
}
case "stop":
VpnManager.shared.stop()
result(nil)
case "getStatus":
result(VpnManager.shared.statusString)
case "selectOutbound":
let tag = call.arguments as? String ?? "auto"
NSLog("VPN: selectOutbound tag=%@", tag)
// TODO(11F): sendProviderMessage PacketTunnelProvider outbound selector
result(nil)
case "getActiveOutbound":
// TODO(11F): query from PacketTunnelProvider via sendProviderMessage
result("auto")
case "setKillSwitch":
let on = call.arguments as? Bool ?? false
NSLog("VPN: setKillSwitch on=%d", on ? 1 : 0)
// TODO(11F): include/excludeRoutes Kill Switch
result(nil)
default:
result(FlutterMethodNotImplemented)
}
}
}