首页
归档
笔记
树洞
搜索
友言

文章详情

Interesting People Record Interesting.

/ JavaScript / 文章详情

前端视角下的JSBridge

Sonder
1天前
6982字
17分钟
浏览 (8)

面试的时候经常会问到手机端应用 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…
  2. postMessage是HTML5引入的一个API,它允许来自不同源的脚本在浏览器环境中进行异步通信。在原生APP嵌入H5页面的场景下,可以利用postMessage来实现两者间的双向通信。juejin.cn/post/729442…
  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/…

android: blog.csdn.net/a910247/art…

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

传统做法

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

image.png

路径: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>
image.png
image.png

利用第三方包

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

这里讲的是 android 的 jsbridge:

第一步.Android Studio 导包

image.png

第二步.在布局文件中添加
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>
image.png
image.png

源码

github.com/YY88Xu/MyAp…

本文转自 https://juejin.cn/post/7382892371225362472, 如有侵权,请联系删除。

下一篇 / 轻快标图(LiteMark):轻量图片标注工具

🎯 相关文章

💡 推荐文章

🕵️‍♂️ 评论 (0)