iOS WKWebView JS 与 原生交互小结
2021-05-10 本文已影响0人
Superman168
前言
目前iOS项目中 Webview 几乎都会用到,iOS 8 之前使用UIWebView,iOS 8 之后 Apple 就不推荐使用了,目前已经放弃了,如果项目中存在就无法上架了,需要转为WKWebView了,说实话 UIWebView 是有性能上的缺陷,内存优化不够友好等,但是不得不说这是老的iOS开发人员用的最熟练熟悉的了,用起来得心应手。非迫不得已还真不愿转到WKWebView。好吧,既然已经这样了,又何必苦苦单恋一支花呢?
看了网上教程很多,自己使用小结一下,简单易用,本文适用于菜鸟级开发,废话不说了,
本地 html 文件,如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body style="margin: 24px">
<p style="text-align:center;text-indent:2em;">
<span style="color:#333333;font-size:18px;font-family:PingFang SC Semibold;"><strong>Demo演示说明</strong></span>
</p>
<span style="color:#666666;font-size:14px;font-family:SimHei;">测试内容。</span><br />
<br />
<span style="color:#666666;font-size:14px;font-family:SimHei;">如您同意</span>
<span style="color:#4F91FF;font-size:14px;font-family:SimHei;"><strong onclick="jumpUserProtocol()">《用户协议》</strong>
<span style="color:#000000;">、</span>
<span style="color:#666666;"></span></span><span style="color:#4F91FF;font-size:14px;font-family:SimHei;"><strong onclick="jumpPrivacyPolicy()">《隐私政策》</strong></span>
<span style="color:#666666;font-size:14px;font-family:SimHei;">,请点击“继续使用”开始使用我们的产品和服务。</span><span style="color:#666666;"></span>
<p>
<br />
</p>
<script type="text/javascript">
function jumpUserProtocol() {
window.webkit.messageHandlers.jumpUserProtocol.postMessage("UserProtocol");
}
function jumpPrivacyPolicy(){
window.webkit.messageHandlers.jumpPrivacyPolicy.postMessage("PrivacyPolicy");
}
function callJS(message) {
alert(message);
window.webkit.messageHandlers.jumpPrivacyPolicy.postMessage("PrivacyPolicy");
}
</script>
</body>
</html>
最主要的方法:发送消息
window.webkit.messageHandlers.<#对象名#>.postMessage(<#参数#>)

注意:对象名和方法名jumpUserProtocol名字的一致,参数可以是常用的NSArray,NSDictionary等类型,先说下在这个Demo中其实没用上,用的方法名判断的。
WKWebView 创建
#pragma mark ========= lazy load =========
-(WKWebView *)webView {
if (!_webView) {
// 2. 网页JS调原生:
// 1> 需要先设置 Webview.configuration 的 userContentController
// 2> 注册方法名 [wkUController addScriptMessageHandler:self name:];
// 3> 遵守协议<WKScriptMessageHandler>,实现其方法.
// 4> 在控制器销毁时,需要移除方法名注册
/*! 设置网页的配置文件 */
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
/*! 允许视频播放 */
configuration.allowsAirPlayForMediaPlayback = YES;
/*! 允许在线播放 */
configuration.allowsInlineMediaPlayback = YES;
/*! 允许可以与网页交互,选择视图 */
configuration.selectionGranularity = YES;
/*! web内容处理池 */
configuration.processPool = [[WKProcessPool alloc] init];
/*! 自定义配置,一般用于 js调用oc方法(OC拦截URL中的数据做自定义操作) */
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
/*! 自适应屏幕宽度,注入js */
NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width,user-scalable=no'); document.getElementsByTagName('head')[0].appendChild(meta); var lastDiv = document.createElement('div');lastDiv.id = 'last-div'; document.getElementsByTagName('body')[0].appendChild(lastDiv)";
WKUserScript *wkUserScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[wkUController addUserScript:wkUserScript];
/*! 允许用户更改网页的设置 */
configuration.userContentController = wkUController;
//JS调用OC 添加处理脚本
[wkUController addScriptMessageHandler:self name:JSMessageName_Protocol];
[wkUController addScriptMessageHandler:self name:JSMessageName_PrivacyPolicy];
// 进行偏好设置
// WKPreferences *preferences = [WKPreferences new];
// preferences.javaScriptCanOpenWindowsAutomatically = YES;
// preferences.minimumFontSize = 40.0;
// configuration.preferences = preferences;
CGRect frame = CGRectMake(0, 64, 375,600);
_webView = [[WKWebView alloc] initWithFrame:frame configuration:configuration];
_webView.navigationDelegate = self;
_webView.scrollView.showsHorizontalScrollIndicator = NO;
// _webView.scrollView.pagingEnabled = NO;
// _webView.scrollView.bounces = NO;
_webView.backgroundColor = [UIColor orangeColor];
}
return _webView;
}
注意: addScriptMessageHandler
//JS调用OC 添加处理脚本
[wkUController addScriptMessageHandler:self name:JSMessageName_Protocol];
[wkUController addScriptMessageHandler:self name:JSMessageName_PrivacyPolicy];
name为方法名 ,和JS 中的保持一致,添加脚本,相当于给Webview添加一个监听,有这个功能来处理JS。
加载本地 html 文件
// WKWebView 网页加载
NSString* path = [[NSBundle mainBundle] pathForResource:@"UserPrivateInfo" ofType:@"html"];
NSURL* url = [NSURL fileURLWithPath:path];
NSURLRequest* request = [NSURLRequest requestWithURL:url] ;
[self.webView loadRequest:request];
[self.view addSubview:self.webView];
处理事件
在WKScriptMessageHandler代理方法中处理回调,实现自己的逻辑。
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:JSMessageName_Protocol]) {
NSLog(@"********用户协议********");
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"用户协议js传递过来的参数"message:[NSString stringWithFormat:@"方法名:%@\n\n参数:%@",message.name,message.body] preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}]];
[[[UIApplication sharedApplication] windows].firstObject.rootViewController presentViewController:alertController animated:YES completion:^{
}];
}else if ([message.name isEqualToString:JSMessageName_PrivacyPolicy]){
NSLog(@"********隐私政策********");
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"隐私政策js传递过来的参数"message:[NSString stringWithFormat:@"方法名:%@\n\n参数:%@",message.name,message.body] preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}]];
[[[UIApplication sharedApplication] windows].firstObject.rootViewController presentViewController:alertController animated:YES completion:^{
}];
}
}
上面就是JS调用OC原生实现。
OC调用JS
这个其实很简单,就一个方法:
#pragma mark -- 原生调用 JS
- (IBAction)callJS:(id)sender {
// 1. webview调用JS函数, JS代码可根据需要拼接好。
// 此处是设置需要调用的js方法以及将对应的参数传入,需要以字符串的形式
// 带参数
NSString *jsFounction = [NSString stringWithFormat:@"callJSFunc('%@')", @"UserProtocol"];
// 不带参数
// NSString *jsFounction = [NSString stringWithFormat:@"jumpUserProtocol()"];
// 调用API方法
[self.webView evaluateJavaScript:jsFounction completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"evaluateJavaScript:\n result = %@ error = %@",result, error);
}else{
NSLog(@"调用成功");
}
}];
}