原生桥接方式:深入了解JavaScript Bridge(JsBridge)

随着移动应用的发展,原生应用与Web内容(如H5页面)之间的交互变得越来越频繁。这些交互需要一种高效、安全且灵活的通信方式,于是诞生了多种原生桥接(Native Bridging)方式。

在这篇文章中,我们将重点介绍其中一种最常用和灵活的原生桥接方式:JavaScript Bridge(JsBridge)。

一、什么是JsBridge?

JavaScript Bridge 是一种在原生应用和Web页面(通常通过WebView加载)之间建立通信的技术。它通过注入对象和方法(API)的方式,允许原生代码和JavaScript代码之间进行无缝的数据传输、方法调用和事件触发。

二、为什么选择JsBridge?

  • 灵活性:JsBridge 允许在原生代码和JavaScript之间定义自定义方法和参数,满足特定的业务需求。
  • 跨平台:JsBridge 可以适用于多种移动端平台,如Android、iOS等。
  • 无缝通信:实现原生代码和Web内容之间的无缝通信,为开发者提供了便捷的交互方式。

三、JsBridge的工作原理

JsBridge 的工作原理基于以下几个核心概念:

  1. 注册原生方法:在原生应用中注册一些方法或函数,这些方法将被暴露给WebView或H5页面调用。
  2. 调用JavaScript方法:原生应用通过特定的接口调用WebView或H5页面中的JavaScript方法,传递参数并获取返回值。
  3. 执行原生代码:WebView或H5页面可以通过JsBridge调用原生应用中的特定功能或执行特定的操作。

四、如何实现JsBridge?

以下为简单的配置例子:

1. 各端配置

iOS原生App端

在iOS原生App中,使用WKWebViewWKUserContentController来实现JsBridge。

import UIKit
import WebKit

class ViewController: UIViewController, WKScriptMessageHandler, WKUIDelegate {
    
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let config = WKWebViewConfiguration()
        let userContentController = WKUserContentController()
        
        userContentController.add(self, name: "JsBridge")
        
        config.userContentController = userContentController
        
        webView = WKWebView(frame: self.view.bounds, configuration: config)
        webView.uiDelegate = self
        
        self.view.addSubview(webView)
        
        if let url = Bundle.main.url(forResource: "index", withExtension: "html") {
            webView.loadFileURL(url, allowingReadAccessTo: url)
        }
    }
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "JsBridge" {
            if let body = message.body as? [String: Any],
               let method = body["method"] as? String,
               let data = body["data"] as? [String: Any] {
                
                handleMethod(method: method, data: data)
            }
        }
    }
    
    func handleMethod(method: String, data: [String: Any]) {
        switch method {
        case "getDataFromApp":
            let responseData: [String: Any] = ["key": "value"]
            sendResponseToH5(data: responseData)
        default:
            print("Method \(method) not found")
        }
    }
    
    func sendResponseToH5(data: [String: Any]) {
        let jsonData = try? JSONSerialization.data(withJSONObject: data, options: [])
        let jsonString = String(data: jsonData!, encoding: .utf8)!
        
        let javascript = "window.JsBridge.receiveDataFromApp(\(jsonString))"
        webView.evaluateJavaScript(javascript, completionHandler: nil)
    }
}

原生App(Android)端

首先,在Android的原生应用中,我们可以使用WebView来实现JsBridge。

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private WebView webView;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = findViewById(R.id.webView);
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);

        webView.addJavascriptInterface(new JsBridge(), "JsBridge");

        webView.loadUrl("file:///android_asset/index.html");
    }

    public class JsBridge {

        @JavascriptInterface
        public void getDataFromApp() {
            // 获取数据
            String responseData = "{\"key\": \"value\"}";
            sendResponseToH5(responseData);
        }

        public void sendResponseToH5(final String data) {
            runOnUiThread(() -> {
                webView.evaluateJavascript("javascript:window.JsBridge.receiveDataFromApp('" + data + "')", null);
            });
        }
    }
}


H5页面端

import React, { useEffect } from 'react';

const App = () => {
  
  // 定义一个供H5调用的函数
  const sendDataToApp = () => {
    const data = "Hello App!";
    
    // 调用原生App提供的方法
    if (window.JsBridge && typeof window.JsBridge.sendDataToApp === 'function') {
      window.JsBridge.sendDataToApp(data);
    } else {
      console.error('JsBridge not initialized or function not found');
    }
  };

  // 定义一个供原生App调用的函数
  const receiveDataFromApp = (data) => {
    console("Received data in H5: " + data);
  };

  useEffect(() => {
    // 检查JsBridge是否已经初始化
    if (!window.JsBridge) {
      // 注入JsBridge到window对象中
      window.JsBridge = {
        sendDataToApp,
        receiveDataFromApp
      };
    }

    // 清理函数,在组件卸载时移除JsBridge
    return () => {
      window.JsBridge = null;
    };
  }, []);

  return (
    <div>
      <h1>JsBridge Example</h1>
      <button onClick={sendDataToApp}>Send Data to App</button>
    </div>
  );
};

export default App;

注意: 以上只是一个简单的例子,具体还是要结合当前业务做相应调整。

2. 使用步骤

原生应用中

在原生应用中,通常需要通过以下步骤来实现JsBridge:

  1. 定义接口:定义一个接口或协议,用于原生代码和JavaScript之间的通信。
  2. 注册方法:在原生应用中注册需要暴露给JavaScript调用的方法。
  3. 调用JavaScript方法:使用特定的API或工具类,调用WebView或H5页面中的JavaScript方法,并传递参数。

Web页面中

在Web页面中,通常需要通过以下步骤来实现JsBridge:

  1. 注册方法:在JavaScript代码中注册需要暴露给原生应用调用的方法。
  2. 监听事件:监听来自原生应用的事件或消息,执行相应的处理逻辑。
  3. 调用原生方法:使用JsBridge提供的API或函数,调用原生应用中注册的方法,并传递参数。

五、JsBridge的优缺点

优点

  • 灵活性:允许定义自定义方法和参数,满足特定的业务需求。
  • 跨平台:适用于多种移动端平台,如Android、iOS等。
  • 无缝通信:实现原生代码和Web内容之间的无缝通信。

缺点

  • 复杂性:需要在原生端和Web端都编写相应的代码。
  • 安全性:需要注意安全问题,避免恶意代码注入。

六、其余相关通信方式

1. PostMessage API

PostMessage API 是一种 HTML5 标准,用于在不同窗口(包括不同源的窗口)之间进行跨域通信。

优点

  • 安全性:提供了一种安全的跨域窗口通信方式。
  • 灵活性:支持复杂的数据结构和消息传递。

缺点

  • 兼容性:需要检查浏览器和 WebView 的支持情况,可能存在兼容性问题。

2. 拦截URL Scheme

工作原理

  • 拦截请求:H5页面通过某种方式(如 iframe.src 或 window.location.href)发送一个特定的 URL Scheme 请求。
  • 原生处理:原生 App 拦截这个请求,并根据 URL Scheme 和附带的参数执行相应的操作。

示例

  • H5 页面发送一个 URL Scheme 请求:myapp://doSomething?param=value
  • 原生 App 拦截该请求,执行 doSomething 操作,并使用 param=value 作为参数。

优缺点

  • 优点:灵活性高,支持复杂的交互。
  • 缺点:URL 长度有限(有数据丢失风险),存在安全风险,WKWebView 在 iOS 上不支持 Ajax 发送同域请求。

3. Native Modules(原生模块)

在一些跨平台框架(如 React Native、Flutter 等)中,通常提供了原生模块的机制,允许 JavaScript 代码直接调用原生代码。

优点

  • 性能优化:直接调用原生代码,性能通常比其他方式更好。
  • 功能强大:可以访问原生 API,实现复杂的功能。

缺点

  • 平台限制:需要为每个平台(如 Android、iOS)编写特定的原生模块。
  • 集成复杂:集成到 H5 可能比较复杂,需要使用特定的框架或库。

注意JsBridge通常是一个更高级、更全面的解决方案,它提供了一套API(可根据业务封装对应的bridge,满足现有业务)供H5页面调用。URL SchemePostMessage API等是JsBridge的底层实现方式之一。JsBridge不仅限于上述的通信方式,它可能还会提供其他功能,如调用原生的功能、获取设备信息、分享功能等。

七、原生桥接的优点和缺点

优点

  • 功能强大:可以访问原生 API,实现复杂的功能。
  • 性能优化:直接调用原生代码,性能通常比其他方式更好。
  • 灵活性:允许自定义方法和参数,满足特定的业务需求。

缺点

  • 复杂性:需要在原生端和 Web 端都编写相应的代码。
  • 安全性:需要谨慎处理安全问题,避免恶意代码注入。
  • 兼容性:不同的平台和版本可能存在兼容性问题,需要进行充分测试。

八、总结

不同的H5与移动端信息交互方式各有优缺点,选择合适的方式取决于我们的具体需求和项目情况。在实际开发中,可能需要结合多种方式,以满足不同的交互需求和性能要求。

  • 如果我们需要实现复杂的交互逻辑和功能,JavaScript Bridge(JsBridge)Native Modules 可能是更好的选择。
  • 对于简单的页面跳转和参数传递,WebView URL SchemePostMessage API 可能更为合适。
  • 在考虑安全性和兼容性时,需要仔细评估每种方式的优缺点,并采取相应的安全措施和兼容性处理。

此次分享,完结❤️❤️❤️❤️。如有不足,欢迎评论区指出🫶🏻🤝,看到会及时更正~~

原文链接:https://juejin.cn/post/7359209218899886120 作者:别催我码的慢

(0)
上一篇 2024年4月19日 下午4:23
下一篇 2024年4月22日 上午9:30

相关推荐

发表回复

登录后才能评论