js Bridge实现原理

501 阅读2分钟

要描述什么是js Bridge,我们得先知道js Bridge是在什么地方去应用 什么是js Bridge呢

  • js,或者H5中无法直接调用native API, native API是什么意思呢?就是手机里面的app
  • 需要通过一些'特殊'的格式来调用
  • 这些格式就统称为js Bridge, 例如微信JSSDK,微信JSSDK应该是我们用的最多的了

image.png

image.png

js Bridge常见实现方式

  • 注册全局API
    • 通过向window注册一些属性,如window.getVersion = xxx,这种方式比较适合比较简单的同步的方式,异步的方式比较适合 URL Scheme方式
  • URL Scheme:自己造一个协议标准,让app去做一层拦截,不要发送网络请求
    • 适合所有的情况
    • 大家可以搜索 微信 scheme就可以找到很多资料,类似weixin://dl/feedback的格式,如chrome://version 正常情况下,app里面的webview要请求接口,需要通过app再到网络去请求接口(http/https),数据返回回来后也要先经过app再到webview页面;那么URL Scheme,约定好前缀URL,比如my-app-name://api/getname,当app识别到my-app-diary,app就自己去处理并设置信息返回了,不需要通过接口了

封装js-bridge

  const sdk = {
    invoke(url, data = {}, onSuccess, onError){
        const iframe = document.createElement('iframe')
        iframe.style.visibility = 'hidden';
        document.body.appendChild(iframe)
        iframe.onload = () => {
          const content = iframe.contentWindow.document.body.innerHTML;
          onSuccess(JSON.parse(content))
          iframe.remove()
        }
        iframe.onerror = () => {
           onError()
           iframe.remove()
        }
        iframe.src = `my-app-diary://${url}?data={JSON.stringify(data)}`
    },
    scan(data, onSuccess,onError){ // 扫一扫的功能
      this.invoe('api/scan', data,onSuccess, onError )
    }
  }
  // 使用
  sdk.scan(data,onSuccess, onError )

在实际项目中,我们h5调用app的方法,项目用的是通过注入API的方式,如:

  'use strict'
  
  (function(){
   function AppHelper() {}
    function isMyApp() { // 判断是否自己的app标识
        return navigator.userAgent.includes("myAppxxx");
      }

    AppHelper.prototype.setupWebViewJavascriptBridge = function (e) {
        if (isMyApp()) {
          if (window.WebViewJavascriptBridge) return e(WebViewJavascriptBridge);
          if (window.WVJBCallbacks) return window.WVJBCallbacks.push(e);
          window.WVJBCallbacks = [e];
          var i = document.createElement("iframe");
          i.style.display = "none";
          i.src = "https://__bridge_loaded__";
          document.documentElement.appendChild(i);
          setTimeout(function () {
            document.documentElement.removeChild(i);
          }, 0);
        }
      };
      
      //  app暴露给h5端的方法:获取登录token
      AppHelper.prototype.nativeToken = function () {
        var res =
          arguments.length > 0 && arguments[0] !== undefined
            ? arguments[0]
            : function (res) {};
        this.setupWebViewJavascriptBridge(function (bridge) {
          bridge.callHandler("nativeToken", {}, res);
        });
      };
      
      // app暴露给h5端的方法:app登录状态改变方法
      AppHelper.prototype.loginStateChange = function (resFunc) {
        this.setupWebViewJavascriptBridge(function (bridge) {
        // loginStateChange需要跟app端的同学约定好
          bridge.registerHandler("loginStateChange", function (
            data,
            responseCallback
          ) {
            resFunc && resFunc(data);
          });
        });
      };
      window.AppHelper = new AppHelper()
      
    }()
     
     
     
      ///=================h5端使用:====================
     AppHelper.nativeToken((res)=> {
        if(!!res){ // 可以拿到token, 说明登录成功
         // do something...
        }
     })