跳至主要內容

JSBridge

wangdongovo...大约 4 分钟工具JSBridge

JSBridge

简介

JavaScript Bridge(JSBridge)是一种连接原生代码和JavaScript代码的技术,它允许在Web视图(如WebView)和原生应用程序之间进行双向通信。通过JSBridge,可以在JavaScript和原生代码之间传递数据、调用方法,并处理回调。

作用

  1. 实现双向通信: 允许JavaScript代码调用原生代码的方法,同时也允许原生代码调用JavaScript代码的函数。
  2. 传递数据: 可以在JavaScript和原生代码之间传递各种类型的数据,如字符串、数字、对象等。
  3. 处理回调: 支持在调用完成后处理回调,使得在异步操作完成后能够获取到结果。

实现原理

通过 WebView 提供的接口实现 JavaScript 和原生代码之间的通信。在移动应用开发中,通常使用 WebView 来加载网页或者 web 应用,而 JSBridge 技术则可以让这些网页或者 web 应用调用设备的原生功能,同时也可以让原生代码调用网页中的 JavaScript 函数。

  1. 注册消息处理器(Message Handler): 在原生代码中注册一个消息处理器,用于接收 JavaScript 发送的消息。在 iOS 中,常用的是通过 WebView 的配置对象(例如 UIWebViewConfiguration 或 WKWebViewConfiguration)的 userContentController 属性,调用其 add(_:name:) 方法添加一个名为 "messageHandler"(或其他自定义的名称)的消息处理器。在 Android 中,可以通过 addJavascriptInterface() 方法将原生对象暴露给 JavaScript。

  2. JavaScript 调用原生代码: JavaScript 通过特定的接口调用原生代码,并将需要传递的数据作为参数传入。在 iOS 中,通常是通过 WebView 的 window.webkit.messageHandlers 对象调用原生代码,例如 window.webkit.messageHandlers.messageHandler.postMessage(data),其中 "messageHandler" 是原生代码注册的消息处理器名称,data 是需要传递的数据。在 Android 中,可以通过 JavaScript 中的 window. 对象调用原生暴露的接口。

  3. 原生代码接收消息并处理: 原生代码通过之前注册的消息处理器接收 JavaScript 发送的消息,在 iOS 中,需要实现 WKScriptMessageHandler 协议的 userContentController(:didReceive:) 方法,或者在旧版的 UIWebView 中,需要实现 UIWebViewDelegate 协议的 webView(:shouldStartLoadWith:request:navigationType:) 方法,在该方法中判断并处理 JavaScript 发送的消息。

  4. 原生代码调用 JavaScript 函数: 原生代码处理完逻辑后,有时需要将结果返回给 JavaScript 端。在 iOS 中,可以通过 WebView 的 evaluateJavaScript(_:completionHandler:) 方法执行 JavaScript 代码,将处理结果传递给 JavaScript 函数。

  5. JavaScript 接收并处理原生代码返回的结果: JavaScript 在收到原生代码的返回结果后,可以在回调函数中处理这些结果,完成整个通信流程。

前端使用React脚手架搭建网页

npx create-react-app my-app --template typescript

IOS端使用Swift 写代码加载网页

 // 创建 WKWebViewConfiguration 实例以配置 WKWebView
let webConfiguration = WKWebViewConfiguration()
// 添加消息处理程序以接收来自 Web 内容的消息
webConfiguration.userContentController.add(self, name: "saveImage")

// 创建 WKWebView 实例
webView = WKWebView(frame: self.view.frame, configuration: webConfiguration)
// 将 WebView 添加到视图中
self.view.addSubview(webView)

// 加载指定的 URL
if let url = URL(string: "http://192.168.220.81:3000") {
    let request = URLRequest(url: url)
    webView.load(request)
}

IOS端定义保存图片到相册的方法

// 接收来自 Web 内容的消息并进行处理
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        // 检查消息名称是否为 "saveImage",并尝试提取 Base64 编码的图像数据
        if message.name == "saveImage", let base64String = message.body as? String {
            // 打印接收到的来自 Web 的消息
            print("Received message from web: \(base64String)")
            // 将 Base64 编码的图像数据保存到相册
            saveBase64ImageToAlbum(base64String: base64String)
        }
    }
    
    // 将 Base64 编码的图像数据保存到相册
    func saveBase64ImageToAlbum(base64String: String) {
        // 将 Base64 字符串解码为图像数据
        if let imageData = Data(base64Encoded: base64String) {
            // 将图像数据转换为 UIImage
            if let image = UIImage(data: imageData) {
                // 将图像保存到相册
                UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
            }
        }
    }

开启访问相册的权限

前端调用IOS端的方法

  • 传递base64格式图片给IOS端(图片前缀删掉,这一步骤要么前端处理要么IOS端处理,建议前端出问题好排查)
import React, { useEffect, useState } from "react"
import { Button, Toast } from "antd-mobile"

const WebJsBridge = () => {
  const [image] = useState<string>(``)

  

  // 保存图片到相册的函数
  const handleSave = () => {
    window.webkit.messageHandlers.saveImage.postMessage(image)
  }

 

  return (
    <div>
      <h1>WebJsBridge</h1>
      <img
        style={{ width: "200px", height: "500px" }}
        src={`data:image/png;base64,${image}`}
        alt="图片"
      />
      <Button onClick={handleSave}>保存图片到相册</Button>
    </div>
  )
}

export default WebJsBridge
// image放base64格式的图片

图片转base64格式网站

图片转base64open in new window

前端触发保存图片的事件

IOS端图片保存的状态告知网页端

// 图像保存到相册后的回调方法
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
    var message: String
    // 检查是否有错误发生
    if let error = error {
        // 如果出现错误,将错误信息记录下来
        message = "保存失败,错误:\(error.localizedDescription)"
    } else {
        // 如果保存成功,设置成功信息
        message = "success"
    }
    // 构建 JavaScript 脚本,用于向网页发送消息,通知保存状态
    let jsScript = "window.BridgeInterface.handleSaveResult('\(message)');"
    // 执行 JavaScript 脚本,向网页发送消息
    webView.evaluateJavaScript(jsScript, completionHandler: nil)
}
// 处理保存结果的函数
const handleSaveResult = (resultMessage: any) => {
  console.log(`🍍🙏🍍👉: resultMessage`, resultMessage)
  Toast.show({
    icon: "success",
    content: "保存成功",
  })
}



useEffect(() => {
  window.BridgeInterface = {
    handleSaveResult,
  }
}, [])
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.5