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

相關文章
相關標籤/搜索