JavaScript桥接高级用法详解

52 阅读16分钟

1. 高级JavaScript桥接架构

1.1 完整的双向通信系统


import WebKit

import UIKit

  


// MARK: - 消息协议定义

protocol JavaScriptMessageProtocol: Codable {

    var id: String { get set }

    var method: String { get }

    var params: [String: Any] { get }

    var timestamp: Date { get }

}

  


struct RequestMessage: JavaScriptMessageProtocol {

    var id: String

    let method: String

    let params: [String: Any]

    let timestamp: Date

    

    init(id: String = UUID().uuidString, method: String, params: [String: Any] = [:]) {

        self.id = id

        self.method = method

        self.params = params

        self.timestamp = Date()

    }

}

  


struct ResponseMessage: Codable {

    let id: String

    let success: Bool

    let result: Any?

    let error: String?

    let timestamp: Date

}

  


// MARK: - 高级桥接管理器

class AdvancedJavaScriptBridge: NSObject {

    

    // MARK: - Properties

    weak var webView: WKWebView?

    private let userContentController: WKUserContentController

    private var messageHandlers: [String: MessageHandler] = [:]

    private var pendingRequests: [String: (ResponseMessage) -> Void] = [:]

    private let queue = DispatchQueue(label: "jsbridge.queue", qos: .userInitiated)

    

    // MARK: - 消息处理器协议

    protocol MessageHandler {

        func handleMessage(_ message: RequestMessage, 

                          completion: @escaping (ResponseMessage) -> Void)

    }

    

    // MARK: - 初始化

    init(webView: WKWebView) {

        let config = webView.configuration

        self.userContentController = config.userContentController

        self.webView = webView

        super.init()

        

        setupDefaultHandlers()

        injectJavaScriptBridge()

    }

    

    // MARK: - 默认处理器设置

    private func setupDefaultHandlers() {

        // 通用处理器

        registerHandler("log", handler: LogHandler())

        registerHandler("storage", handler: StorageHandler())

        registerHandler("device", handler: DeviceHandler())

        registerHandler("network", handler: NetworkHandler())

        registerHandler("camera", handler: CameraHandler())

        registerHandler("location", handler: LocationHandler())

    }

    

    // MARK: - JavaScript桥接注入

    private func injectJavaScriptBridge() {

        let bridgeScript = """

        (function() {

            // 高级JavaScript桥接实现

            window.JSBridge = {

                _messageId: 0,

                _callbacks: {},

                _queue: [],

                

                // 发送消息到原生

                callNative: function(method, params, callback) {

                    var messageId = 'msg_' + (++this._messageId);

                    var message = {

                        id: messageId,

                        method: method,

                        params: params || {},

                        timestamp: Date.now()

                    };

                    

                    if (callback) {

                        this._callbacks[messageId] = callback;

                    }

                    

                    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.bridge) {

                        window.webkit.messageHandlers.bridge.postMessage(message);

                    } else {

                        this._queue.push(message);

                    }

                    

                    return messageId;

                },

                

                // 处理原生响应

                handleNativeResponse: function(response) {

                    var callback = this._callbacks[response.id];

                    if (callback) {

                        callback(response.success, response.result, response.error);

                        delete this._callbacks[response.id];

                    }

                },

                

                // 批量调用

                batchCall: function(calls, callback) {

                    var results = [];

                    var completed = 0;

                    var total = calls.length;

                    

                    var batchCallback = function(success, result, error) {

                        results.push({success: success, result: result, error: error});

                        completed++;

                        

                        if (completed === total) {

                            if (callback) {

                                callback(results);

                            }

                        }

                    };

                    

                    calls.forEach(function(call) {

                        this.callNative(call.method, call.params, batchCallback);

                    });

                },

                

                // 订阅/发布模式

                subscribe: function(event, callback) {

                    if (!window.JSBridge._subscriptions) {

                        window.JSBridge._subscriptions = {};

                    }

                    if (!window.JSBridge._subscriptions[event]) {

                        window.JSBridge._subscriptions[event] = [];

                    }

                    window.JSBridge._subscriptions[event].push(callback);

                },

                

                publish: function(event, data) {

                    if (window.JSBridge._subscriptions && window.JSBridge._subscriptions[event]) {

                        window.JSBridge._subscriptions[event].forEach(function(callback) {

                            callback(data);

                        });

                    }

                },

                

                // 工具方法

                ready: function(callback) {

                    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.bridge) {

                        callback();

                    } else {

                        var checkReady = setInterval(function() {

                            if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.bridge) {

                                clearInterval(checkReady);

                                callback();

                            }

                        }, 100);

                    }

                }

            };

            

            // 全局错误处理

            window.addEventListener('error', function(e) {

                JSBridge.callNative('error', {

                    type: 'js_error',

                    message: e.message,

                    filename: e.filename,

                    lineno: e.lineno

                });

            });

            

            // 性能监控

            if (performance && performance.mark) {

                JSBridge.callNative('performance', {

                    type: 'page_load_start',

                    navigationStart: performance.timing.navigationStart

                });

            }

        })();

        """

        

        let userScript = WKUserScript(

            source: bridgeScript,

            injectionTime: .atDocumentStart,

            forMainFrameOnly: false

        )

        userContentController.addUserScript(userScript)

        

        // 注册桥接处理器

        userContentController.add(self, name: "bridge")

    }

    

    // MARK: - 注册自定义处理器

    func registerHandler(_ name: String, handler: MessageHandler) {

        queue.async { [weak self] in

            self?.messageHandlers[name] = handler

        }

        

        // 通知JavaScript新的处理器可用

        let jsCode = "JSBridge.publish('handler_added', {name: '\(name)'});"

        webView?.evaluateJavaScript(jsCode)

    }

    

    // MARK: - 发送响应到JavaScript

    func sendResponse(_ response: ResponseMessage) {

        let jsonData = try? JSONSerialization.data(withJSONObject: response, options: [])

        let jsonString = String(data: jsonData ?? Data(), encoding: .utf8) ?? "{}"

        

        let jsCode = """

        if (typeof JSBridge !== 'undefined' && JSBridge.handleNativeResponse) {

            JSBridge.handleNativeResponse(\(jsonString));

        }

        """

        

        webView?.evaluateJavaScript(jsCode) { _, error in

            if let error = error {

                print("Failed to send response: \(error)")

            }

        }

    }

    

    // MARK: - 发布事件

    func publishEvent(_ event: String, data: [String: Any]) {

        let payload: [String: Any] = [

            "event": event,

            "data": data,

            "timestamp": ISO8601DateFormatter().string(from: Date())

        ]

        

        let jsonData = try? JSONSerialization.data(withJSONObject: payload, options: [])

        let jsonString = String(data: jsonData ?? Data(), encoding: .utf8) ?? "{}"

        

        let jsCode = "if (typeof JSBridge !== 'undefined') { JSBridge.publish('\(event)', \(jsonString)); }"

        webView?.evaluateJavaScript(jsCode)

    }

}

  


// MARK: - WKScriptMessageHandler

extension AdvancedJavaScriptBridge: WKScriptMessageHandler {

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {

        guard let body = message.body as? [String: Any],

              let id = body["id"] as? String,

              let method = body["method"] as? String else {

            return

        }

        

        let params = body["params"] as? [String: Any] ?? [:]

        let request = RequestMessage(id: id, method: method, params: params)

        

        queue.async { [weak self] in

            self?.handleRequest(request)

        }

    }

    

    private func handleRequest(_ request: RequestMessage) {

        let handler = messageHandlers[request.method]

        

        if let handler = handler {

            handler.handleMessage(request) { [weak self] response in

                self?.sendResponse(response)

            }

        } else {

            let errorResponse = ResponseMessage(

                id: request.id,

                success: false,

                result: nil,

                error: "Method '\(request.method)' not found",

                timestamp: Date()

            )

            sendResponse(errorResponse)

        }

    }

}

2. 高级消息处理器实现

2.1 日志处理器


// MARK: - 日志处理器

class LogHandler: AdvancedJavaScriptBridge.MessageHandler {

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.params["level"] as? String {

        case "debug":

            print("🔍 [JS DEBUG] \(message.params["message"] ?? "Unknown")")

        case "info":

            print("ℹ️ [JS INFO] \(message.params["message"] ?? "Unknown")")

        case "warn":

            print("⚠️ [JS WARN] \(message.params["message"] ?? "Unknown")")

        case "error":

            print("❌ [JS ERROR] \(message.params["message"] ?? "Unknown")")

        default:

            print("📝 [JS LOG] \(message.params["message"] ?? "Unknown")")

        }

        

        let response = ResponseMessage(

            id: message.id,

            success: true,

            result: ["timestamp": ISO8601DateFormatter().string(from: Date())],

            error: nil,

            timestamp: Date()

        )

        completion(response)

    }

}

2.2 存储处理器


// MARK: - 存储处理器

class StorageHandler: AdvancedJavaScriptBridge.MessageHandler {

    private let defaults = UserDefaults.standard

    private let storageKey = "js_storage"

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "setItem":

            setItem(message)

        case "getItem":

            getItem(message, completion)

        case "removeItem":

            removeItem(message)

        case "clear":

            clear(message)

        default:

            let error = "Unknown storage method: \(message.method)"

            completion(createErrorResponse(message.id, error: error))

        }

    }

    

    private func setItem(_ message: RequestMessage) {

        guard let key = message.params["key"] as? String,

              let value = message.params["value"] else {

            completion(createErrorResponse(message.id, error: "Missing key or value"))

            return

        }

        

        var storage = getStorage()

        storage[key] = value

        saveStorage(storage)

        

        completion(createSuccessResponse(message.id, result: ["success": true]))

    }

    

    private func getItem(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let key = message.params["key"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing key"))

            return

        }

        

        let storage = getStorage()

        let value = storage[key]

        

        completion(createSuccessResponse(message.id, result: ["value": value ?? NSNull()]))

    }

    

    private func removeItem(_ message: RequestMessage) {

        guard let key = message.params["key"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing key"))

            return

        }

        

        var storage = getStorage()

        storage.removeValue(forKey: key)

        saveStorage(storage)

        

        completion(createSuccessResponse(message.id, result: ["success": true]))

    }

    

    private func clear(_ message: RequestMessage) {

        defaults.removeObject(forKey: storageKey)

        completion(createSuccessResponse(message.id, result: ["success": true]))

    }

    

    private func getStorage() -> [String: Any] {

        return defaults.dictionary(forKey: storageKey) ?? [:]

    }

    

    private func saveStorage(_ storage: [String: Any]) {

        defaults.set(storage, forKey: storageKey)

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

2.3 设备信息处理器


// MARK: - 设备信息处理器

class DeviceHandler: AdvancedJavaScriptBridge.MessageHandler {

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "getInfo":

            getDeviceInfo(message, completion)

        case "vibrate":

            vibrate(message, completion)

        case "getBattery":

            getBatteryInfo(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown device method"))

        }

    }

    

    private func getDeviceInfo(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let deviceInfo: [String: Any] = [

            "platform": "iOS",

            "version": UIDevice.current.systemVersion,

            "model": UIDevice.current.model,

            "name": UIDevice.current.name,

            "systemName": UIDevice.current.systemName,

            "isSimulator": TARGET_OS_SIMULATOR != 0,

            "language": Locale.current.languageCode ?? "en",

            "region": Locale.current.regionCode ?? "US",

            "screen": [

                "width": UIScreen.main.bounds.width,

                "height": UIScreen.main.bounds.height,

                "scale": UIScreen.main.scale

            ],

            "app": [

                "version": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0",

                "build": Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1",

                "name": Bundle.main.infoDictionary?["CFBundleName"] as? String ?? "App"

            ]

        ]

        

        completion(createSuccessResponse(message.id, result: deviceInfo))

    }

    

    private func vibrate(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let duration = message.params["duration"] as? TimeInterval ?? 0.1

        

        DispatchQueue.main.async {

            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)

            completion(self.createSuccessResponse(message.id, result: ["success": true]))

        }

    }

    

    private func getBatteryInfo(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        UIDevice.current.isBatteryMonitoringEnabled = true

        

        let batteryInfo: [String: Any] = [

            "level": UIDevice.current.batteryLevel * 100,

            "state": batteryStateToString(UIDevice.current.batteryState),

            "isCharging": UIDevice.current.batteryState != .unplugged

        ]

        

        completion(createSuccessResponse(message.id, result: batteryInfo))

    }

    

    private func batteryStateToString(_ state: UIDevice.BatteryState) -> String {

        switch state {

        case .unknown: return "unknown"

        case .unplugged: return "unplugged"

        case .charging: return "charging"

        case .full: return "full"

        @unknown default: return "unknown"

        }

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

2.4 网络处理器


// MARK: - 网络处理器

import Network

  


class NetworkHandler: AdvancedJavaScriptBridge.MessageHandler, ObservableObject {

    private var monitor: NWPathMonitor?

    private var isConnected = true

    @Published var connectionType: String = "unknown"

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "getStatus":

            getNetworkStatus(message, completion)

        case "upload":

            uploadFile(message, completion)

        case "download":

            downloadFile(message, completion)

        case "fetch":

            makeHTTPRequest(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown network method"))

        }

    }

    

    private func getNetworkStatus(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let status: [String: Any] = [

            "connected": isConnected,

            "type": connectionType,

            "effectiveType": effectiveType(),

            "downlink": downlinkSpeed()

        ]

        

        completion(createSuccessResponse(message.id, result: status))

    }

    

    private func makeHTTPRequest(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let urlString = message.params["url"] as? String,

              let url = URL(string: urlString) else {

            completion(createErrorResponse(message.id, error: "Invalid URL"))

            return

        }

        

        var request = URLRequest(url: url)

        request.httpMethod = message.params["method"] as? String ?? "GET"

        

        // 添加headers

        if let headers = message.params["headers"] as? [String: String] {

            for (key, value) in headers {

                request.setValue(value, forHTTPHeaderField: key)

            }

        }

        

        // 添加body

        if let body = message.params["body"] {

            request.httpBody = try? JSONSerialization.data(withJSONObject: body)

            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        }

        

        URLSession.shared.dataTask(with: request) { data, response, error in

            DispatchQueue.main.async {

                if let error = error {

                    completion(self.createErrorResponse(message.id, error: error.localizedDescription))

                    return

                }

                

                guard let httpResponse = response as? HTTPURLResponse else {

                    completion(self.createErrorResponse(message.id, error: "Invalid response"))

                    return

                }

                

                var result: [String: Any] = [

                    "status": httpResponse.statusCode,

                    "headers": httpResponse.allHeaderFields

                ]

                

                if let data = data, let json = try? JSONSerialization.jsonObject(with: data) {

                    result["body"] = json

                } else if let data = data, let text = String(data: data, encoding: .utf8) {

                    result["body"] = text

                }

                

                completion(self.createSuccessResponse(message.id, result: result))

            }

        }.resume()

    }

    

    private func uploadFile(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        // 文件上传实现

        guard let urlString = message.params["url"] as? String,

              let url = URL(string: urlString),

              let filePath = message.params["filePath"] as? String,

              let fileURL = URL(string: filePath) else {

            completion(createErrorResponse(message.id, error: "Invalid parameters"))

            return

        }

        

        var request = URLRequest(url: url)

        request.httpMethod = "POST"

        

        let task = URLSession.shared.uploadTask(with: request, fromFile: fileURL) { data, response, error in

            DispatchQueue.main.async {

                if let error = error {

                    completion(self.createErrorResponse(message.id, error: error.localizedDescription))

                } else {

                    let result: [String: Any] = [

                        "success": true,

                        "response": response?.description ?? ""

                    ]

                    completion(self.createSuccessResponse(message.id, result: result))

                }

            }

        }

        task.resume()

    }

    

    private func downloadFile(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        // 文件下载实现

        guard let urlString = message.params["url"] as? String,

              let url = URL(string: urlString) else {

            completion(createErrorResponse(message.id, error: "Invalid URL"))

            return

        }

        

        let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

        let destination = documentsPath.appendingPathComponent(url.lastPathComponent)

        

        let task = URLSession.shared.downloadTask(with: url) { tempURL, response, error in

            if let error = error {

                DispatchQueue.main.async {

                    completion(self.createErrorResponse(message.id, error: error.localizedDescription))

                }

            } else if let tempURL = tempURL {

                do {

                    try FileManager.default.moveItem(at: tempURL, to: destination)

                    let result: [String: Any] = [

                        "success": true,

                        "filePath": destination.path,

                        "fileSize": try FileManager.default.attributesOfItem(atPath: destination.path)["NSFileSize"] as? Int ?? 0

                    ]

                    DispatchQueue.main.async {

                        completion(self.createSuccessResponse(message.id, result: result))

                    }

                } catch {

                    DispatchQueue.main.async {

                        completion(self.createErrorResponse(message.id, error: error.localizedDescription))

                    }

                }

            }

        }

        task.resume()

    }

    

    private func effectiveType() -> String {

        // 简化的连接类型判断

        return connectionType == "wifi" ? "4g" : "2g"

    }

    

    private func downlinkSpeed() -> Double {

        // 简化的下载速度估算

        return connectionType == "wifi" ? 10.0 : 1.0 // MB/s

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

    

    // MARK: - 网络状态监控

    func startMonitoring() {

        monitor = NWPathMonitor()

        monitor?.pathUpdateHandler = { [weak self] path in

            self?.isConnected = path.status == .satisfied

            self?.connectionType = self?.pathToString(path) ?? "unknown"

            

            // 通知JavaScript网络状态变化

            let status: [String: Any] = [

                "connected": self?.isConnected ?? false,

                "type": self?.connectionType ?? "unknown"

            ]

            self?.bridge?.publishEvent("networkStatusChanged", data: status)

        }

        monitor?.start(queue: DispatchQueue.global(qos: .background))

    }

    

    private func pathToString(_ path: NWPath) -> String {

        if path.usesInterfaceType(.wifi) { return "wifi" }

        if path.usesInterfaceType(.cellular) { return "cellular" }

        if path.usesInterfaceType(.wired) { return "wired" }

        return "unknown"

    }

    

    weak var bridge: AdvancedJavaScriptBridge?

}

3. 相机和媒体处理器


// MARK: - 相机处理器

import AVFoundation

  


class CameraHandler: AdvancedJavaScriptBridge.MessageHandler, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    weak var viewController: UIViewController?

    private var picker: UIImagePickerController?

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "scanQR":

            scanQRCode(message, completion)

        case "takePhoto":

            takePhoto(message, completion)

        case "pickImage":

            pickImage(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown camera method"))

        }

    }

    

    private func scanQRCode(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard AVCaptureDevice.authorizationStatus(for: .video) == .authorized else {

            requestCameraPermission {

                self.scanQRCode(message, completion)

            }

            return

        }

        

        let picker = UIImagePickerController()

        picker.sourceType = .camera

        picker.delegate = self

        picker.cameraCaptureMode = .photo

        picker.modalPresentationStyle = .fullScreen

        

        // QR码检测

        if UIImagePickerController.isSourceTypeAvailable(.camera) {

            picker.sourceType = .camera

        } else {

            completion(createErrorResponse(message.id, error: "Camera not available"))

            return

        }

        

        self.picker = picker

        viewController?.present(picker!, animated: true)

        

        // 存储完成回调

        self.completionHandler = { result in

            completion(result)

        }

    }

    

    private func takePhoto(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let vc = viewController else {

            completion(createErrorResponse(message.id, error: "No view controller"))

            return

        }

        

        let picker = UIImagePickerController()

        picker.sourceType = .camera

        picker.delegate = self

        picker.allowsEditing = true

        

        self.picker = picker

        self.completionHandler = { result in

            completion(result)

        }

        

        vc.present(picker, animated: true)

    }

    

    private func pickImage(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        var config = PHPickerConfiguration()

        config.filter = .images

        config.selectionLimit = message.params["maxCount"] as? Int ?? 1

        

        let picker = PHPickerViewController(configuration: config)

        picker.delegate = self

        picker.modalPresentationStyle = .fullScreen

        

        self.picker = picker

        self.completionHandler = { result in

            completion(result)

        }

        

        viewController?.present(picker, animated: true)

    }

    

    // MARK: - UIImagePickerControllerDelegate

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {

        picker.dismiss(animated: true)

        

        if let image = info[.editedImage] as? UIImage {

            // 保存到临时文件

            let tempDir = FileManager.default.temporaryDirectory

            let fileName = UUID().uuidString + ".jpg"

            let fileURL = tempDir.appendingPathComponent(fileName)

            

            if let data = image.jpegData(compressionQuality: 0.8) {

                try? data.write(to: fileURL)

                

                let result: [String: Any] = [

                    "success": true,

                    "filePath": fileURL.path,

                    "fileSize": data.count,

                    "width": image.size.width,

                    "height": image.size.height,

                    "base64": data.base64EncodedString()

                ]

                

                completionHandler?(createSuccessResponse(messageId, result: result))

            }

        }

    }

    

    // MARK: - PHPickerViewControllerDelegate

    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

        picker.dismiss(animated: true)

        

        var images: [[String: Any]] = []

        

        let group = DispatchGroup()

        var tempFiles: [URL] = []

        

        for result in results {

            group.enter()

            

            result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] image, error in

                defer { group.leave() }

                

                guard let image = image as? UIImage, error == nil else {

                    return

                }

                

                let tempDir = FileManager.default.temporaryDirectory

                let fileName = UUID().uuidString + ".jpg"

                let fileURL = tempDir.appendingPathComponent(fileName)

                tempFiles.append(fileURL)

                

                if let data = image.jpegData(compressionQuality: 0.8) {

                    try? data.write(to: fileURL)

                    

                    let imageInfo: [String: Any] = [

                        "filePath": fileURL.path,

                        "fileSize": data.count,

                        "width": image.size.width,

                        "height": image.size.height,

                        "base64": data.base64EncodedString()

                    ]

                    images.append(imageInfo)

                }

            }

        }

        

        group.notify(queue: .main) {

            let result: [String: Any] = [

                "success": true,

                "images": images,

                "count": images.count

            ]

            self.completionHandler?(self.createSuccessResponse(self.messageId, result: result))

        }

    }

    

    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {

        picker.dismiss(animated: true)

        completionHandler?(createErrorResponse(messageId, error: "User cancelled"))

    }

    

    // MARK: - 权限处理

    private func requestCameraPermission(completion: @escaping () -> Void) {

        AVCaptureDevice.requestAccess(for: .video) { granted in

            DispatchQueue.main.async {

                if granted {

                    completion()

                } else {

                    self.completionHandler?(self.createErrorResponse(self.messageId, error: "Camera access denied"))

                }

            }

        }

    }

    

    // MARK: - 辅助属性和方法

    private var completionHandler: ((ResponseMessage) -> Void)?

    private var messageId: String = ""

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

4. 位置服务处理器


// MARK: - 位置处理器

import CoreLocation

  


class LocationHandler: AdvancedJavaScriptBridge.MessageHandler, CLLocationManagerDelegate {

    private let locationManager = CLLocationManager()

    private var currentLocation: CLLocation?

    private weak var bridge: AdvancedJavaScriptBridge?

    

    init(bridge: AdvancedJavaScriptBridge?) {

        self.bridge = bridge

        super.init()

        locationManager.delegate = self

        locationManager.desiredAccuracy = kCLLocationAccuracyBest

        locationManager.requestWhenInUseAuthorization()

    }

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "getCurrentPosition":

            getCurrentPosition(message, completion)

        case "watchPosition":

            watchPosition(message, completion)

        case "clearWatch":

            clearWatch(message, completion)

        case "geocode":

            geocodeAddress(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown location method"))

        }

    }

    

    private func getCurrentPosition(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let options = message.params["options"] as? [String: Any] ?? [:]

        let timeout = options["timeout"] as? TimeInterval ?? 10000

        let maximumAge = options["maximumAge"] as? TimeInterval ?? 0

        

        if let location = currentLocation, maximumAge == 0 || Date().timeIntervalSince(location.timestamp) < maximumAge {

            let result = locationToDictionary(location)

            completion(createSuccessResponse(message.id, result: result))

            return

        }

        

        if CLLocationManager.locationServicesEnabled() {

            locationManager.requestLocation()

            startTimeout(timeout: timeout) { timedOut in

                if timedOut {

                    completion(self.createErrorResponse(message.id, error: "Location request timed out"))

                }

            }

        } else {

            completion(createErrorResponse(message.id, error: "Location services disabled"))

        }

    }

    

    private func watchPosition(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let watchId = UUID().uuidString

        let options = message.params["options"] as? [String: Any] ?? [:]

        let enableHighAccuracy = options["enableHighAccuracy"] as? Bool ?? false

        

        if enableHighAccuracy {

            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

        } else {

            locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters

        }

        

        locationManager.startUpdatingLocation()

        

        // 存储watch ID

        // 在实际实现中应该保存到某个管理器中

        let result: [String: Any] = [

            "watchId": watchId,

            "success": true

        ]

        completion(createSuccessResponse(message.id, result: result))

    }

    

    private func clearWatch(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let watchId = message.params["watchId"] as? String ?? ""

        

        // 停止位置更新

        locationManager.stopUpdatingLocation()

        

        let result: [String: Any] = [

            "watchId": watchId,

            "success": true

        ]

        completion(createSuccessResponse(message.id, result: result))

    }

    

    private func geocodeAddress(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let address = message.params["address"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing address"))

            return

        }

        

        let geocoder = CLGeocoder()

        geocoder.geocodeAddressString(address) { placemarks, error in

            if let error = error {

                completion(self.createErrorResponse(message.id, error: error.localizedDescription))

            } else if let placemarks = placemarks, !placemarks.isEmpty {

                let results = placemarks.compactMap { placemark -> [String: Any]? in

                    guard let location = placemark.location else { return nil }

                    

                    var result: [String: Any] = [

                        "latitude": location.coordinate.latitude,

                        "longitude": location.coordinate.longitude,

                        "accuracy": location.horizontalAccuracy,

                        "altitude": location.altitude,

                        "timestamp": ISO8601DateFormatter().string(from: location.timestamp)

                    ]

                    

                    if let name = placemark.name {

                        result["name"] = name

                    }

                    if let thoroughfare = placemark.thoroughfare {

                        result["street"] = thoroughfare

                    }

                    if let locality = placemark.locality {

                        result["city"] = locality

                    }

                    if let administrativeArea = placemark.administrativeArea {

                        result["state"] = administrativeArea

                    }

                    if let postalCode = placemark.postalCode {

                        result["zip"] = postalCode

                    }

                    if let country = placemark.country {

                        result["country"] = country.name

                    }

                    

                    return result

                }

                

                completion(self.createSuccessResponse(message.id, result: ["results": results]))

            } else {

                completion(self.createErrorResponse(message.id, error: "No results found"))

            }

        }

    }

    

    // MARK: - CLLocationManagerDelegate

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        guard let location = locations.last else { return }

        currentLocation = location

        

        let result = locationToDictionary(location)

        

        // 通知所有监听者

        bridge?.publishEvent("locationUpdated", data: result)

        

        // 停止单次定位请求

        if manager.monitoredRegions.isEmpty {

            manager.stopUpdatingLocation()

        }

    }

    

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

        bridge?.publishEvent("locationError", data: [

            "error": error.localizedDescription,

            "code": "LOCATION_ERROR"

        ])

    }

    

    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {

        let status = manager.authorizationStatus

        let authStatus: [String: Any] = [

            "status": statusToString(status),

            "granted": status == .authorizedWhenInUse || status == .authorizedAlways

        ]

        

        bridge?.publishEvent("authorizationStatusChanged", data: authStatus)

    }

    

    // MARK: - 辅助方法

    private var timeoutTimer: Timer?

    private func startTimeout(timeout: TimeInterval, completion: @escaping (Bool) -> Void) {

        timeoutTimer?.invalidate()

        timeoutTimer = Timer.scheduledTimer(withTimeInterval: timeout / 1000.0, repeats: false) { _ in

            completion(true)

        }

    }

    

    private func locationToDictionary(_ location: CLLocation) -> [String: Any] {

        return [

            "latitude": location.coordinate.latitude,

            "longitude": location.coordinate.longitude,

            "accuracy": location.horizontalAccuracy,

            "altitude": location.altitude,

            "altitudeAccuracy": location.verticalAccuracy,

            "speed": location.speed,

            "heading": location.course,

            "timestamp": ISO8601DateFormatter().string(from: location.timestamp)

        ]

    }

    

    private func statusToString(_ status: CLAuthorizationStatus) -> String {

        switch status {

        case .notDetermined: return "notDetermined"

        case .restricted: return "restricted"

        case .denied: return "denied"

        case .authorizedAlways: return "authorizedAlways"

        case .authorizedWhenInUse: return "authorizedWhenInUse"

        @unknown default: return "unknown"

        }

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

5. 集成到WebViewController


// MARK: - 增强的WebViewController

class EnhancedWebViewController: UIViewController {

    

    // MARK: - Properties

    private let webView = WKWebView()

    private lazy var jsBridge = AdvancedJavaScriptBridge(webView: webView)

    private var networkHandler: NetworkHandler?

    private var cameraHandler: CameraHandler?

    private var locationHandler: LocationHandler?

    

    // MARK: - UI Components

    private lazy var activityIndicator: UIActivityIndicatorView = {

        let indicator = UIActivityIndicatorView(style: .large)

        indicator.translatesAutoresizingMaskIntoConstraints = false

        indicator.hidesWhenStopped = true

        return indicator

    }()

    

    // MARK: - Lifecycle

    override func viewDidLoad() {

        super.viewDidLoad()

        setupWebView()

        setupHandlers()

        loadInitialPage()

    }

    

    override func viewDidDisappear(_ animated: Bool) {

        super.viewDidDisappear(animated)

        cleanupHandlers()

    }

    

    // MARK: - Setup

    private func setupWebView() {

        view.backgroundColor = .systemBackground

        

        // 配置WebView

        let configuration = WKWebViewConfiguration()

        configuration.allowsInlineMediaPlayback = true

        configuration.mediaTypesRequiringUserActionForPlayback = []

        

        webView.configuration = configuration

        webView.navigationDelegate = self

        webView.uiDelegate = self

        webView.allowsBackForwardNavigationGestures = true

        

        view.addSubview(webView)

        webView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([

            webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),

            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),

            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),

            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)

        ])

        

        // 添加加载指示器

        view.addSubview(activityIndicator)

        NSLayoutConstraint.activate([

            activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor),

            activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor)

        ])

    }

    

    private func setupHandlers() {

        // 网络处理器

        networkHandler = NetworkHandler()

        networkHandler?.bridge = jsBridge

        networkHandler?.startMonitoring()

        

        // 相机处理器

        cameraHandler = CameraHandler()

        cameraHandler?.viewController = self

        jsBridge.registerHandler("camera", handler: cameraHandler!)

        

        // 位置处理器

        locationHandler = LocationHandler(bridge: jsBridge)

        jsBridge.registerHandler("location", handler: locationHandler!)

        

        // 自定义处理器

        jsBridge.registerHandler("analytics", handler: AnalyticsHandler())

        jsBridge.registerHandler("payment", handler: PaymentHandler())

    }

    

    private func cleanupHandlers() {

        networkHandler?.monitor?.cancel()

        locationHandler?.locationManager.stopUpdatingLocation()

    }

    

    private func loadInitialPage() {

        if let url = URL(string: "https://your-hybrid-app.com") {

            webView.load(URLRequest(url: url))

            activityIndicator.startAnimating()

        }

    }

    

    // MARK: - 工具方法

    func callJavaScript(_ function: String, parameters: [String: Any] = [:], completion: ((Any?) -> Void)? = nil) {

        var jsCode = function

        if !parameters.isEmpty {

            let jsonData = try? JSONSerialization.data(withJSONObject: parameters, options: [])

            let jsonString = String(data: jsonData ?? Data(), encoding: .utf8) ?? "{}"

            jsCode = "\(function)(\(jsonString));"

        }

        

        webView.evaluateJavaScript(jsCode) { result, error in

            if let error = error {

                print("JavaScript execution error: \(error)")

            }

            completion?(result)

        }

    }

}

  


// MARK: - WKNavigationDelegate

extension EnhancedWebViewController: WKNavigationDelegate {

    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {

        activityIndicator.startAnimating()

    }

    

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

        activityIndicator.stopAnimating()

        

        // 页面加载完成后初始化

        let initCode = """

        if (typeof JSBridge !== 'undefined') {

            JSBridge.ready(function() {

                // 通知页面应用已准备就绪

                JSBridge.callNative('appReady', {

                    platform: 'iOS',

                    version: '\(Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0")'

                });

                

                // 初始化应用

                if (typeof app !== 'undefined' && typeof app.init === 'function') {

                    app.init();

                }

            });

        }

        """

        webView.evaluateJavaScript(initCode)

    }

    

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {

        activityIndicator.stopAnimating()

        showError(error.localizedDescription)

    }

    

    private func showError(_ message: String) {

        let alert = UIAlertController(title: "加载失败", message: message, preferredStyle: .alert)

        alert.addAction(UIAlertAction(title: "重试", style: .default) { _ in

            webView.reload()

        })

        alert.addAction(UIAlertAction(title: "取消", style: .cancel))

        present(alert, animated: true)

    }

}

  


// MARK: - WKUIDelegate

extension EnhancedWebViewController: WKUIDelegate {

    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {

        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)

        alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in

            completionHandler()

        })

        present(alert, animated: true)

    }

    

    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {

        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)

        alert.addAction(UIAlertAction(title: "取消", style: .cancel) { _ in

            completionHandler(false)

        })

        alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in

            completionHandler(true)

        })

        present(alert, animated: true)

    }

    

    func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {

        let alert = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)

        alert.addTextField { textField in

            textField.text = defaultText

        }

        alert.addAction(UIAlertAction(title: "取消", style: .cancel) { _ in

            completionHandler(nil)

        })

        alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in

            completionHandler(alert.textFields?.first?.text)

        })

        present(alert, animated: true)

    }

}

6. 分析和支付处理器示例


// MARK: - 分析处理器

class AnalyticsHandler: AdvancedJavaScriptBridge.MessageHandler {

    private let analytics = AnalyticsManager.shared

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "trackEvent":

            trackEvent(message, completion)

        case "trackPageView":

            trackPageView(message, completion)

        case "setUserProperties":

            setUserProperties(message, completion)

        case "identifyUser":

            identifyUser(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown analytics method"))

        }

    }

    

    private func trackEvent(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let eventName = message.params["eventName"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing eventName"))

            return

        }

        

        let properties = message.params["properties"] as? [String: Any] ?? [:]

        analytics.track(event: eventName, properties: properties)

        

        completion(createSuccessResponse(message.id, result: ["eventId": UUID().uuidString]))

    }

    

    private func trackPageView(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let pageName = message.params["pageName"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing pageName"))

            return

        }

        

        let properties = message.params["properties"] as? [String: Any] ?? [:]

        analytics.trackPageView(pageName: pageName, properties: properties)

        

        completion(createSuccessResponse(message.id, result: ["success": true]))

    }

    

    private func setUserProperties(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let properties = message.params["properties"] as? [String: Any] ?? [:]

        analytics.setUserProperties(properties)

        

        completion(createSuccessResponse(message.id, result: ["success": true]))

    }

    

    private func identifyUser(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let userId = message.params["userId"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing userId"))

            return

        }

        

        let traits = message.params["traits"] as? [String: Any] ?? [:]

        analytics.identify(userId: userId, traits: traits)

        

        completion(createSuccessResponse(message.id, result: ["success": true]))

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

  


// MARK: - 支付处理器

class PaymentHandler: AdvancedJavaScriptBridge.MessageHandler {

    private let paymentService = PaymentService.shared

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "startPayment":

            startPayment(message, completion)

        case "checkPaymentStatus":

            checkPaymentStatus(message, completion)

        case "refund":

            processRefund(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown payment method"))

        }

    }

    

    private func startPayment(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let amount = message.params["amount"] as? Double,

              let currency = message.params["currency"] as? String,

              let orderId = message.params["orderId"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing required payment parameters"))

            return

        }

        

        let paymentParams: [String: Any] = [

            "amount": amount,

            "currency": currency,

            "orderId": orderId,

            "userId": message.params["userId"] as? String ?? "",

            "description": message.params["description"] as? String ?? ""

        ]

        

        paymentService.startPayment(with: paymentParams) { [weak self] result in

            DispatchQueue.main.async {

                switch result {

                case .success(let paymentResult):

                    let responseData: [String: Any] = [

                        "paymentId": paymentResult.paymentId,

                        "status": paymentResult.status,

                        "transactionId": paymentResult.transactionId

                    ]

                    self?.completion(createSuccessResponse(message.id, result: responseData))

                case .failure(let error):

                    self?.completion(createErrorResponse(message.id, error: error.localizedDescription))

                }

            }

        }

    }

    

    private func checkPaymentStatus(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let paymentId = message.params["paymentId"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing paymentId"))

            return

        }

        

        paymentService.checkStatus(for: paymentId) { result in

            DispatchQueue.main.async {

                switch result {

                case .success(let status):

                    let responseData: [String: Any] = [

                        "status": status,

                        "updatedAt": ISO8601DateFormatter().string(from: Date())

                    ]

                    completion(createSuccessResponse(message.id, result: responseData))

                case .failure(let error):

                    completion(createErrorResponse(message.id, error: error.localizedDescription))

                }

            }

        }

    }

    

    private func processRefund(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let paymentId = message.params["paymentId"] as? String,

              let amount = message.params["amount"] as? Double else {

            completion(createErrorResponse(message.id, error: "Missing refund parameters"))

            return

        }

        

        paymentService.processRefund(paymentId: paymentId, amount: amount) { result in

            DispatchQueue.main.async {

                switch result {

                case .success(let refundResult):

                    let responseData: [String: Any] = [

                        "refundId": refundResult.refundId,

                        "status": refundResult.status,

                        "amount": refundResult.amount

                    ]

                    completion(createSuccessResponse(message.id, result: responseData))

                case .failure(let error):

                    completion(createErrorResponse(message.id, error: error.localizedDescription))

                }

            }

        }

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

7. 使用示例和测试

7.1 HTML页面示例


<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Hybrid App Test</title>

    <style>

        body { font-family: -apple-system, sans-serif; padding: 20px; }

        button { padding: 10px 20px; margin: 5px; border: none; border-radius: 5px; background: #007AFF; color: white; }

        #log { background: #f5f5f5; padding: 10px; border-radius: 5px; height: 200px; overflow-y: scroll; margin-top: 20px; }

    </style>

</head>

<body>

    <h1>JavaScript桥接测试</h1>

    

    <button onclick="testDeviceInfo()">获取设备信息</button>

    <button onclick="testLocation()">获取位置</button>

    <button onclick="testCamera()">拍照</button>

    <button onclick="testNetwork()">网络请求</button>

    <button onclick="testStorage()">测试存储</button>

    <button onclick="testAnalytics()">分析事件</button>

    <button onclick="testPayment()">测试支付</button>

    

    <div id="log"></div>

  


    <script>

        // 等待桥接就绪

        JSBridge.ready(function() {

            log('JSBridge 已就绪');

            

            // 订阅事件

            JSBridge.subscribe('networkStatusChanged', function(data) {

                log('网络状态变化: ' + JSON.stringify(data));

            });

            

            JSBridge.subscribe('locationUpdated', function(data) {

                log('位置更新: ' + JSON.stringify(data));

            });

        });

  


        function log(message) {

            var logDiv = document.getElementById('log');

            var timestamp = new Date().toLocaleTimeString();

            logDiv.innerHTML += '[' + timestamp + '] ' + message + '<br>';

            logDiv.scrollTop = logDiv.scrollHeight;

            

            // 同时发送到原生日志

            JSBridge.callNative('log', { level: 'info', message: message });

        }

  


        function testDeviceInfo() {

            JSBridge.callNative('device.getInfo', {}, function(success, result, error) {

                if (success) {

                    log('设备信息: ' + JSON.stringify(result, null, 2));

                } else {

                    log('设备信息错误: ' + error);

                }

            });

        }

  


        function testLocation() {

            JSBridge.callNative('location.getCurrentPosition', {

                enableHighAccuracy: true,

                timeout: 10000,

                maximumAge: 0

            }, function(success, result, error) {

                if (success) {

                    log('当前位置: 纬度' + result.latitude + ', 经度' + result.longitude);

                } else {

                    log('位置错误: ' + error);

                }

            });

        }

  


        function testCamera() {

            JSBridge.callNative('camera.takePhoto', {}, function(success, result, error) {

                if (success) {

                    log('拍照成功: ' + result.filePath);

                    // 可以显示图片

                    if (result.base64) {

                        var img = document.createElement('img');

                        img.src = 'data:image/jpeg;base64,' + result.base64;

                        img.style.maxWidth = '100%';

                        document.body.appendChild(img);

                    }

                } else {

                    log('拍照错误: ' + error);

                }

            });

        }

  


        function testNetwork() {

            // 测试网络状态

            JSBridge.callNative('network.getStatus', {}, function(success, result) {

                log('网络状态: ' + JSON.stringify(result));

            });

  


            // 测试HTTP请求

            JSBridge.callNative('network.fetch', {

                url: 'https://jsonplaceholder.typicode.com/posts/1',

                method: 'GET'

            }, function(success, result, error) {

                if (success) {

                    log('网络请求成功: ' + JSON.stringify(result.body));

                } else {

                    log('网络请求错误: ' + error);

                }

            });

        }

  


        function testStorage() {

            // 测试存储

            JSBridge.callNative('storage.setItem', {

                key: 'testKey',

                value: 'Hello from JS!'

            }, function(success) {

                if (success) {

                    JSBridge.callNative('storage.getItem', {

                        key: 'testKey'

                    }, function(success, result) {

                        log('存储值: ' + result.value);

                    });

                }

            });

        }

  


        function testAnalytics() {

            JSBridge.callNative('analytics.trackEvent', {

                eventName: 'button_clicked',

                properties: {

                    button_id: 'test_button',

                    user_type: 'premium'

                }

            }, function(success, result) {

                log('分析事件发送: ' + JSON.stringify(result));

            });

  


            JSBridge.callNative('analytics.setUserProperties', {

                properties: {

                    user_age: 25,

                    user_city: 'Beijing'

                }

            });

        }

  


        function testPayment() {

            JSBridge.callNative('payment.startPayment', {

                amount: 9.99,

                currency: 'USD',

                orderId: 'order_' + Date.now(),

                description: 'Test Payment'

            }, function(success, result, error) {

                if (success) {

                    log('支付发起成功: ' + JSON.stringify(result));

                } else {

                    log('支付错误: ' + error);

                }

            });

        }

  


        // 批量测试

        function testBatch() {

            var calls = [

                { method: 'device.getInfo' },

                { method: 'network.getStatus' },

                { method: 'storage.getItem', params: { key: 'testKey' } }

            ];

  


            JSBridge.batchCall(calls, function(results) {

                log('批量调用结果: ' + JSON.stringify(results, null, 2));

            });

        }

    </script>

</body>

</html>

8. 性能优化和安全考虑

8.1 性能监控


// MARK: - 性能监控处理器

class PerformanceHandler: AdvancedJavaScriptBridge.MessageHandler {

    private var startTime: Date?

    private var metrics: [String: Any] = [:]

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        switch message.method {

        case "startMeasure":

            startMeasure(message, completion)

        case "endMeasure":

            endMeasure(message, completion)

        case "getMetrics":

            getMetrics(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown performance method"))

        }

    }

    

    private func startMeasure(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let measureName = message.params["name"] as? String ?? "default"

        startTime = Date()

        metrics[measureName] = ["startTime": Date().timeIntervalSince1970]

        

        completion(createSuccessResponse(message.id, result: ["measureId": measureName]))

    }

    

    private func endMeasure(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let measureName = message.params["name"] as? String ?? metrics.keys.first,

              let startInfo = metrics[measureName] as? [String: Double],

              let startTime = startInfo["startTime"] else {

            completion(createErrorResponse(message.id, error: "No active measure"))

            return

        }

        

        let endTime = Date().timeIntervalSince1970

        let duration = endTime - startTime

        

        metrics[measureName] = [

            "startTime": startTime,

            "endTime": endTime,

            "duration": duration

        ]

        

        let result: [String: Any] = [

            "measure": measureName,

            "duration": duration * 1000, // 毫秒

            "unit": "ms"

        ]

        

        completion(createSuccessResponse(message.id, result: result))

    }

    

    private func getMetrics(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let filteredMetrics: [[String: Any]] = metrics.compactMap { name, info in

            guard let metricInfo = info as? [String: Double] else { return nil }

            return [

                "name": name,

                "duration": (metricInfo["endTime"] ?? 0) - (metricInfo["startTime"] ?? 0),

                "startTime": metricInfo["startTime"] ?? 0,

                "endTime": metricInfo["endTime"] ?? 0

            ]

        }

        

        completion(createSuccessResponse(message.id, result: ["metrics": filteredMetrics]))

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

8.2 安全处理器


// MARK: - 安全处理器

class SecurityHandler: AdvancedJavaScriptBridge.MessageHandler {

    private let keychain = KeychainService()

    

    func handleMessage(_ message: RequestMessage, completion: @escaping (ResponseMessage) -> Void) {

        // 验证消息来源

        guard validateMessageOrigin(message) else {

            completion(createErrorResponse(message.id, error: "Invalid message origin"))

            return

        }

        

        // 验证方法权限

        guard hasPermission(for: message.method) else {

            completion(createErrorResponse(message.id, error: "Permission denied"))

            return

        }

        

        switch message.method {

        case "encrypt":

            encryptData(message, completion)

        case "decrypt":

            decryptData(message, completion)

        case "validateToken":

            validateToken(message, completion)

        case "biometricAuth":

            authenticateWithBiometrics(message, completion)

        default:

            completion(createErrorResponse(message.id, error: "Unknown security method"))

        }

    }

    

    private func validateMessageOrigin(_ message: RequestMessage) -> Bool {

        // 验证消息来源的安全性

        let allowedDomains = ["https://yourapp.com", "https://api.yourapp.com"]

        let origin = message.params["origin"] as? String ?? ""

        return allowedDomains.contains { origin.hasSuffix($0) }

    }

    

    private func hasPermission(for method: String) -> Bool {

        // 检查用户权限

        let permissions = UserDefaults.standard.array(forKey: "security_permissions") as? [String] ?? []

        return permissions.contains(method)

    }

    

    private func encryptData(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let data = message.params["data"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing data"))

            return

        }

        

        do {

            let encrypted = try keychain.encrypt(data: data)

            let result: [String: Any] = [

                "encryptedData": encrypted,

                "algorithm": "AES256"

            ]

            completion(createSuccessResponse(message.id, result: result))

        } catch {

            completion(createErrorResponse(message.id, error: error.localizedDescription))

        }

    }

    

    private func decryptData(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let encryptedData = message.params["encryptedData"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing encryptedData"))

            return

        }

        

        do {

            let decrypted = try keychain.decrypt(encryptedData: encryptedData)

            completion(createSuccessResponse(message.id, result: ["data": decrypted]))

        } catch {

            completion(createErrorResponse(message.id, error: error.localizedDescription))

        }

    }

    

    private func validateToken(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        guard let token = message.params["token"] as? String else {

            completion(createErrorResponse(message.id, error: "Missing token"))

            return

        }

        

        // JWT令牌验证

        let isValid = validateJWT(token: token)

        let expiresIn = calculateTokenExpiry(token)

        

        let result: [String: Any] = [

            "valid": isValid,

            "expiresIn": expiresIn,

            "needsRefresh": expiresIn < 300 // 5分钟

        ]

        

        completion(createSuccessResponse(message.id, result: result))

    }

    

    private func authenticateWithBiometrics(_ message: RequestMessage, _ completion: @escaping (ResponseMessage) -> Void) {

        let context = LAContext()

        var error: NSError?

        

        guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {

            let result: [String: Any] = [

                "success": false,

                "reason": error?.localizedDescription ?? "Biometrics not available"

            ]

            completion(createSuccessResponse(message.id, result: result))

            return

        }

        

        let reason = message.params["reason"] as? String ?? "Please authenticate to continue"

        context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { [weak self] success, authError in

            DispatchQueue.main.async {

                let result: [String: Any] = [

                    "success": success,

                    "error": authError?.localizedDescription

                ]

                self?.completion(createSuccessResponse(message.id, result: result))

            }

        }

    }

    

    private func validateJWT(token: String) -> Bool {

        // 简化的JWT验证

        let components = token.components(separatedBy: ".")

        guard components.count == 3 else { return false }

        

        // 在实际应用中应该验证签名

        do {

            let payloadData = Data(base64Encoded: components[1]

                .replacingOccurrences(of: "-", with: "+")

                .replacingOccurrences(of: "_", with: "/") + "==")

            let payload = try JSONSerialization.jsonObject(with: payloadData!) as? [String: Any]

            let exp = payload?["exp"] as? TimeInterval

            return exp.map { $0 > Date().timeIntervalSince1970 } ?? false

        } catch {

            return false

        }

    }

    

    private func calculateTokenExpiry(_ token: String) -> TimeInterval {

        let components = token.components(separatedBy: ".")

        guard components.count == 3,

              let payloadData = Data(base64Encoded: components[1]

                .replacingOccurrences(of: "-", with: "+")

                .replacingOccurrences(of: "_", with: "/") + "=="),

              let payload = try? JSONSerialization.jsonObject(with: payloadData) as? [String: Any],

              let exp = payload["exp"] as? TimeInterval else {

            return 0

        }

        

        return max(0, exp - Date().timeIntervalSince1970)

    }

    

    private func createSuccessResponse(_ id: String, result: Any) -> ResponseMessage {

        return ResponseMessage(id: id, success: true, result: result, error: nil, timestamp: Date())

    }

    

    private func createErrorResponse(_ id: String, error: String) -> ResponseMessage {

        return ResponseMessage(id: id, success: false, result: nil, error: error, timestamp: Date())

    }

}

总结

这个高级JavaScript桥接实现提供了:

🎯 核心特性

  • 双向通信: 完整的请求-响应模型

  • 类型安全: Codable协议支持

  • 异步处理: 完整的回调支持

  • 事件订阅: 发布/订阅模式

🔧 高级功能

  • 批量调用: 高效的批量操作

  • 性能监控: 内置性能测量

  • 安全验证: 消息来源和权限验证

  • 错误处理: 统一的错误处理机制

📱 原生功能集成

  • 设备信息: 完整的设备API

  • 网络服务: HTTP请求和文件传输

  • 媒体处理: 相机、相册访问

  • 位置服务: GPS定位和地理编码

  • 安全认证: 生物识别和数据加密

  • 分析跟踪: 事件和用户行为分析

  • 支付集成: 支付流程管理

🚀 使用建议

  1. 生产环境: 添加更多的错误处理和重试机制

  2. 安全性: 实现完整的消息签名验证

  3. 性能: 添加消息队列和限流机制

  4. 测试: 编写全面的单元测试和集成测试