iOS Native与JS通信:JSBridge

文章目录

  • 一、简介
  • 二、JS 调用 Native
    • 1.使用 URL Scheme
      • a.UIWebView
      • b.WKWebView
    • 2.使用 JavaScriptCore (iOS 7+)
    • 3.使用 WKWebView 和 WKScriptMessageHandler (iOS 8+)
  • 三、Native 调用 JS
    • 1.使用 UIWebView
    • 2.使用 WKWebView
    • 3.使用 JavaScriptCore (iOS 7+)


一、简介

对于移动应用程序的开发,有多种技术选型,最基础的是原生开发,后面由于动态化和跨平台的需求,引入了跨端的方案,比如H5、RN。以原生+H5 混合开发模式为例,H5页面经常需要使用到Native端的功能,比如打开二维码扫描、调用本地相册、获取用户信息等,同时Native端也需要向H5页面发送消息、更新状态等。所以需要一种通信机制,来让两端进行通信。这时候就引入了桥(Bridge)的概念。

JSBridge(JavaScript Bridge)是一种设计模式,用于在JavaScript和原生代码(如iOS的Objective-C/Swift或Android的Java/Kotlin)之间建立通信桥梁。通过JSBridge,Web页面中的JavaScript代码可以调用原生功能,原生代码也可以调用JavaScript方法,从而实现Web和原生代码的互操作性。

JSBridge的核心思想是通过特定的通信协议在JavaScript和原生代码之间传递消息和数据(🔗iOS与JS交互)。其工作原理通常包括以下步骤:

  1. JavaScript调用原生代码:
  • JavaScript通过调用特定的接口或注入的对象,发送消息给原生代码。
  • 原生代码接收到消息后,执行相应的操作,并将结果返回给JavaScript。
  1. 原生代码调用JavaScript:
  • 原生代码通过特定的接口或注入的对象,发送消息给JavaScript。
  • JavaScript接收到消息后,执行相应的操作,并将结果返回给原生代码。

二、JS 调用 Native

1.使用 URL Scheme

这种方法通过在 JavaScript 端构建一个特定的 URL,然后在原生端捕获这个 URL 并解析出需要调用的方法和参数。

a.UIWebView

使用 UIWebView 的代理方法 webView:shouldStartLoadWithRequest:navigationType: 来拦截即将加载的请求,并根据请求的URL参数执行相应的逻辑,包括注入JavaScript代码、显示提示信息、处理登录结果等。

JS端:

function callNativeMethod(method, params) {var url = "myapp://" + method + "?" + encodeURIComponent(JSON.stringify(params));window.location.href = url;
}

Native端:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {NSURL *url = [request URL];if ([[url scheme] isEqualToString:@"myapp"]) {NSString *method = [url host];NSString *query = [url query];NSData *data = [query dataUsingEncoding:NSUTF8StringEncoding];NSDictionary *params = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];if ([method isEqualToString:@"someNativeMethod"]) {[self someNativeMethod:params];}return NO;}return YES;

这里举一个例子:

stringByEvaluatingJavaScriptFromString: 方法返回执行JS脚本的结果,通过这种方式,我们可以在UIWebView中拦截即将加载的请求,注入JavaScript代码,并根据URL参数执行相应的逻辑。这种方法可以用于处理各种需要与Web内容交互的场景,如动态调整页面布局、显示提示信息、处理登录结果等。(UIWebView在iOS 12之后已经被废弃)
在这里插入图片描述

b.WKWebView

WKWebView 有两个代理,一个是 WKNavigationDelegate,另一个是 WKUIDelegate。这里是使用WKWebView的代理方法 webView:decidePolicyForNavigationAction:decisionHandler:

JS端:

function callNative() {loadURL("your_func_name://xxx");
}  

Native端:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {NSURL *url = navigationAction.request.URL;// 与约定好的函数名作比较if ([[url scheme] isEqualToString:@"your_func_name"]) {// just do itdecisionHandler(WKNavigationActionPolicyCancel);return;}decisionHandler(WKNavigationActionPolicyAllow);
}//decisionHandler 是当你的应用程序决定是允许还是取消导航时,要调用的代码块。 
//该代码块使用单个参数,它必须是枚举类型 WKNavigationActionPolicy 的常量之一。如果不调用 decisionHandler 会引起 crash。

这里简单介绍一下 WKUIDelegate 中的代理方法 webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:

webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler: 是 WKUIDelegate 协议中的一个方法。当网页中通过 JavaScript 调用 alert 方法时,WebKit 会调用这个委托方法。你可以在此方法中自定义显示一个警告框并在用户点击确定按钮后执行相应的操作。也就是说,可以将 JS 端调用 alert 方法视作向 Native 发送一个消息,Native 接受到这个消息后实现一些自定义的行为,但这种行为一般都是对警告框进行操作。

2.使用 JavaScriptCore (iOS 7+)

iOS 7 有了 JavaScriptCore 专门用来做 Native 与 JS 的交互。我们可以在 webview 完成加载之后获取 JSContext,然后利用 JSContext 将 JS 中的对象引用过来用 Native 代码对其作出解释或响应。先贴个文档🔗深入理解JSCore

JS端:

function callNative() {native.showAlert('Hello from JavaScript!');
}

Native端:

#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>// 定义一个协议,声明可以被 JavaScript 调用的方法
@protocol JSExportProtocol <JSExport>
- (void)showAlert:(NSString *)message;
@end@interface ViewController : UIViewController <JSExportProtocol>@property (nonatomic, strong) UIWebView *webView;
@property (nonatomic, strong) JSContext *jsContext;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// 初始化并配置 UIWebViewself.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];[self.view addSubview:self.webView];    self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // 获取 JavaScript 上下文self.jsContext[@"native"] = self;  // 绑定原生对象到 JavaScript 上下文
}// 实现协议方法,供 JavaScript 调用
- (void)showAlert:(NSString *)message {/*......*/}
@end

3.使用 WKWebView 和 WKScriptMessageHandler (iOS 8+)

当应用程序需要一种方法来响应网页视图中的JavaScript消息时,请采用WKScriptMessageHandler协议。当JavaScript代码发送一个特定目标的消息到消息处理器时,WebKit将调用处理器的userContentController:didReceiveScriptMessage:方法。使用该方法来实现响应。例如,可以根据网页内容的更改来更新应用程序的其他部分。

@protocol WKScriptMessageHandler

如何添加一个消息处理器呢?WKUserContentController 类有一个方法:

- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
//scriptMessageHandler:实现了 WKScriptMessageHandler 协议的对象,该对象会处理来自 JavaScript 的消息。
//name:消息的名称,JavaScript 通过这个名称发送消息。
//The name of this function is window.webkit.messageHandlers.<name>.postMessage(<messageBody>),
//where <name> corresponds to the value of this parameter. For example, if you specify the string MyFunction, 
//the user content controller defines the window.webkit.messageHandlers.MyFunction.postMessage() function in JavaScript.

举个例子:

@interface ViewController () <WKScriptMessageHandler>
@end@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];// 配置 WebViewWKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];WKUserContentController *userContentController = [[WKUserContentController alloc] init];[userContentController addScriptMessageHandler:self name:@"messageHandler"]; //----------添加脚本处理器-----------------configuration.userContentController = userContentController;WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];[self.view addSubview:webView];
}//WKScriptMessageHandler 协议方法,在接收到脚本信息时触发 //------------我们需要实现它,处理来自 JavaScript 的消息-------------------
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {if ([message.name isEqualToString:@"messageHandler"]) {// ......NSLog(@"Received message from JavaScript: %@", message.body);}
}
@end//在JS中按下面方式调用就可以了
window.webkit.messageHandlers.messageHandler.postMessage({body: 'Hello, world!'});

这里解释一下 WKUserContentController 和 WKWebView 的关系:

在 WKWebView 的初始化函数中有一个入参 configuration,它的类型是 WKWebViewConfiguration。WKWebViewConfiguration 中包含一个属性 userContentController,这个 userContentController 就是 WKUserContentController 类型的实例,我们可以用这个 userContentController 来添加不同名称的脚本处理器。

@interface WKWebView : UIView
@property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration;
@end@interface WKWebViewConfiguration : NSObject <NSSecureCoding, NSCopying>
@property (nonatomic, strong) WKUserContentController *userContentController;
@end

这里需要注意一下循环引用的问题:scriptMessageHandler 入参会被强引用,那么如果你把当前 WKWebView 所在的 UIViewController 作为第一个入参,这个 viewController 被他自己所持有的 webview.configuration. userContentController 所持有,就会造成循环引用。

在这里插入图片描述

所以一般情况下我们的代码会在 viewWillAppear 和 viewWillDisappear 成对儿的添加和删除 MessageHandler:

- (void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];[self.webview.configuration.userContentController addScriptMessageHandler:self name:@"YourFuncName"];
}- (void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:animated];[self.webview.configuration.userContentController removeScriptMessageHandlerForName:@"YourFuncName"];
}

三、Native 调用 JS

1.使用 UIWebView

在 UIWebView 中,可以使用 stringByEvaluatingJavaScriptFromString: 方法,来返回运行JavaScript脚本的结果。它是一个同步方法,会阻塞当前线程!

在这里插入图片描述

2.使用 WKWebView

在 WKWebView 中,可以使用 evaluateJavaScript:completionHandler: 方法来调用 JavaScript。因为它异步执行 JavaScript 代码,所以不会阻塞主线程,并在完成后通过回调处理结果,它的回调代码块总是在主线程中运行。

- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *error))completionHandler;

3.使用 JavaScriptCore (iOS 7+)

JavaScriptCore 框架允许直接在 Objective-C 和 JavaScript 之间互相调用方法。

Native端:

#import <JavaScriptCore/JavaScriptCore.h>@interface ViewController ()
@property (nonatomic, strong) JSContext *jsContext;
@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
}- (void)callJavaScriptFunction {JSValue *jsFunction = self.jsContext[@"javascriptFunctionName"];[jsFunction callWithArguments:@[@"param1", @"param2"]];
}
@end

JS端:

function javascriptFunctionName(param1, param2) {console.log("Called from Native with params:", param1, param2);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/52124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出:你需要了解的用户数据报协议(UDP)

文章目录 **UDP概述****1. 无连接性****2. 尽最大努力交付****3. 面向报文****4. 多种交互通信支持****5. 较少的首部开销** **UDP报文的首部格式****详细解释每个字段** **UDP的多路分用模型****多路分用的实际应用** **检验和的计算方法****伪首部的详细内容****检验和计算步…

Python 数据分析之Numpy学习(一)

Python 数据分析之Numpy学习&#xff08;一&#xff09; 一、Numpy的引入 1.1 矩阵/向量的按位运算 需求&#xff1a;矩阵的按位相加 [0,1,4] [0,1,8] [0,2,12] 1.1.1 利用python实现矩阵/向量的按位运算 # 1.通过列表实现 list1 [0, 1, 4] list2 [0, 1, 8]# 列表使用…

iOS 18 Beta 5:苹果的细腻之笔,绘制用户体验新画卷

在苹果的世界里&#xff0c;每一次系统更新都是对用户体验进行的一次精心雕琢。 随着iOS 18 Beta 5的上线&#xff0c;苹果带来了一系列令人耳目一新的功能&#xff0c;同时也在系统的每个细微之处展现了对完美的追求。 Safari浏览器的“干扰控制”功能 在今天信息充斥的数字…

SpringBoot接入高德地图猎鹰轨迹服务API

SpringBoot接入高德地图猎鹰轨迹服务API 一、AP文档 猎鹰轨迹服务API文档 二、页面图 1、需登录账号&#xff0c;申请对应的应用key值 三、代码部分&#xff1a; 1、控制层 RestController RequestMapping("/gdTrack") public class TrackController {private …

搜维尔科技:【研究】Haption Virtuose外科手术触觉视觉学习系统的开发和评估

Haption面临挑战 除此之外&#xff0c;外科医生有时会对骨组织进行非常复杂的手术&#xff0c;其中一个例子是人工耳蜗的手术植入。重要的是要避免神经或血管等危险结构受伤&#xff0c;并尽可能轻柔地进行手术。在外科医生能够安全、无差错地进行此类手术之前&#xff0c;需要…

Flink常见数据源使用教程(DataStream API)

前言 一个 Flink 程序,其实就是对 DataStream 的各种转换。具体来说,代码基本上都由以下几部分构成,如下图所示: 获取执行环境(execution environment)读取数据源(source)定义基于数据的转换操作(transformations)定义计算结果的输出位置(sink)触发程序执行(exec…

鸿蒙HarmonOS实战开发: CMake脚本编写构建NDK工程

NDK工程构建 HarmonyOS NDK默认使用CMake作为构建系统&#xff0c;随包提供了符合HarmonyOS工具链的基础配置文件ohos.toolchain.cmake&#xff0c;用于预定义CMake变量来简化开发者配置。 常用的NDK工程构建方式有&#xff1a; 从源码构建 源码构建也有不同方式&#xff1a;…

写给大模型新人的经验,刷到少走三年弯路!

这篇文章&#xff0c;我将结合自己在大模型领域的经验&#xff0c;给大家详细聊聊新人应该如何转行大模型赛道&#xff1f; 比如大模型都有哪些方向&#xff1f;各方向的能力要求和岗位匹配&#xff1f;新手转行大模型常踩的坑和常见的误区&#xff1f;以及入行大模型最顺滑的…

什么是HW,企业要通过什么方式进行HW安全保障?

一、什么是HW 网络安全形势近年出现新变化&#xff0c;网络安全态势变得越来越复杂&#xff0c;黑客攻击入侵、勒索病毒等网络安全事件愈演愈烈&#xff0c;严重威胁到我国的网络空间安全。同时&#xff0c;国内不少关键信息基础设施的建设管理单位安全意识不够、安全投入不足…

怎么管控终端电脑上的移动端口

管控终端电脑上的移动端口&#xff0c;尤其是USB等移动端口&#xff0c;是确保企业数据安全和提升网络管理效率的重要手段。 一、使用注册表编辑器禁用USB端口&#xff08;适用于Windows系统&#xff09; 打开注册表编辑器&#xff1a; 同时按下“WinR”组合键&#xff0c;打…

24年上半年天融信营收缩减1.8亿,亏损2.06亿

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330#rd 《网安面试指南》http://mp.weixin.qq.com/s?…

哪家轻量化PDM系统更适合中小企业?国内PDM系统推荐

在数字化转型的大潮中&#xff0c;中小企业面临着前所未有的挑战与机遇。产品数据管理PDM系统作为支持企业产品研发、制造和维护全生命周期的重要工具&#xff0c;其重要性日益凸显。然而&#xff0c;传统PDM系统往往因成本高、实施复杂而让中小企业望而却步。因此&#xff0c;…

java使用itext 直接生成pdf

itext 使用 需求背景itext 的使用依赖简单示例基础设置&#xff08;页面大小、边距、字体等&#xff09;段落内部&#xff0c;特殊设置关键字 字体或颜色生成动态表格页脚展示页数其他设置密码添加水印&#xff08;背景图&#xff09;目录Header, Footer分割 PDF合并 PDF 需求背…

HTML标签入门篇(1)——标题标签、段落标签、换行标签、水平线标签、图片标签、文本标签

目录 一. 标题标签 1.1 标题标签的介绍 1.2 标题标签的使用 1.3 快速在浏览器打开的插件 二. 段落、换行、水平线标签 2.1 段落标签 2.2 换行标签 2.3 水平线标签 三. 图片标签 3.1 标签举例 3.2 alt 替代文本属性 3.3 width图片宽度、heght图片高度属性 3.4 ti…

java学习--MySQL--安装与配置

\ 选中语句点击箭头&#xff0c;可出现user表

代码随想录算法day19 | 回溯算法part01 | 77. 组合,216.组合总和III,17.电话号码的字母组合

第77题. 组合 对着 在 回溯算法理论基础 给出的 代码模板&#xff0c;来做本题组合问题&#xff0c;大家就会发现 写回溯算法套路。 力扣题目链接(opens new window) 给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: […

vue3 中 defineProps 和 defineEmits

在 Vue 3 中&#xff0c;defineProps 和 defineEmits 是组合式 API 的核心功能&#xff0c;用于处理父子组件之间的传值和事件通信。 1. defineProps defineProps 用于定义并接收父组件传递过来的数据&#xff08;props&#xff09;。它是在子组件中使用的&#xff0c;接收的…

吹爆SyntaxFlow!数据流分析实战解析

正文开始前辟个谣先 最近有小伙伴来问闭源收费的事 牛牛郑重告知大家 目前还没有这个计划 请大家放心使用 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 样例解析在之前的SyntaxFlow教程中&#xff0c;我们已经看到了非常多的代码样例进行数据流分…

前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)

本章开始补充一些基础的图形绘制&#xff0c;比如绘制&#xff1a;直线、曲线、圆/椭形、矩形。这一章主要分享一下本示例是如何开始绘制一个图形的&#xff0c;并以绘制圆/椭形为实现目标。 请大家动动小手&#xff0c;给我一个免费的 Star 吧~ 大家如果发现了 Bug&#xff0c…

WEB渗透免杀篇-cshot远程shellcode

往期文章 WEB渗透免杀篇-免杀工具全集-CSDN博客 WEB渗透免杀篇-加载器免杀-CSDN博客 WEB渗透免杀篇-分块免杀-CSDN博客 WEB渗透免杀篇-Powershell免杀-CSDN博客 WEB渗透免杀篇-Python源码免杀-CSDN博客 WEB渗透免杀篇-C#源码免杀-CSDN博客 WEB渗透免杀篇-MSFshellcode免杀…