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