记录:离线包实现桥接

写在前面

  1. 使用 WebViewJavascriptBridge 框架,将WebViewJavascriptBridge对象由原生端注入到WebView中。
  2. 前端检验 window.WebViewJavascriptBridge 是否存在
  3. 通过特定机制(事件监听/iframe) 等待桥接准备就绪
  4. 使用原生注入的 WebViewJavascriptBridge 对象提供的方法:
    • callHandler: 调用原生功能
    • registerHandler: 注册供原生调用的方法

jsBridge编写

新建一个jsBridge文件

js 复制代码
const u = navigator.userAgent
const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1

/* eslint-disable */
function setupWebViewJavascriptBridge(callback) {
  // 第一次调用这个方法的时候,为false
  if (window.WebViewJavascriptBridge) {
    return callback(WebViewJavascriptBridge)
  }
  if (isAndroid) {
    document.addEventListener('WebViewJavascriptBridgeReady', function () {
      callback(WebViewJavascriptBridge)
    }, false)
  } else {
    // 第一次调用的时候,也是false
    if (window.WVJBCallbacks) {
      return window.WVJBCallbacks.push(callback)
    }
    // 把callback对象赋值给对象。
    window.WVJBCallbacks = [callback]
    // 这段代码的意思就是执行加载WebViewJavascriptBridge_JS.js中代码的作用
    var WVJBIframe = document.createElement('iframe')
    WVJBIframe.style.display = 'none'
    WVJBIframe.src = 'https://__bridge_loaded__'
    document.documentElement.appendChild(WVJBIframe)
    setTimeout(function () {
      document.documentElement.removeChild(WVJBIframe)
    }, 0)
  }
}

/* Android 版本 WebViewJavascriptBridge 的设计要求:
通过调用 init() 方法,建立 JS 端与 Android 原生端的双向通信通道

iOS 版本的 WebViewJavascriptBridge 在桥接对象注入时自动完成初始化,
通过 iframe 机制触发加载后,桥接自动就绪 
*/
if (isAndroid) {
  setupWebViewJavascriptBridge(function (bridge) {
    bridge.init()
  })
}
export default {
  callhandler(name, data, callback) {
    setupWebViewJavascriptBridge(function (bridge) {
      bridge.callHandler(name, data, callback)
    })
  },
  registerhandler(name, callback) {
    setupWebViewJavascriptBridge(function (bridge) {
      bridge.registerHandler(name, function (data, responseCallback) {
        callback(data, responseCallback)
      })
    })
  }
}

Android

Android使用 addEventListener 的原因:

  • Android WebView 提供了标准的事件机制
  • 原生端可以在适当时候触发 JavaScript 事件
  • 通过 document.addEventListener 监听自定义事件是一种标准做法

Android原生端在初始化完成后主动触发 WebViewJavascriptBridgeReady 事件通知 JS 端

iOS

iOS 使用 iframe 的原因:

  • UIWebView(较老的 iOS WebView)没有像 Android 那样的直接事件触发机制
  • 但 WebView 会拦截特定 URL 请求,这是可以利用的特性

使用URL Scheme 拦截机制:

js 复制代码
var WVJBIframe = document.createElement('iframe') 
WVJBIframe.style.display = 'none' 
WVJBIframe.src = 'https://__bridge_loaded__' 
document.documentElement.appendChild(WVJBIframe)

创建一个隐藏的 iframe 并设置特殊 URL,iOS 原生端通过拦截这个 URL 请求来知道需要初始化桥接。

使用

index.js

js 复制代码
  import jsBridge from './jsBridge'
  
  /**
   * methods downloadImage  下载图片
   * params list {Array} base64列表parmas = {list: [base64]} base64不要前面的信息 img/png
   *        title {string}
   * */
    downloadImage  (params, responseCallback) {
        jsBridge.callhandler('downloadImage', params, (data) => {
          responseCallback(JSON.parse(data))
        })
    },
  
    /**
    * methods checkSmsCode 校验验证码
    * params businessCode  {string} (modifyDrawPasswordDynamic     銀行卡修改取款密碼
    * params strategyCode {string} (ebil_ebilling写死)
    * */
    checkSmsCode (params, responseCallback) {
        jsBridge.callhandler('checkSmsCode', params, (data) => {
          let obj = JSON.parse(data)
          if (obj.authStatus === 'pass') {
            responseCallback(JSON.parse(data))
          } else {
            Toast.info('驗證碼錯誤_SMS code Error')
          }
        })
   },
   
  /**
   * methods 校验账户的交易密码
   * params {} 无需传参
   * */
  getCheckPassword (responseCallback) {
    jsBridge.callhandler('getCheckPassword', {}, data => {
      if (data) {
        responseCallback(JSON.parse(data))
      }
    })
  },

前端页面:

js 复制代码
    getImg () {
      this.$bridge.downloadImage({ list: this.url }, () => {
        // console.log(res)
      })
    },
    nextPage () {
      this.$bridge.checkSmsCode({ businessCode: 'creditAutoAply', strategyCode: 'credit_aply_sms_code' }, res => {
        this.$bridge.getCheckPassword(data => {
          if (data.authStatus) {
            // 保存文件信息
            this.$remote(SAVE_FILE_INFO, params).then(res => {
              ....
            })
          }
        })
      })
    }

总结

  • Android: 利用标准事件机制,原生主动通知 Web
  • iOS: 利用 URL 拦截机制,Web 主动触发原生初始化
相关推荐
wenzhangli71 小时前
Ooder A2UI 核心架构深度解析:WEB 拦截层的设计与实现
前端·架构
前端百草阁1 小时前
【前端性能优化全链路指南】从开发编写到构建运行的多维度实践
前端·性能优化
女生也可以敲代码2 小时前
AI时代下的50道前端开发面试题:从基础到大模型应用
前端·面试
ZhengEnCi2 小时前
M5-markconv自定义CSS样式指南 📝
前端·css·python
IT_陈寒2 小时前
SpringBoot自动配置的坑差点让我加班到天亮
前端·人工智能·后端
xingpanvip2 小时前
星盘接口开发文档:星相日历接口指南
android·开发语言·前端·css·php·lua
@PHARAOH2 小时前
WHAT - GitLens supercharged 插件
前端
TT模板3 小时前
苹果cms整合西瓜播放器XGplayer插件支持跳过片头尾
前端·html5
Wect3 小时前
React 性能优化精讲
前端·react.js·性能优化
追风筝的人er4 小时前
SpringBoot+Vue3 企业考勤如何处理法定假期?节假日方案、调休补班与工作日判断链路拆解
前端·vue.js·后端