OC与JS交互之WKWebView

 

上一篇文章咱们使用了JavaScriptCore框架重写了以前的示例,iOS8苹果偏心HTML5,重构了UIWebVIew,给咱们带来了WKWebView,使其性能、稳定性、功能大幅度提高,也更好的支持了HTML5的新特性。这篇文章就们就拿WKWebView来小试牛刀javascript

 

1、WKWebView Framework

WKWebView的14个类与3个协议:html

 

WKBackForwardList: 以前访问过的 web 页面的列表,能够经过后退和前进动做来访问到。java

WKBackForwardListItem: webview 中后退列表里的某一个网页。react

WKFrameInfo: 包含一个网页的布局信息。git

WKNavigation: 包含一个网页的加载进度信息。github

WKNavigationAction: 包含可能让网页导航变化的信息,用于判断是否作出导航变化。web

WKNavigationResponse: 包含可能让网页导航变化的返回内容信息,用于判断是否作出导航变化。react-native

WKPreferences: 归纳一个 webview 的偏好设置。服务器

WKProcessPool: 表示一个 web 内容加载池。 app

WKUserContentController: 提供使用 JavaScript post 信息和注射 script 的方法。

WKScriptMessage: 包含网页发出的信息。

WKUserScript: 表示能够被网页接受的用户脚本。 

WKWebViewConfiguration: 初始化 webview 的设置。

WKWindowFeatures: 指定加载新网页时的窗口属性。

WKWebsiteDataStore: 包含网页数据存储和查找。

 

WKNavigationDelegate: 提供了追踪主窗口网页加载过程和判断主窗口和子窗口是否进行页面加载新页面的相关方法。

WKUIDelegate: 提供用原生控件显示网页的方法回调。

WKScriptMessageHandler: 提供从网页中收消息的回调方法。

 

2、WKWebView中的三个代理方法 

1. WKNavigationDelegate

该代理提供的方法,能够用来追踪加载过程(页面开始加载、加载完成、加载失败)、决定是否执行跳转。

// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 页面加载完成以后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;

页面跳转的代理方法有三种,分为(收到跳转与决定是否跳转两种)

// 接收到服务器跳转请求以后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在发送请求以前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

 

2. WKUIDelegate

建立一个新的WKWebView

// 建立一个新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;

剩下三个代理方法全都是与界面弹出提示框相关的,针对于web界面的三种提示框(警告框、确认框、输入框)分别对应三种代理方法。

// 界面弹出警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
// 界面弹出确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
// 界面弹出输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;

 

3. WKScriptMessageHandler

这个协议中包含一个必须实现的方法,这个方法是native与web端交互的关键,它能够直接将接收到的JS脚本转为OC或Swift对象。

// 从web界面中接收到一个脚本时调用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

  

3、使用WKWebView重写

这里咱们和以前的界面作了一点改动,以前OC调用JS的时候是进行弹框处理,这里我在写的时候,很郁闷,方法能够调用过去,可是惟独js的alert方法调用没有效果,因此这里采用了输出到div的形式,并增长了一个clear按钮

WKWebView不支持nib文件,因此这里须要使用代码初始化并加载WebView 

WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.preferences.minimumFontSize = 18;

self.wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height/2) configuration:config];
[self.view addSubview:self.wkWebView];


NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
NSURL *baseURL = [[NSBundle mainBundle] bundleURL];
[self.wkWebView loadHTMLString:[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil] baseURL:baseURL];

OC端:

//1. JS调用OC 添加处理脚本
[userCC addScriptMessageHandler:self name:@"showMobile"];
[userCC addScriptMessageHandler:self name:@"showName"];
[userCC addScriptMessageHandler:self name:@"showSendMsg"];

// 在代理方法中处理对应事件
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSLog(@"%@",NSStringFromSelector(_cmd));
    NSLog(@"%@",message.body);

    if ([message.name isEqualToString:@"showMobile"]) {
        [self showMsg:@"我是下面的小红 手机号是:18870707070"];
    }
    
    if ([message.name isEqualToString:@"showName"]) {
        NSString *info = [NSString stringWithFormat:@"你好 %@, 很高兴见到你",message.body];
        [self showMsg:info];
    }
    
    if ([message.name isEqualToString:@"showSendMsg"]) {
        NSArray *array = message.body;
        NSString *info = [NSString stringWithFormat:@"这是个人手机号: %@, %@ !!",array.firstObject,array.lastObject];
        [self showMsg:info];
    }
}

// 2. native调用js
- (IBAction)btnClick:(UIButton *)sender {
    if (!self.wkWebView.loading) {
        if (sender.tag == 123) {
            [self.wkWebView evaluateJavaScript:@"alertMobile()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
                //TODO
                NSLog(@"%@ %@",response,error);
            }];
        }
        
        if (sender.tag == 234) {
            [self.wkWebView evaluateJavaScript:@"alertName('小红')" completionHandler:nil];
        }
        
        if (sender.tag == 345) {
            [self.wkWebView evaluateJavaScript:@"alertSendMsg('18870707070','周末登山真是件愉快的事情')" completionHandler:nil];
        }

    } else {
        NSLog(@"the view is currently loading content");
    }
}

JS端:

function clear() {
    document.getElementById('mobile').innerHTML = ''
    document.getElementById('name').innerHTML = ''
    document.getElementById('msg').innerHTML = ''
}

//OC调用JS的方法列表
function alertMobile() {
    //这里已经调用过来了 可是搞不明白为何alert方法没有响应
    //alert('我是上面的小黄 手机号是:13300001111')
    document.getElementById('mobile').innerHTML = '我是上面的小黄 手机号是:13300001111'
}

function alertName(msg) {
    //alert('你好 ' + msg + ', 我也很高兴见到你')
    document.getElementById('name').innerHTML = '你好 ' + msg + ', 我也很高兴见到你'
}

function alertSendMsg(num,msg) {
    //window.alert('这是个人手机号:' + num + ',' + msg + '!!')
    document.getElementById('msg').innerHTML = '这是个人手机号:' + num + ',' + msg + '!!'
}

//JS响应方法列表
function btnClick1() {
    window.webkit.messageHandlers.showMobile.postMessage(null)
}

function btnClick2() {
    window.webkit.messageHandlers.showName.postMessage('xiao黄')
}

function btnClick3() {
    window.webkit.messageHandlers.showSendMsg.postMessage(['13300001111', 'Go Climbing This Weekend !!!'])
}

 

4、后记

  至此,整个系列的示例已完成,过程当中收货颇丰。每篇文章都会对知识点进行总结,在文章末尾给出相关连接和示例DEMO的地址,一样本文的示例也已放在GitHub上,须要的同窗取走不谢。关于这几篇文章的DEMO,我汇总了下放在了360云盘中,同窗们也能够下载此压缩包,解压,对比学习,在看的过程当中有什么呢疑问,欢迎在bolg下面留言,若发现文章中有那些地方没有阐述清,或者没有提到也能够留言告诉我

  随着H5的强大,hybrid app已经成为当前互联网的大方向,单纯的native app和web app在某些方面显得就很劣势,2015年,Facebook在React.js Conf 2015大会上推出了基于JavaScript的开源框架React Native,使PhoneGap、Cordova时代完全成为了过去式,React Native有着良好的原生控件的体验,完全摆脱了UIWebView那让人不爽的性能和交互流程,并且具备良好的拓展和热更新能力,它的功能远远不止这些,有兴趣的同窗,能够进入下面的 传送门RN之不归路

 

戳这里:本文的DEMO地址欢迎star

戳这里:系列示例DEMO合集:https://yunpan.cn/OcMmK58epCKjzn (提取码:e525)

参考资料(戳这里):

>  http://nshipster.cn/wkwebkit/

>  http://www.huangyibiao.com/archives/742

>  https://github.com/reactnativecn/react-native-guide

相关文章
相关标签/搜索