前端视角下的JSBridge

文摘   2024-10-14 23:05   北京  

关注公众号 前端界,回复“加群

加入我们一起学习,天天进步

面试的时候经常会问到手机端应用 App 怎么跟 h5 通信的问题,什么是 JSBridge?说实话,之前没有认真研究过,最近入职了新公司正好是 App 和 h5 混合开发模式,周末有时间,研究了一番。

App 和 H5 通信

App 和 H5 通信和 JSBridge 其实是两个概念,不要混淆。App 和 H5 通信有多种,而 JSBridge 只是其中能实现 App 和 H5 通信的一种方式。

常见的 App 和 H5 通信方式:

  1. URL Scheme
    URL Scheme 是一种自定义的URL协议,允许 H5 页面通过链接到特定的格式触发 APP 内部的操作。例如,当H5页面中的链接被点击时,可以利用URL Scheme 唤起 APP 并执行预定义的动作,或者传递参数给 APP。这种方式适用于简单的跳转和数据传递,但功能有限,且用户体验可能因需要先打开系统浏览器再跳转至 APP 而受到影响。developer.baidu.com/article/det…[1]
  2. postMessage是HTML5引入的一个API,它允许来自不同源的脚本在浏览器环境中进行异步通信。在原生APP嵌入H5页面的场景下,可以利用postMessage来实现两者间的双向通信。juejin.cn/post/729442…[2]
  3. APP与H5之间可以通过WebSocket进行通信。WebSocket是一种在单个TCP连接上进行全双工通信的协议,它提供了浏览器和服务器之间的低延迟、持久化的连接,非常适合实时数据传输场景。
  4. JSBridge:JSBridge 的核心目的就是搭建一个桥梁,让运行在 WebView 中的 JavaScript 代码能够与宿主的原生应用程序(比如 Android 或 iOS 应用)互相通讯。

本文的重点在于介绍第4种 App 和 H5 的通信方式即 JSBridge。为了彻底搞懂大家说的 JSBridge 是什么,我在网上翻阅了很多博客,然后自己摸摸索索,把实现 JSBridge 的代码写了一遍,这样直接看代码解释起来会更清晰。

Android 开发环境配置

以 Android 为例,来看下 JSBridge 的实现,先配置 Android 的开发环境:

Java环境配置: blog.csdn.net/u014454538/…[3]

android: blog.csdn.net/a910247/art…[4]

配置腾讯云 gradle 镜像,解决下载Gradle文件慢问题:www.cnblogs.com/tc310/p/180…[5]

传统做法

传统做法利用的是 Android 系统提供的android.webkit.WebView 初始化一个 WebView,通过 addJavascriptInterface 方法绑定方法到JavaScript环境,实现JavaScript与Android原生代码的交互,这是实现 JSBridge 机制的基础。


路径:MyApplication2\app\src\main\AndroidManifest.xml

<!-- 添加网络权限 --> 
<uses-permission android:name="android.permission.INTERNET" />

android 端关键代码:通过 addJavascriptInterface 方法在 window 上添加 JsBridge 对象,并将 sendDataToApp 方法绑定到 JsBridge 对象上,这样 h5 就可以通过 windowJsBridge 对象的 sendDataToApp 跟 App 发送数据了。

public class MainActivity extends AppCompatActivity {
    private WebView webView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webview_layout);
        webView = findViewById(R.id.webview);
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        // window 上添加 JsBridge 对象
        webView.addJavascriptInterface(new JsBridge(), "JsBridge");
        webView.loadUrl("http://10.168.2.149:5500/h5-test.html");
    }
    
    public class JsBridge {
        // 添加 sendDataToApp 到 window.JsBridge 上
        @JavascriptInterface
        public void sendDataToApp(String value) {
            // 获取数据
            sendResponseToH5(value);
        }
        // 执行 JS 的方法
        public void sendResponseToH5(final String data) {
            runOnUiThread(() -> {
                webView.evaluateJavascript("javascript:window.JsBridge.receiveDataFromApp('" + data + "')"null);
            });
        }
    }
}

html5 的代码:页面点击按钮,触发 h5 的 sendDataToApp 方法,接着触发 window.JsBridge.sendDataToApp 方法向 App 发送数据,同时,h5 代码增加了 window.JsBridge.receiveDataFromApp,那么在 App 中就可以触发window.JsBridge.receiveDataFromApp 方法,从而实现 App 和 h5 的双向通信。

  <button onClick="sendDataToApp()">Send Data to App</button>
  <div id="log"></div>
  <div>我是app触发的:</div>
  <div id="app"></div>
  <script>
    function sendDataToApp(){
      if (window.JsBridge && typeof window.JsBridge.sendDataToApp === 'function') {
        window.JsBridge.sendDataToApp('Hello from Web');
        document.getElementById('log').innerHTML = 'Data sent to App';
      } else {
        document.getElementById('log').innerHTML = 'sent data failed';
      }
    }

    window.JsBridge.receiveDataFromApp = function(data{
      document.getElementById('app').innerHTML = 'Received data from App: ' + data;
    }
  
</script>

利用第三方包

除了上面介绍的传统的方式,还可以借助更安全可靠的第三方包来实现:
android jsbridge: github.com/uknownothin…[6]
ios jsbridge: github.com/marcuswesti…[7]

这里讲的是 android 的 jsbridge:

第一步.Android Studio 导包


第二步.在布局文件中添加
MyApplication2\app\src\main\res\layout\webview_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.github.lzyzsd.jsbridge.BridgeWebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

第三步.android 端代码

private BridgeWebView webView;

private static final String TAG="JSBridge";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.webview_layout);
    webView = findViewById(R.id.webview);
    WebSettings webSettings = webView.getSettings();
    webSettings.setJavaScriptEnabled(true);
    webView.loadUrl("http://10.168.2.149:5500/jsbridge.html");

    webView.registerHandler("submitFromWeb"new BridgeHandler() {
        @Override
        public void handler(String data, CallBackFunction function) {
            Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
            function.onCallBack("submitFromWeb exe, response data from Java");
        }
    });
}

第四步.h5 端代码

  <button onclick="handleClick()">调用 Android 方法</button>
  <div id="show"></div>
  <script>
    function handleClick(){
      if (window.WebViewJavascriptBridge) {
        WebViewJavascriptBridge.callHandler(
          'submitFromWeb'
          , {'param''参数测试'}
          , function(responseData{
              document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
          }
        );
      } else {
        document.getElementById("show").innerHTML = "WebViewJavascriptBridge is not loaded"
      }
    }

    function connectWebViewJavascriptBridge(callback{
    if (window.WebViewJavascriptBridge) {
      callback(WebViewJavascriptBridge)
    } else {
      document.addEventListener(
        'WebViewJavascriptBridgeReady'
        , function ({
          callback(WebViewJavascriptBridge)
        },
        false
      );
    }
  }

  connectWebViewJavascriptBridge(function (bridge{
    //===1===在JS中注册默认的Handler,以方便Java调用,java通过send方法发送数据
    bridge.init(function (message, responseCallback{
      console.log('JS got a message', message);
      var data = {
        'json''JS返回任意数据!'
      };
      console.log('JS responding with', data);/*打印信息*/
      document.getElementById("init").innerHTML = "data = " + message;
      responseCallback(data);
    });
    //===2===注册functionJs方法供java调用
    bridge.registerHandler("functionJs"function (data, responseCallback{
      document.getElementById("show").innerHTML = ("Android端: = " + data);
      var responseData = "Javascript 数据";
      responseCallback(responseData);
    });
  })
  
</script>



源码

github.com/YY88Xu/MyAp…[8]

本文转载于稀土掘金技术社区,作者:许多金

原文链接:https://juejin.cn/post/7382892371225362472

最后


大家好,我是芝士,最近创建了一个低代码/前端工程化/高级前端面试交流群,欢迎加我微信,拉你进群,互相监督学习进步等!




关注福利,关注公众号后,在首页:

  • 回复「简历获取精选的简历模板

  • 回复「思维图」获取完整 JavaScript 相关思维图

  • 回复「电子书」可下载我整理的大量前端资源,包含面试、Vue实战项目、CSS和JavaScript电子书等。

  • 回复「Node」获取简历制作建议

最后不要忘了点个赞再走噢


前端界
高质量文章分享、实践干货、技术前沿、学习资料, 你感兴趣的都在前端界
 最新文章