Administrator
发布于 2025-03-07 / 1141 阅读

SDK ios集成文档

IOS集成

1. 初始化不需要task了

2. object-c的方法名
startWithPort
startNoPort

一、IOS

1.下载导入SDK

下载 Proxy.framework.zip,解压后,将文件夹放到项目文件,Embed 设置为 Embed & sign,最小版本为ios 15.6

swift

增加头文件,文件名随意,

Objective-C Bridging Header -> Header.h

主要是 #import <Proxy/Proxy.h>

#ifndef Header_h
#define Header_h

#import <Proxy/Proxy.h>

#endif /* Header_h */

object-c

不需要添加头文件

2.初始化

1. 在AppDelegate.swift文件中通过initWith初始化

swift

import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(
        _: UIApplication,
        didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        WaylProxy.initWith(self)

        return true
    }
}

import SwiftUI

@main
struct App: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

object-c

#import "AppDelegate.h"
@import Proxy;
@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [WaylProxy initWith:self completion:^{
        NSLog(@"WaylProxy 初始化");
    }];
    
    // Override point for customization after application launch.
    return YES;
}


#pragma mark - UISceneSession lifecycle


- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}


- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}


@end

2. 或者在入口文件

因为sdk需要向服务器发送请求,所以要在app有网络访问权限后再调用初始化sdk

swift

import SwiftUI

@main
struct App: App {
    // 如果不想使用UIApplicationDelegateAdaptor,请用 Proxy.shared.initial()
    // 不要在init中调用 Proxy.shared.initial() 会阻塞进程
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    WaylProxy.shared.initial()
                }
        }
    }
}

3. 在info.plist文件添加uuid

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.wayl.proxy.UUID</key>
    <string>****************</string>
</dict>
</plist>

3.功能使用

启动代理,传入需要的端口号,启动成功以后将监听该本地端口的所有请求,千万不要传10808端口,10808已经被sdk占用

// swift
let proxy = WaylProxy.shared
let result = await proxy.start(port: 10808)

// 或者不传入端口,由sdk自己随机生成一个端口
let result = await proxy.start()

// object-c
[[WaylProxy shared] startWithPort:10808 completion:^(Result *result) {
    dispatch_async(dispatch_get_main_queue(), ^{

    });
}];
// 或者不传入端口,由sdk自己随机生成一个端口 因为object-c不能重载方法,因此方法名是 startNoPort
[[WaylProxy shared] startNoPort: ^(Result *result) {
    dispatch_async(dispatch_get_main_queue(), ^{

    });
}];

也可以调用该方法先拿到一个空闲端口

getFreePorts()

停止代理服务

stop()

清除代理服务,该方法会清除掉所有的代理数据,(清理以后,是无法再次调用启动方法,需要初始化重新开启)

clear()

获取sdk版本号

getVersion()

4.接口文档

swift

@objc public protocol ProxyDelegate {

    /// 当安装状态发生变化时回调
    @objc func onInitStatusChanged(_ newStatus: Bool)

    /// 当验证状态发生变化时回调
    @objc func onValidationStatusChanged(_ newStatus: Bool)

    /// 当代理服务启动状态发生变化时回调
    @objc func onStartStatusChanged(_ newStatus: Bool)
}

@objcMembers public class Result : NSObject, @unchecked Sendable {

    /// 表示操作是否成功
    public let success: Bool

    /// 包含结果数据的对象
    public let data: Proxy.ResultData?

    /// 相关的消息
    public let message: String?

    /// 初始化一个 `Result` 实例
    /// - Parameters:
    ///   - success: 操作是否成功
    ///   - data: 结果数据
    ///   - message: 相关消息
    public init(success: Bool, data: Proxy.ResultData?, message: String?)

    /// 转换为字典
    /// - Returns: 包含 success, data 和 message 的字典
    public func toDictionary() -> [String : Any]
}

@objcMembers public class ResultData : NSObject {

    /// 端口号
    public var port: NSNumber?

    /// 用字典初始化 `ResultData` 实例
    /// - Parameter dictionary: 包含端口号的字典
    public init(dictionary: [String : Any])

    /// 转换为字典
    /// - Returns: 包含 port 的字典
    public func toDictionary() -> [String : Any]
}

@objc public class WaylProxy : NSObject {

    /// 当前 SDK 版本号
    @objc public static let sdkVersion: String

    /// 单例对象,用于访问 WaylProxy
    @objc public static let shared: Proxy.WaylProxy

    /// 代理(监听器)对象,用于接收状态更新回调
    @objc weak public var delegate: (any Proxy.ProxyDelegate)?

    /// 对外只读 初始化状态
    @objc public var initiated: Bool { get }

    /// 对外只读 套餐验证状态
    @objc public var isValidated: Bool { get }

    /// 对外只读 代理开启状态
    @objc public var isStarted: Bool { get }

    /// 异步初始化方法,仅供 Swift 使用
    /**
     * [Swift] 异步初始化代理
     *
     * 该方法用于在 Swift 环境中异步初始化代理服务。
     * 它接收一个代理对象,该代理必须遵守 `WaylProxyDelegate` 协议,并在异步过程中更新状态。
     *
     * **Swift 使用示例:**
     * ```swift
     * WaylProxy.initWith(delegate)
     * ```
     *
     * **注意:** 该方法仅供 Swift 调用,不适用于 Objective-C。
     */
    public class func initWith(_ delegate: AnyObject)

    /// 异步初始化代理服务,仅供 Swift 使用
    /**
     * [Swift] 异步初始化代理服务
     *
     * 此方法在 Swift 环境中用于初始化代理服务,检查必要的配置和网络状态,
     * 并返回一个 `Result` 对象表示初始化结果。
     *
     * **Swift 使用示例:**
     * ```swift
     * let result = WaylProxy.shared.initial()
     * print(result.message ?? "未知错误")
     * ```
     *
     * **注意:** 该方法仅供 Swift 调用,不适用于 Objective-C。
     */
    @discardableResult
    public func initial() -> Proxy.Result

    /// 异步启动代理服务,仅供 Swift 使用
    /**
     * [Swift] 异步启动代理服务
     *
     * 该方法在 Swift 中用于启动代理服务,会检查代理是否已初始化和验证,
     * 如果条件满足,则在指定端口启动代理服务,并返回一个 `Result` 对象表示启动结果。
     *
     * **Swift 使用示例:**
     * ```swift
     * let result = await WaylProxy.shared.start(port: 10808)
     * print(result.message ?? "未知错误")
     * ```
     *
     * **注意:** 该方法仅供 Swift 调用,不适用于 Objective-C。
     */
    public func start(port: Int) async -> Proxy.Result

    /// 异步启动代理服务(自动选择端口),仅供 Swift 使用
    /**
     * 该方法在 Swift 中用于启动代理服务,会自动选择一个可用端口启动服务,并返回启动结果。
     *
     * **返回:**
     * - `Result` 对象,包含代理启动状态和使用的端口信息。
     *
     * **Swift 使用示例:**
     * ```swift
     * let result = await WaylProxy.shared.start()
     * print(result.message ?? "未知错误")
     * ```
     *
     * **注意:** 该方法仅供 Swift 调用,不适用于 Objective-C。
     */
    public func start() async -> Proxy.Result

    /// 停止代理服务
    /**
     * 停止当前的代理服务,并重置代理状态。
     *
     * **Swift 调用示例:**
     * ```swift
     * WaylProxy.shared.stop()
     * ```
     *
     * **Objective-C 调用示例:**
     * ```objc
     * [[WaylProxy shared] stop];
     * ```
     */
    @objc public func stop()

    /// 获取可用端口
    /**
     * 获取当前可用的端口信息。
     *
     * - Returns: `Result` 对象,包含可用端口的信息。
     *
     * **Swift 调用示例:**
     * ```swift
     * let result = WaylProxy.shared.getFreePorts()
     * print(result.message ?? "未知错误")
     * ```
     *
     * **Objective-C 调用示例:**
     * ```objc
     * Result *result = [[WaylProxy shared] getFreePorts];
     * NSLog(@"可用端口信息: %@", result.message);
     * ```
     */
    @objc public func getFreePorts() -> Proxy.Result

    /// 清理代理状态
    /**
     * 清理代理的所有状态信息,包括重置标志位和清除钥匙串中的数据。
     *
     * **Swift 调用示例:**
     * ```swift
     * WaylProxy.shared.clear()
     * ```
     *
     * **Objective-C 调用示例:**
     * ```objc
     * [[WaylProxy shared] clear];
     * ```
     */
    @objc public func clear()

    /// 获取 SDK 版本号
    /// - Returns: 当前 SDK 的版本号字符串
    @objc public func getVersion() -> String
}

object-c

SWIFT_PROTOCOL("_TtP5Proxy13ProxyDelegate_")
@protocol ProxyDelegate
/// 当安装状态发生变化时回调
- (void)onInitStatusChanged:(BOOL)newStatus;
/// 当验证状态发生变化时回调
- (void)onValidationStatusChanged:(BOOL)newStatus;
/// 当代理服务启动状态发生变化时回调
- (void)onStartStatusChanged:(BOOL)newStatus;
@end

@class ResultData;
@class NSString;
SWIFT_CLASS("_TtC5Proxy6Result")
@interface Result : NSObject
/// 表示操作是否成功
@property (nonatomic, readonly) BOOL success;
/// 包含结果数据的对象
@property (nonatomic, readonly, strong) ResultData * _Nullable data;
/// 相关的消息
@property (nonatomic, readonly, copy) NSString * _Nullable message;
/// 初始化一个 <code>Result</code> 实例
/// \param success 操作是否成功
///
/// \param data 结果数据
///
/// \param message 相关消息
///
- (nonnull instancetype)initWithSuccess:(BOOL)success data:(ResultData * _Nullable)data message:(NSString * _Nullable)message OBJC_DESIGNATED_INITIALIZER;
/// 转换为字典
///
/// returns:
/// 包含 success, data 和 message 的字典
- (NSDictionary<NSString *, id> * _Nonnull)toDictionary SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
@end

@class NSNumber;
SWIFT_CLASS("_TtC5Proxy10ResultData")
@interface ResultData : NSObject
/// 端口号
@property (nonatomic, strong) NSNumber * _Nullable port;
/// 用字典初始化 <code>ResultData</code> 实例
/// \param dictionary 包含端口号的字典
///
- (nonnull instancetype)initWithDictionary:(NSDictionary<NSString *, id> * _Nonnull)dictionary OBJC_DESIGNATED_INITIALIZER;
/// 转换为字典
///
/// returns:
/// 包含 port 的字典
- (NSDictionary<NSString *, id> * _Nonnull)toDictionary SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
@end

SWIFT_CLASS("_TtC5Proxy9WaylProxy")
@interface WaylProxy : NSObject
/// 当前 SDK 版本号
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, copy) NSString * _Nonnull sdkVersion;)
+ (NSString * _Nonnull)sdkVersion SWIFT_WARN_UNUSED_RESULT;
/// 单例对象,用于访问 WaylProxy
SWIFT_CLASS_PROPERTY(@property (nonatomic, class, readonly, strong) WaylProxy * _Nonnull shared;)
+ (WaylProxy * _Nonnull)shared SWIFT_WARN_UNUSED_RESULT;
/// 代理(监听器)对象,用于接收状态更新回调
@property (nonatomic, weak) id <ProxyDelegate> _Nullable delegate;
/// 对外只读 初始化状态
@property (nonatomic, readonly) BOOL initiated;
/// 对外只读 套餐验证状态
@property (nonatomic, readonly) BOOL isValidated;
/// 对外只读 代理开启状态
@property (nonatomic, readonly) BOOL isStarted;
/// 防止外部初始化
/// 此初始化方法为私有,防止外部直接创建 WaylProxy 实例。
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable");
/// 异步初始化方法的包装,仅供 Objective-C 使用
/// [Objective-C] 异步初始化代理的包装方法
/// 该方法为 Objective-C 提供了异步初始化代理服务的接口。
/// 传入一个代理对象(必须遵守 <code>WaylProxyDelegate</code> 协议)和一个完成回调,
/// 在初始化完成后回调执行。
/// <em>Objective-C 使用示例:</em>
/// \code
/// [WaylProxy initWith:self completion:^{
///    NSLog(@"WaylProxy 初始化");
/// }];
///
/// \endcode<em>注意:</em> 该方法仅供 Objective-C 调用,不适用于 Swift。
+ (void)initWith:(id _Nonnull)delegate completion:(void (^ _Nonnull)(void))completion SWIFT_METHOD_FAMILY(none);
/// 异步初始化代理服务的包装方法,仅供 Objective-C 使用
/// [Objective-C] 异步初始化代理服务的包装方法
/// 为 Objective-C 提供异步初始化代理服务的接口,
/// 通过回调返回一个 <code>Result</code> 对象表示初始化结果。
/// <em>Objective-C 使用示例:</em>
/// \code
/// [[WaylProxy shared] initial:^(Result *result) {
///    NSLog(@"初始化结果: %@", result.message);
/// }];
///
/// \endcode<em>注意:</em> 该方法仅供 Objective-C 调用,不适用于 Swift。
- (void)initial:(void (^ _Nonnull)(Result * _Nonnull))completion;
/// 异步启动代理服务的包装方法,仅供 Objective-C 使用
/// [Objective-C] 异步启动代理服务的包装方法
/// 为 Objective-C 提供启动代理服务的接口,
/// 通过回调返回一个 <code>Result</code> 对象表示启动结果。
/// <em>Objective-C 使用示例:</em>
/// \code
/// [[WaylProxy shared] start:10808 completion:^(Result *result) {
///    NSLog(@"代理启动状态: %@", result.message);
/// }];
///
/// \endcode<em>注意:</em> 该方法仅供 Objective-C 调用,不适用于 Swift。
- (void)startWithPort:(NSInteger)port completion:(void (^ _Nonnull)(Result * _Nonnull))completion;
/// 异步启动代理服务(自动选择端口)的包装方法,仅供 Objective-C 使用
/// 该方法为 Objective-C 提供自动选择端口启动代理服务的接口,
/// 通过回调返回启动结果。
/// <em>Objective-C 使用示例:</em>
/// \code
/// [[WaylProxy shared] startNoPort:^(Result *result) {
///    NSLog(@"代理启动状态: %@", result.message);
/// }];
///
/// \endcode<em>注意:</em> 该方法仅供 Objective-C 调用,不适用于 Swift。
/// \param completion 完成回调,返回 <code>Result</code> 对象表示启动结果。
///
- (void)startNoPort:(void (^ _Nonnull)(Result * _Nonnull))completion;
/// 停止代理服务
/// 停止当前的代理服务,并重置代理状态。
/// <em>Swift 调用示例:</em>
/// \code
/// WaylProxy.shared.stop()
///
/// \endcode<em>Objective-C 调用示例:</em>
/// \code
/// [[WaylProxy shared] stop];
///
/// \endcode
- (void)stop;
/// 获取可用端口
/// 获取当前可用的端口信息。
/// <em>Swift 调用示例:</em>
/// \code
/// let result = WaylProxy.shared.getFreePorts()
/// print(result.message ?? "未知错误")
///
/// \endcode<em>Objective-C 调用示例:</em>
/// \code
/// Result *result = [[WaylProxy shared] getFreePorts];
/// NSLog(@"可用端口信息: %@", result.message);
///
/// \endcode
/// returns:
/// <code>Result</code> 对象,包含可用端口的信息。
- (Result * _Nonnull)getFreePorts SWIFT_WARN_UNUSED_RESULT;
/// 清理代理状态
/// 清理代理的所有状态信息,包括重置标志位和清除钥匙串中的数据。
/// <em>Swift 调用示例:</em>
/// \code
/// WaylProxy.shared.clear()
///
/// \endcode<em>Objective-C 调用示例:</em>
/// \code
/// [[WaylProxy shared] clear];
///
/// \endcode
- (void)clear;
/// 获取 SDK 版本号
///
/// returns:
/// 当前 SDK 的版本号字符串
- (NSString * _Nonnull)getVersion SWIFT_WARN_UNUSED_RESULT;
@end

5.例子

使用了监听器展示一个相对完整的例子,也可以不使用,看项目实际情况

import SwiftUI

struct ContentView: View {
    @StateObject private var delegate = Delegate() // 创建 ProxyDelegate 实例
    @State private var logMessage = ""
    @State private var launchTime = Date()
    @State private var initiatedTime: Date?
    @State private var validatedTime: Date?

    var body: some View {
        VStack(spacing: 20) {
            if !delegate.initiated {
                ProgressView("正在初始化...")
                    .progressViewStyle(CircularProgressViewStyle())
            } else {
                Button(action: {
                    toggle()
                }) {
                    Text(delegate.isRunning ? "停止" : "开启")
                        .foregroundColor(.white)
                        .padding()
                        .frame(maxWidth: .infinity)
                        .background(delegate.isRunning ? Color.red : Color.green)
                        .cornerRadius(10)
                }
                .disabled(!delegate.initiated || !delegate.isValidated) // 初始化未完成或未验证通过时禁用按钮
            }

            // 显示状态信息
            VStack(spacing: 10) {
                HStack {
                    Text("初始化状态:")
                        .bold()
                    Text(!delegate.initiated ? "进行中" : "完成")
                        .foregroundColor(!delegate.initiated ? .orange : .green)
                }
                HStack {
                    Text("验证状态:")
                        .bold()
                    Text(delegate.isValidated ? "通过" : "未通过")
                        .foregroundColor(delegate.isValidated ? .green : .red)
                }
                HStack {
                    Text("代理状态:")
                        .bold()
                    Text(delegate.isRunning ? "已开启" : "已关闭")
                        .foregroundColor(delegate.isRunning ? .green : .red)
                }
            }
            .padding()
            .background(Color(UIColor.secondarySystemBackground))
            .cornerRadius(10)

            Text(logMessage)
                .padding()
                .foregroundColor(.gray)
                .multilineTextAlignment(.center)
        }
        .padding()
        .onAppear {
            initializeProxy()
            print("程序启动时间:\(launchTime)")
        }
        .onChange(of: delegate.initiated) { _, newValue in
            if newValue {
                initiatedTime = Date()
                let interval = initiatedTime!.timeIntervalSince(launchTime)
                print("✅ 初始化完成时间:\(initiatedTime!)")
                print("⏱️ 初始化耗时:\(interval) 秒")
                checkAndStartProxy()
            }
        }
        .onChange(of: delegate.isValidated) { _, newValue in
            if newValue {
                validatedTime = Date()
                let interval = validatedTime!.timeIntervalSince(launchTime)
                print("✅ 验证通过时间:\(validatedTime!)")
                print("⏱️ 验证耗时:\(interval) 秒")
            }
            
        }
    }

    /// 初始化 WaylProxy
    func initializeProxy() {
        // 设置代理
        WaylProxy.shared.delegate = delegate

        Task {
            // 调用异步初始化方法,如果使用委托就不要用这个
            // await WaylProxy.shared.initial()
            DispatchQueue.main.async {
                delegate.initiated = true // 初始化完成
            }
        }
    }

    func checkAndStartProxy() {
        if delegate.initiated && !delegate.isRunning {
            Task {
                print("🔵 检测到已初始化和验证通过,准备启动代理...")
                let result = await WaylProxy.shared.start()
                print("🟢 启动代理返回:\(result)")

                if let port = result.data?.port {
                    print("✅ 获取到端口:\(port)")
                    logMessage = "启动成功,端口: \(port)"
                    delegate.isRunning = true

                    let currentTime = Date()
                    let interval = currentTime.timeIntervalSince(launchTime)
                    print("📗 开启代理成功时间:\(currentTime)")
                    print("⏱️ 启动耗时:\(interval) 秒")
                } else {
                    print("❌ 启动失败,message: \(result.message ?? "无错误信息")")
                    logMessage = result.message ?? "启动失败"
                    delegate.isRunning = false
                }
            }
        }
    }

    /// 启动或停止
    func toggle() {
        let proxy = WaylProxy.shared

        Task {
            if delegate.isRunning {
                proxy.stop()
                logMessage = "已停止"
                delegate.isRunning = false
            } else {
                let result = await proxy.start()              // 不带端口

                DispatchQueue.main.async {
                    if let port = result.data?.port {
                        logMessage = "启动成功,端口: \(port)"
                        delegate.isRunning = true
                        let currentTime = Date()
                        let interval = currentTime.timeIntervalSince(launchTime)
                        print("开启代理成功时间:\(currentTime)")
                        print("启动耗时:\(interval) 秒")
                    } else {
                        logMessage = result.message ?? "启动失败"
                        delegate.isRunning = false
                    }
                }
            }
        }
    }
}

class Delegate: NSObject, ProxyDelegate, ObservableObject {
    @Published var initiated: Bool = false
    @Published var isValidated: Bool = false
    @Published var isRunning: Bool = false

    func onInitStatusChanged(_ newStatus: Bool) {
        DispatchQueue.main.async {
            self.initiated = newStatus
        }
    }

    func onValidationStatusChanged(_ newStatus: Bool) {
        DispatchQueue.main.async {
            self.isValidated = newStatus
        }
    }

    func onStartStatusChanged(_ newStatus: Bool) {
        DispatchQueue.main.async {
            self.isRunning = newStatus
        }
    }
}

object-c

#import "ViewController.h"
#import <Proxy/Proxy.h>

@interface ViewController () <ProxyDelegate>

@property (nonatomic, strong) UIButton *toggleButton;
@property (nonatomic, strong) UILabel *logLabel;
@property (nonatomic, strong) UILabel *initializedLabel;
@property (nonatomic, strong) UILabel *validateLabel;
@property (nonatomic, strong) UILabel *startLabel;
@property (nonatomic, assign) BOOL isRunning;
@property (nonatomic, strong) NSDate *startTimestamp; // New property

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"程序启动时间:%@", [NSDate date]);
    
    self.startTimestamp = [NSDate date]; // Set the timestamp
    
    self.isRunning = NO;
    
    // 创建按钮
    self.toggleButton = [UIButton buttonWithType:UIButtonTypeSystem];
    self.toggleButton.frame = CGRectMake(50, 100, self.view.frame.size.width - 100, 50);
    [self.toggleButton setTitle:@"Start" forState:UIControlStateNormal];
    [self.toggleButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    self.toggleButton.backgroundColor = [UIColor greenColor];
    self.toggleButton.layer.cornerRadius = 10;
    [self.toggleButton addTarget:self action:@selector(toggle) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.toggleButton];
    
    // 创建日志标签
    self.logLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 200, self.view.frame.size.width - 40, 50)];
    self.logLabel.textAlignment = NSTextAlignmentCenter;
    self.logLabel.textColor = [UIColor grayColor];
    self.logLabel.numberOfLines = 0;
    self.logLabel.text = @"";
    [self.view addSubview:self.logLabel];
    
    // 创建状态标签
    self.initializedLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 260, self.view.frame.size.width - 40, 40)];
    self.initializedLabel.textAlignment = NSTextAlignmentCenter;
    self.initializedLabel.textColor = [UIColor grayColor];
    self.initializedLabel.backgroundColor = [UIColor colorWithRed:0.678 green:0.847 blue:0.902 alpha:1.0]; // 淡蓝
    self.initializedLabel.font = [UIFont boldSystemFontOfSize:17];
    self.initializedLabel.layer.cornerRadius = 10;
    self.initializedLabel.clipsToBounds = YES;
    [self.view addSubview:self.initializedLabel];
    
    self.validateLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 310, self.view.frame.size.width - 40, 40)];
    self.validateLabel.textAlignment = NSTextAlignmentCenter;
    self.validateLabel.textColor = [UIColor grayColor];
    self.validateLabel.backgroundColor = [UIColor colorWithRed:0.980 green:0.980 blue:0.600 alpha:1.0]; // 淡黄
    self.validateLabel.font = [UIFont boldSystemFontOfSize:17];
    self.validateLabel.layer.cornerRadius = 10;
    self.validateLabel.clipsToBounds = YES;
    [self.view addSubview:self.validateLabel];
    
    self.startLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 360, self.view.frame.size.width - 40, 40)];
    self.startLabel.textAlignment = NSTextAlignmentCenter;
    self.startLabel.textColor = [UIColor grayColor];
    self.startLabel.backgroundColor = [UIColor colorWithRed:0.678 green:1.000 blue:0.678 alpha:1.0]; // 淡绿
    self.startLabel.font = [UIFont boldSystemFontOfSize:17];
    self.startLabel.layer.cornerRadius = 10;
    self.startLabel.clipsToBounds = YES;
    [self.view addSubview:self.startLabel];
    
    // 获取 Info.plist 中的 com.wayl.proxy.UUID
    NSString *proxyUUID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"com.wayl.proxy.UUID"];
    if (proxyUUID) {
        NSLog(@"com.wayl.proxy.UUID: %@", proxyUUID);
    } else {
        NSLog(@"com.wayl.proxy.UUID 未找到");
    }
    
    // 设置代理
    WaylProxy.shared.delegate = self;
}

- (void)toggle {
    if (self.isRunning) {
        // 停止代理
        [[WaylProxy shared] stop];
        self.logLabel.text = @"已停止";
        self.isRunning = NO;
        self.toggleButton.backgroundColor = [UIColor greenColor];
        [self.toggleButton setTitle:@"Start" forState:UIControlStateNormal];
    } else {
        // 启动代理 (后台线程执行)
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//            [[WaylProxy shared] startWithPort:10808 completion:^(Result *result) {   //带端口
            [[WaylProxy shared] startNoPort :^(Result *result) {               //不带端口
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.logLabel.text = result.message ?: @"未知错误";
                    if (result.data && result.data.port != nil) {
                        NSInteger port = result.data.port.integerValue;
                        NSString *portMessage = [NSString stringWithFormat:@"端口号: %ld", (long)port];
                        self.logLabel.text = [self.logLabel.text stringByAppendingFormat:@"\n%@", portMessage];
                    }
                    self.isRunning = result.success;
                    self.toggleButton.backgroundColor = result.success ? [UIColor redColor] : [UIColor greenColor];
                    [self.toggleButton setTitle:result.success ? @"Stop" : @"Start" forState:UIControlStateNormal];
                });
            }];
        });
    }
}

// ProxyDelegate 方法实现
- (void)onInitStatusChanged:(BOOL)newStatus {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.initializedLabel.text = newStatus ? @"初始化成功" : @"初始化失败";
        if (newStatus) {
            [[WaylProxy shared] startNoPort:^(Result *result) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.logLabel.text = result.message ?: @"未知错误";
                    if (result.data && result.data.port != nil) {
                        NSInteger port = result.data.port.integerValue;
                        NSString *portMessage = [NSString stringWithFormat:@"端口号: %ld", (long)port];
                        self.logLabel.text = [self.logLabel.text stringByAppendingFormat:@"\n%@", portMessage];
                    }
                    self.isRunning = result.success;
                    self.toggleButton.backgroundColor = result.success ? [UIColor redColor] : [UIColor greenColor];
                    [self.toggleButton setTitle:result.success ? @"Stop" : @"Start" forState:UIControlStateNormal];
                    
                    NSDate *now = [NSDate date];
                    NSTimeInterval interval = [now timeIntervalSinceDate:self.startTimestamp];
                    NSString *timeCost = [NSString stringWithFormat:@"启动耗时:%.2f 秒", interval];
                    NSLog(@"%@", timeCost);
                    self.logLabel.text = [self.logLabel.text stringByAppendingFormat:@"\n%@", timeCost];
                });
            }];
        }
    });
}

- (void)onValidationStatusChanged:(BOOL)newStatus {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.validateLabel.text = newStatus ? @"验证成功" : @"验证失败";
        
    });
}

- (void)onStartStatusChanged:(BOOL)newStatus {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.startLabel.text = newStatus ? @"代理开启" : @"代理关闭";
    });
}

@end