webview和js交互_webview2是什么软件

webview和js交互_webview2是什么软件文章目录WKWebViewOC与JS交互1.OC调用JS2.JS调用OC3.总结WKWebViewOC与JS交互整体上看原理还是挺简单的,即OC端向JS中注入JS脚本或者注入一个事件对象,生成一个时间handeler

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. 添加了事件,需要在合适的地方移除事件,否则可能导致闪退

建议:
不建议每个事件都注册一次,建议一个WebView只注册一个事件,通过事件的消息体里自定义事件类型去做事件区分,这样的好处显而易见,注入少,代码也好管理,JS端调用也好处理。

下面直接上代码:

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
});

这是js里的一个Sesstion过期,通知OC端重新登录,等待OC端登的方法。使用window.webkit.messageHandlers.SessionTimeOut来发送消息给OC端。这里的SessionTimeOut是客户端你和js端商定好的,OC端注册到js的事件名称。
在这里插入图片描述

打印了一下js端的messageHandlers和window.webkit.messageHandlers.ScriptMessageHandler,都是对象类型的,这也说明了注册事件本质上就是生成了一个js事件对象。下截图中的SesstionTimeOut即这里的ScriptMessageHandler,调试时demo中随便写了一个名字,这个可忽略。
在这里插入图片描述

今天的文章webview和js交互_webview2是什么软件分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/74761.html

(0)
编程小号编程小号

相关推荐

发表回复

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