WKWebView OC与JS交互

WKWebView OC与JS交互文章目录 WKWebViewOC 与 JS 交互 1 OC 调用 JS2 JS 调用 OC3 总结 WKWebViewOC 与 JS 交互整体上看原理还是挺简单的 即 OC 端向 JS 中注入 JS 脚本或者注入一个事件对象 生成一个时间 handeler 当 JS 触发此事件时 handler 处理事件的回调用 实现相互传值和事件交互的效果 1 OC 调用 JSOC 调用 JS 方法主要是通过执行 javaScript 脚本来实现的 WKWebKit 提供的主要方法是 void evaluateJava NSString

WKWebView OC与JS交互

整体上看原理还是挺简单的,即OC端向JS中注入JS脚本或者注入一个事件对象,生成一个时间handeler,当JS触发此事件时,handler处理事件的回调用,实现相互传值和事件交互的效果。

1. OC调用JS

OC调用JS方法主要是通过执行javaScript脚本来实现的。

WKWebKit提供的主要方法是:- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler

  • 例1:通过javaScript执行js里的某个函数
NSString *script = [NSString stringWithFormat:@"function('%@', '%@');", xx, xx]; [self.webView evaluateJavaScript:script completionHandler:^(id result, NSError *error) { 
    // ... }]; 

通过的webView提供的API,执行一段javaScript脚本代码,即OC调用了js中的function()这个函数,xx,xx分别是调用js函数时候传递的两个参数。

  • 例2:通过evaluateJavaScript获取js某属性值

设置userAgent

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { 
    // Set the user-Agent. [webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable result, NSError * _Nullable error) { 
    NSString *versionIdentifier = [NSString stringWithFormat:@"%@ %@",WMS_CUSTOMER_USER_AGENT,[EIInfoPlist appVersion]]; if (![result containsString:versionIdentifier]) { 
    NSString *deviceIdentifier = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) ? @"iPad" :@"iPhone"; webView.customUserAgent = [NSString stringWithFormat:@"%@^%@^%@",result,deviceIdentifier,versionIdentifier]; } NSLog(@"user-Agent : %@",webView.customUserAgent); }]; } 

如上,我们通过执行js的方法navigator.userAgent来获取userAgent,实际上是调用的navigator的getUserAgent()。

2. JS调用OC

JS调用OC方法,感觉更像是一种通知。

OC端需要先注册事件,这个事件可能是js端某个按钮的点击事件或者某个函数事件。

需要注入到JS中的消息handeler名称,在JS中应该会注册一个事件对象。

static NSString *const kLoadSuccessfully = @"kLoadSuccessfully"; 

通过以下方式注入js或者添加一个消息处理对象

 // 注册事件 [self addScriptHandhelderTo:webView message:kSessionTimeOut javascript:nil]; // 这种方式是注入一段js脚本 //[self addScriptHandhelderTo:webView message:kSessionTimeOut javascript:[NSString stringWithFormat:@"function SessionTimeOut() { \n window.webkit.messageHandlers.%@.postMessage(body); \n}", kSessionTimeOut]]; 
- (void)addScriptHandhelderTo:(WKWebView *)webView message:(NSString *)message javascript:(NSString *)javascript { 
    if (message) { 
    WMSJavascriptHandlerDelegateBridge *delegateBridge = [[WMSJavascriptHandlerDelegateBridge alloc] initWithDelegate:self]; [webView.configuration.userContentController addScriptMessageHandler:delegateBridge name:message]; [delegateBridge release]; } if (javascript) { 
    WKUserScript *userScript = [[WKUserScript alloc] initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]; [webView.configuration.userContentController addUserScript:userScript]; [userScript release]; } } 

当JS触发该事件时,会通过window.webkit.messageHandlers.xx来获取到OC注入的事件对象xx,然后post一个message给OC端。

例如:

if (window.webkit && window.webkit.messageHandlers.NavigationBar) { window.webkit.messageHandlers.NavigationBar.postMessage({ ... }); } 

NavigationBar就是OC端注入到JS中的一个事件对象。JS端通过 window.webkit.messageHandlers.NavigationBar这种方式,从messageHandlers里面获取到NavigationBar这个事件对象。然后通过 postMessage({ ... })发送一条消息到OC端,其中 {…} 内,可以自定义一些字段。这些字段对应的是OC端的message的body。NavigationBar对应的OC中的message的name。

再例如:

if (window.webkit && window.webkit.messageHandlers.LoadSuccessfully) { 
    window.webkit.messageHandlers.LoadSuccessfully.postMessage({ 
    Result: Sucess }); } 

OC端需要实现WKScriptMessageHandler回调来接收JS发送的消息

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { 
    if ([message.name isEqualToString:kLoadSuccessfully]) { 
    // .. } } 

message.name即JS端的事件对象,也就是OC端注册的事件对象,或者说是OC端注入到JS中的一个事件对象。
message.body即JS端发送的消息的消息体。

3. 总结

总之,JS和OC的通信,是通过OC向JS中注入事件对象或者注入JS脚本来实现的。

关键点:

  1. OC端必须注册事件/注入JS
  2. OC端需实现WKScriptMessageHandler来接收JS事件回调消息

注意:

  1. 添加了事件,需要在合适的地方移除事件,否则可能导致闪退

下面直接上代码:

OC端:

#import "ViewController.h" #import <WebKit/WebKit.h> // 定义需要注册的js消息事件handler名称 static NSString *const kScriptMessageHandler = @"ScriptMessageHandler"; @interface ViewController ()<WKUIDelegate,WKNavigationDelegate,WKScriptMessageHandler> // 遵循 WKScriptMessageHandler 协议 @property (nonatomic, strong) WKWebView *webView; @end @implementation ViewController - (void)viewDidLoad { 
    [super viewDidLoad]; // Do any additional setup after loading the view. WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config]; self.webView.UIDelegate = self; self.webView.navigationDelegate = self; NSString *URLString = @"https://"; NSURLRequest *testRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:URLString]]; [self.webView loadRequest:testRequest]; [self.view addSubview:self.webView]; } - (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; // 注册js事件 //这里给定一个消息事件的handler名称,在js端会对应的生成一个事件对象 [self.webView.configuration.userContentController addScriptMessageHandler:self name:kScriptMessageHandler]; } - (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; // 移除注册的js事件 [self.webView.configuration.userContentController removeScriptMessageHandlerForName:kScriptMessageHandler]; } #pragma mark - WKScriptMessageHandler // 实现 WKScriptMessageHandler 协议,接收js发送的时间回调 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { 
    // 这里的message.name即我们注册过的 @"ScriptMessageHandler" // message.body是一个map,这个可以在js中自定义,传输任何key:value。 // 建议js端在body中有一个固定的字段,例如EventType,用来区分事件。这样的话我们只注册一个ScriptMessageHandler,实现多个不同事件的处理。减少代码,方便管理,同时减少js上的内存开销。不管是对客户端还是js端来说都是一个更加合理的解决方案。 NSLog(@"didReceiveScriptMessage %@ %@",message.name,message.body); if ([message.name isEqualToString:kScriptMessageHandler]) { 
    NSString *eventType =message.body[@"EventType"]; if ([eventType isEqualToString:@"EventType_ReLogin"]) { 
    // ... } ... } } @end 

js端

if (window.webkit && window.webkit.messageHandlers.ScriptMessageHandler) { 
    window.webkit.messageHandlers.ScriptMessageHandler.postMessage({ 
    Result: sucess, EventType: EventType_ReLogin }); 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199717.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 下午12:22
下一篇 2026年3月20日 下午12:22


相关推荐

  • STM32 串口中断总结

    STM32 串口中断总结本文以 USART1 为例 叙述串口中断的编程过程 1 先来讲述一下在应用串口中断时涉及到的一些库文件 首先对于 STM32 外设库文件的应用编程 misc c 和 stm32f10x rcc c 是肯定要添加到 接下来就是我们要用到的相关外设了 毫无疑问 串口文件 stm32f10x usart c 是必须的 串口通信是对通用 GPIO 端口引脚的功能复用 所以还需要 stm32f10x gpi

    2026年3月19日
    1
  • java notifyall_Java Thread notifyAll()方法[通俗易懂]

    java notifyall_Java Thread notifyAll()方法[通俗易懂]Thread类的notifyAll()方法用于唤醒所有线程。此方法向特定对象的所有等待线程发出通知。如果使用notifyAll()方法并且多个线程正在等待通知,那么所有线程都会收到通知,但线程的执行将逐个执行,因为线程需要锁定,并且只有一个锁可用于一个对象。语法publicfinalvoidnotifyAll()返回此方法不返回任何值。异常IllegalMonitorStateExcepti…

    2025年10月4日
    5
  • 史上最全设计模式导学目录(完整版)

    史上最全设计模式导学目录(完整版)圣诞献礼!2012年-2013年,Sunny在CSDN技术博客中陆续发表了100多篇与设计模式相关的文章,涵盖了七个面向对象设计原则和24个设计模式(23个GoF设计模式+简单工厂模式),为了方便大家学习,现将所有与设计模式学习相关文章的链接进行了整理,希望能给各位带来帮助!

    2022年6月14日
    27
  • 【离散数学】单射、满射、双射、映射的合成与逆映射

    【离散数学】单射、满射、双射、映射的合成与逆映射单射、满射、双射、映射的合成与逆映射

    2022年5月15日
    207
  • 软件工程期末试题及答案(史上最全)

    软件工程期末试题及答案(史上最全)软件工程期末试题及答案1.开发瀑布模型中的软件定义时期各个阶段依次是:(B)A)可行性研究,问题定义,需求分析。B)问题定义,可行性研究,需求分析。C)可行性研究,需求分析,问题定义。D)以上顺序都不对。(软件开发时期:概要设计、详细设计、软件实现、软件测试)2.可行性研究主要从以下几个方面进行研究:(A)A)技术可行性,经济可行性,操作可行性。B)技术可行性,经济可行性,系统可行性。C)经济可行性,系统可行性,操作可行性。D)经济可行性,系统可行性,时间可行性。..

    2025年12月2日
    8
  • 如何查看python安装位置图_如何查看pymysql 安装成功

    如何查看python安装位置图_如何查看pymysql 安装成功方法 步骤 mysql 安装文件分为两种 一种是 msi 格式的 一种是 zip 格式的 如果是 msi 格式的可以直接点击安装 按照它给出的安装提示进行安装 相信大家的英文可以看懂英文提示 一般 mysql 将会安装在 c programfiles mysql mysqlserver5 6 该目录中 zip 格式是自己解压 解压缩之后其实 mysql 就可以使用了 但是要进行配置 解压之后可以将该文件夹改名 放

    2026年3月16日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号