【移动端知识】移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现

移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现

  • [移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现](#移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现)
    • 一、核心架构设计
    • [二、Android 平台实现](#二、Android 平台实现)
      • [1. 基础通信架构](#1. 基础通信架构)
      • [2. 控制器实现](#2. 控制器实现)
      • [3. WebView 安全配置](#3. WebView 安全配置)
    • [三、iOS 平台实现 (Swift)](#三、iOS 平台实现 (Swift))
      • [1. WKWebView 通信桥接](#1. WKWebView 通信桥接)
      • [2. AppDelegate 路由控制](#2. AppDelegate 路由控制)
    • 四、鸿蒙平台实现 (HarmonyOS)
      • [1. WebView 通信桥接](#1. WebView 通信桥接)
      • [2. Ability 控制器实现](#2. Ability 控制器实现)
      • [3. 鸿蒙 WebView 配置](#3. 鸿蒙 WebView 配置)
    • [五、通用 JavaScript 接口](#五、通用 JavaScript 接口)
      • [1. 跨平台通信 SDK](#1. 跨平台通信 SDK)
      • [2. HTML 页面集成](#2. HTML 页面集成)
    • 六、平台差异处理表
    • 七、高级功能实现
      • [1. 双向实时通信](#1. 双向实时通信)
      • [2. 文件传输支持](#2. 文件传输支持)
      • [3. 安全控制措施](#3. 安全控制措施)
    • 八、调试与监控
      • [1. 统一日志系统](#1. 统一日志系统)
      • [2. 性能监控](#2. 性能监控)
    • 九、最佳实践建议
    • 十、完整实现流程图

移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现

一、核心架构设计

平台层 JS调用 消息路由 调用目标 执行JS Android Native Bridge iOS 鸿蒙 WebView A 平台控制器 WebView B WebView B页面

二、Android 平台实现

1. 基础通信架构

java 复制代码
// WebViewBridge.java
public class WebViewBridge {
    private WeakReference<WebView> mWebViewRef;
    private String mBridgeName;
    
    public WebViewBridge(WebView webView, String bridgeName) {
        mWebViewRef = new WeakReference<>(webView);
        mBridgeName = bridgeName;
        webView.addJavascriptInterface(this, bridgeName);
    }
    
    @JavascriptInterface
    public void postMessage(String targetBridge, String message) {
        MainActivity activity = (MainActivity) mWebViewRef.get().getContext();
        activity.routeMessage(targetBridge, message);
    }
    
    public void receiveMessage(String message) {
        WebView webView = mWebViewRef.get();
        if (webView != null) {
            String js = String.format("window.%s.onMessage('%s')", 
                                     mBridgeName, message);
            webView.evaluateJavascript(js, null);
        }
    }
}

2. 控制器实现

java 复制代码
// MainActivity.java
public class MainActivity extends AppCompatActivity {
    private WebView webViewA, webViewB;
    private WebViewBridge bridgeA, bridgeB;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        webViewA = findViewById(R.id.webview_a);
        webViewB = findViewById(R.id.webview_b);
        
        // 初始化桥接
        bridgeA = new WebViewBridge(webViewA, "BridgeA");
        bridgeB = new WebViewBridge(webViewB, "BridgeB");
        
        // 加载HTML
        webViewA.loadUrl("file:///android_asset/webview_a.html");
        webViewB.loadUrl("file:///android_asset/webview_b.html");
    }
    
    // 消息路由方法
    public void routeMessage(String targetBridge, String message) {
        if ("BridgeA".equals(targetBridge)) {
            bridgeA.receiveMessage(message);
        } else if ("BridgeB".equals(targetBridge)) {
            bridgeB.receiveMessage(message);
        }
    }
}

3. WebView 安全配置

java 复制代码
// 启用JavaScript
webView.getSettings().setJavaScriptEnabled(true);

// 防止内存泄漏
webView.setWebViewClient(new WebViewClient());
webView.setWebChromeClient(new WebChromeClient());

// 文件访问权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    webView.getSettings().setAllowFileAccessFromFileURLs(true);
    webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
}

三、iOS 平台实现 (Swift)

1. WKWebView 通信桥接

swift 复制代码
// WebViewBridge.swift
class WebViewBridge: NSObject, WKScriptMessageHandler {
    private weak var webView: WKWebView?
    private let bridgeName: String
    
    init(webView: WKWebView, bridgeName: String) {
        self.webView = webView
        self.bridgeName = bridgeName
        super.init()
        webView.configuration.userContentController.add(self, name: bridgeName)
    }
    
    func userContentController(_ controller: WKUserContentController, 
                              didReceive message: WKScriptMessage) {
        guard let body = message.body as? [String: Any],
              let target = body["target"] as? String,
              let msg = body["message"] as? String else {
            return
        }
        
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.routeMessage(target: target, message: msg)
        }
    }
    
    func sendMessage(_ message: String) {
        let js = "window.\(bridgeName).onMessage('\(message)')"
        webView?.evaluateJavaScript(js, completionHandler: nil)
    }
}

2. AppDelegate 路由控制

swift 复制代码
// AppDelegate.swift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    var webViewA: WKWebView!
    var webViewB: WKWebView!
    var bridgeA: WebViewBridge!
    var bridgeB: WebViewBridge!
    
    func application(_ application: UIApplication, 
                   didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // 创建WebView
        webViewA = WKWebView(frame: .zero)
        webViewB = WKWebView(frame: .zero)
        
        // 初始化桥接
        bridgeA = WebViewBridge(webView: webViewA, bridgeName: "BridgeA")
        bridgeB = WebViewBridge(webView: webViewB, bridgeName: "BridgeB")
        
        // 加载HTML
        if let urlA = Bundle.main.url(forResource: "webview_a", withExtension: "html") {
            webViewA.loadFileURL(urlA, allowingReadAccessTo: urlA)
        }
        
        if let urlB = Bundle.main.url(forResource: "webview_b", withExtension: "html") {
            webViewB.loadFileURL(urlB, allowingReadAccessTo: urlB)
        }
        
        return true
    }
    
    // 消息路由
    func routeMessage(target: String, message: String) {
        if target == "BridgeA" {
            bridgeA.sendMessage(message)
        } else if target == "BridgeB" {
            bridgeB.sendMessage(message)
        }
    }
}

四、鸿蒙平台实现 (HarmonyOS)

1. WebView 通信桥接

java 复制代码
// HarmonyBridge.java
public class HarmonyBridge {
    private WebView webView;
    private String bridgeName;
    private Context context;
    
    public HarmonyBridge(Context context, WebView webView, String bridgeName) {
        this.context = context;
        this.webView = webView;
        this.bridgeName = bridgeName;
        this.webView.addJsInterface(this, bridgeName);
    }
    
    @JSFunction
    public void postMessage(String targetBridge, String message) {
        // 获取主Ability
        MainAbility mainAbility = (MainAbility) context;
        mainAbility.routeMessage(targetBridge, message);
    }
    
    public void receiveMessage(String message) {
        String js = "window." + bridgeName + ".onMessage('" + message + "')";
        webView.executeJs(js);
    }
}

2. Ability 控制器实现

java 复制代码
// MainAbility.java
public class MainAbility extends Ability {
    private WebView webViewA;
    private WebView webViewB;
    private HarmonyBridge bridgeA;
    private HarmonyBridge bridgeB;
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        DirectionalLayout layout = new DirectionalLayout(this);
        
        // 创建WebViewA
        webViewA = new WebView(this);
        webViewA.setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
        webViewA.setHeight(ComponentContainer.LayoutConfig.MATCH_CONTENT);
        webViewA.setWeight(1);
        webViewA.load("file:///assets/webview_a.html");
        
        // 创建WebViewB
        webViewB = new WebView(this);
        webViewB.setWidth(ComponentContainer.LayoutConfig.MATCH_PARENT);
        webViewB.setHeight(ComponentContainer.LayoutConfig.MATCH_CONTENT);
        webViewB.setWeight(1);
        webViewB.load("file:///assets/webview_b.html");
        
        // 初始化桥接
        bridgeA = new HarmonyBridge(this, webViewA, "BridgeA");
        bridgeB = new HarmonyBridge(this, webViewB, "BridgeB");
        
        // 添加到布局
        layout.addComponent(webViewA);
        layout.addComponent(webViewB);
        setUIContent(layout);
    }
    
    // 消息路由
    public void routeMessage(String targetBridge, String message) {
        if ("BridgeA".equals(targetBridge)) {
            bridgeA.receiveMessage(message);
        } else if ("BridgeB".equals(targetBridge)) {
            bridgeB.receiveMessage(message);
        }
    }
}

3. 鸿蒙 WebView 配置

java 复制代码
// 启用JavaScript
WebConfig webConfig = webView.getWebConfig();
webConfig.setJavaScriptPermit(true);

// 设置WebView代理
webView.setWebAgent(new WebAgent() {
    @Override
    public boolean onPageStart(WebView webView, String url) {
        // 页面开始加载处理
        return true;
    }
});

五、通用 JavaScript 接口

1. 跨平台通信 SDK

javascript 复制代码
// bridge-sdk.js
class CrossWebViewBridge {
    constructor(bridgeName) {
        this.bridgeName = bridgeName;
        this.messageHandlers = {};
    }
    
    postMessage(targetBridge, message) {
        // Android
        if (window.AndroidBridge) {
            window.AndroidBridge.postMessage(targetBridge, message);
        }
        // iOS
        else if (window.webkit && window.webkit.messageHandlers[this.bridgeName]) {
            window.webkit.messageHandlers[this.bridgeName].postMessage({
                target: targetBridge,
                message: message
            });
        }
        // HarmonyOS
        else if (window.HarmonyBridge) {
            window.HarmonyBridge.postMessage(targetBridge, message);
        }
    }
    
    onMessage(handler) {
        this.messageHandlers['default'] = handler;
    }
    
    // 供原生调用的方法
    __onNativeMessage(message) {
        if (this.messageHandlers['default']) {
            this.messageHandlersmessage;
        }
    }
}

// 初始化
window.BridgeA = new CrossWebViewBridge('BridgeA');
window.BridgeB = new CrossWebViewBridge('BridgeB');

2. HTML 页面集成

html 复制代码
<!-- webview_a.html -->
<!DOCTYPE html>
<html>
<head>
    <title>WebView A</title>
    <script src="bridge-sdk.js"></script>
</head>
<body>
    <button onclick="sendMessage()">发送消息到WebView B</button>
    
    <script>
        // 初始化桥接
        const bridgeA = new CrossWebViewBridge('BridgeA');
        
        // 注册消息处理器
        bridgeA.onMessage(function(message) {
            console.log('WebViewA收到消息:', message);
            document.getElementById('output').innerText = message;
        });
        
        // 发送消息
        function sendMessage() {
            bridgeA.postMessage('BridgeB', 'Hello from WebView A');
        }
    </script>
    
    <div id="output"></div>
</body>
</html>

六、平台差异处理表

功能 Android iOS 鸿蒙 解决方案
JS接口注入 addJavascriptInterface WKUserContentController addJsInterface 统一桥接SDK
JS执行方式 evaluateJavascript evaluateJavaScript executeJs 封装原生方法
文件访问 需权限配置 沙盒限制 资源目录访问 使用相对路径
内存管理 WeakReference weak var 自动回收 弱引用处理
后台通信 Service支持 后台限制 ServiceAbility 消息队列缓存

七、高级功能实现

1. 双向实时通信

javascript 复制代码
// 在WebView A中
bridgeA.onMessage(function(message) {
    console.log('实时消息:', message);
    // 立即回复
    bridgeA.postMessage('BridgeB', '收到消息');
});

// 在WebView B中
setInterval(() => {
    bridgeB.postMessage('BridgeA', `心跳 ${Date.now()}`);
}, 5000);

2. 文件传输支持

java 复制代码
// Android 文件传输
@JavascriptInterface
public void sendFile(String base64Data, String fileName) {
    byte[] data = Base64.decode(base64Data, Base64.DEFAULT);
    // 保存文件
    File file = new File(getFilesDir(), fileName);
    try (FileOutputStream fos = new FileOutputStream(file)) {
        fos.write(data);
    }
    
    // 通知目标WebView
    String message = "file://" + file.getAbsolutePath();
    routeMessage("BridgeB", message);
}

3. 安全控制措施

java 复制代码
// Android 源验证
private boolean isValidOrigin(String origin) {
    return Arrays.asList(
        "file:///android_asset/", 
        "https://trusted-domain.com"
    ).contains(origin);
}

// 在WebViewClient中
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    if (!isValidOrigin(request.getUrl().toString())) {
        return true; // 阻止加载
    }
    return false;
}

八、调试与监控

1. 统一日志系统

javascript 复制代码
class BridgeLogger {
    constructor(bridgeName) {
        this.bridgeName = bridgeName;
    }
    
    log(message, level = 'info') {
        // 发送日志到原生
        const payload = {
            type: 'log',
            level: level,
            message: message
        };
        this.bridge.postMessage('Logger', JSON.stringify(payload));
    }
}

// 集成到SDK
CrossWebViewBridge.prototype.log = function(message) {
    this.logger.log(message);
};

2. 性能监控

java 复制代码
// Android 性能监控
private void startPerformanceMonitoring() {
    new Timer().scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
            Debug.getMemoryInfo(memoryInfo);
            
            long totalMemory = memoryInfo.getTotalPss();
            int cpuUsage = getCpuUsage();
            
            String message = String.format(
                "{\"memory\":%d,\"cpu\":%d}", 
                totalMemory, cpuUsage
            );
            
            bridgeA.postMessage("Monitor", message);
        }
    }, 0, 5000); // 每5秒监控一次
}

九、最佳实践建议

  1. 消息协议标准化

    json 复制代码
    {
      "version": "1.0",
      "id": "uuid",
      "timestamp": 1685091200,
      "source": "BridgeA",
      "target": "BridgeB",
      "type": "text/json/file",
      "payload": {}
    }
  2. 错误处理机制

    javascript 复制代码
    try {
      bridgeA.postMessage("BridgeB", largeData);
    } catch (e) {
      if (e.message.includes("Message too long")) {
        // 分片发送
        sendInChunks(largeData);
      }
    }
  3. 心跳保活

    java 复制代码
    // Android心跳服务
    public class HeartbeatService extends Service {
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            new Thread(() -> {
                while (true) {
                    if (webViewA != null) {
                        webViewA.post(() -> 
                            webViewA.evaluateJavascript("BridgeA.ping()", null)
                        );
                    }
                    Thread.sleep(30000);
                }
            }).start();
            return START_STICKY;
        }
    }

十、完整实现流程图

WebView A Native Bridge Platform Router WebView B postMessage(target, data) 路由请求 调用目标bridge 执行onMessage (可选)回复消息 WebView A Native Bridge Platform Router WebView B

通过以上方案,可在Android、iOS和鸿蒙平台上实现高效稳定的WebView间通信。关键点在于:

  1. 使用标准化通信协议
  2. 统一JavaScript接口
  3. 平台特定桥接实现
  4. 完善的安全控制
  5. 性能优化措施

实际部署时建议:

  • 在小流量环境验证
  • 逐步完善错误处理
  • 添加详细日志监控
  • 定期进行安全审计
相关推荐
lpfasd12328 分钟前
鸿蒙OS与Rust整合开发流程
华为·rust·harmonyos
_祝你今天愉快1 小时前
Android FrameWork - 开机启动 SystemServer 进程
android
洞见前行2 小时前
Android第一代加固技术原理详解(附源码)
android·安全
CYRUS_STUDIO2 小时前
深入解析 dex2oat:vdex、cdex、dex 格式转换全流程实战
android·源码·逆向
HarmonyOS_SDK3 小时前
云闪付联合HarmonyOS SDK打造更便捷安全的支付体验
harmonyos
2501_916013743 小时前
iOS 文件管理与 uni-app 性能优化实战 多工具协作的完整指南
android·ios·性能优化·小程序·uni-app·iphone·webview
lichong9515 小时前
【混合开发】Android+WebView视频图片播放硬件加速详解
android·音视频
Jackson_Li6 小时前
文本转语音?我们来盘一盘(鸿蒙开发)
harmonyos
future_studio8 小时前
如何用 Kotlin 在 Android 手机开发一个应用程序获取国家或地区信息
android·智能手机·kotlin
future_studio9 小时前
如何用 Kotlin 在 Android 手机开发一个计算器
android