UIWebView delegate 協定方法
//UIWebView自帶了一個方法, 可以直接調用JS代碼(轉化為string類型的js代碼)
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
//例如修改id為‘html’标簽内部的text屬性
[web stringByEvaluatingJavaScriptFromString:@"document.getElementById('html').innerText='修改内容'"];
//也可以執行多行js代碼
[web stringByEvaluatingJavaScriptFromString:@"var div = document.getElementById('html'); div.innerText = '修改内容'"];
利用JavaScriptCore實作互動
JavaScriptCore中類及協定:
JSContext:給JavaScript提供運作的上下文環境
JSValue:JavaScript和Objective-C資料和方法的橋梁
JSManagedValue:管理資料和方法的類
JSVirtualMachine:處理線程相關,使用較少
JSExport:這是一個協定,如果采用協定的方法互動,自己定義的協定必須遵守此協定
OC中提供了JavaScriptCore 這個庫,使得OC與js的互動變得更加友善。
使用方法:
1 加入JavaScriptCore 這個framework
2 引入頭檔案<JavaScriptCore/JavaScriptCore.h>
3 在VC裡面加入一個JSContext屬性
@property (strong, nonatomic) JSContext *context;
JSContext是什麼那? 我們看一下api裡面的解釋
JSContext是一個JS的執行環境,所有的JS執行都發生在一個context裡面, 所有的JS value都綁定到context裡面
具體使用如下:
//初始化context
self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//OC調用JS
//(1)例如html的script中一個方法
function dolike(a,b,c){
}
//通過OC調用此方法
NSString * method = @"dolike";
JSValue * function = [self.context objectForKeyedSubscript:method];
//這裡面的a,b,c就是OC調用JS的時候給JS傳的參數
[function callWithArguments:@[a,b,c]];
//JS調用OC
//例如網頁中有個标簽,點選button的時候調用Jump方法, 此處3為傳入的參數
<button onclick="jump('3')">點我</button>
//當點選網頁中的button的時候,觸發jump方法, 在OC中用如下代碼可以捕捉到jump方法, 并拿到JS給我傳的參數‘3’
self.context[@"jump"] = ^(NSString * str){
//此處 str 值為'3'(js調用OC時傳給OC的參數)
};
WKWebView
說到WKWebView, 首先要說下WKWebView的優勢
1 更多的支援HTML5的特性
2 官方宣稱的高達60fps的滾動重新整理率以及内置手勢
3 将UIWebViewDelegate與UIWebView拆分成了14類與3個協定,以前很多不友善實作 的功能得以實作
4 Safari相同的JavaScript引擎
5 占用更少的記憶體
類:
WKBackForwardList: 之前通路過的 web 頁面的清單,可以通過後退和前進動作來通路到。
WKBackForwardListItem: webview 中後退清單裡的某一個網頁。
WKFrameInfo: 包含一個網頁的布局資訊。
WKNavigation: 包含一個網頁的加載進度資訊。
WKNavigationAction: 包含可能讓網頁導航變化的資訊,用于判斷是否做出導航變化。
WKNavigationResponse: 包含可能讓網頁導航變化的傳回内容資訊,用于判斷是否做出導航變化。
WKPreferences: 概括一個 webview 的偏好設定。
WKProcessPool: 表示一個 web 内容加載池。
WKUserContentController: 提供使用 JavaScript post 資訊和注射 script 的方法。
WKScriptMessage: 包含網頁發出的資訊。
WKUserScript: 表示可以被網頁接受的使用者腳本。
WKWebViewConfiguration: 初始化 webview 的設定。
WKWindowFeatures: 指定加載新網頁時的視窗屬性。
協定:
WKNavigationDelegate: 提供了追蹤主視窗網頁加載過程和判斷主視窗和子視窗是否進行頁面加載新頁面的相關方法。
WKScriptMessageHandler: 提供從網頁中收消息的回調方法。
WKUIDelegate: 提供用原生控件顯示網頁的方法回調。
WKWebView的 UIDelegate 提供了三個協定方法, 可以讓前端很友善的攔截JS的alert, confirm, prompt方法。除此之外,OC,JS互調可以按照如下方法。
1 OC 調用JS
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
//例如OC調用JS的方法 setName
[webView evaluateJavaScript:@"setname('張三')" completionHandler:nil];
//此處 setname為JS定義的方法名, 内部 ‘張三’為傳給JS的參數。 如果setname方法需要傳入一個json或者array等非字元參數, 需要用format方法将其轉為string類型,在調用evaluate方法。例如
NSString * para = [NSString stringWithFormat:@"setname('%@')",json];
JS調用OC
此時就要用到WKScriptMessageHandler了
//首先.m中加入屬性
@property (nonatomic ,strong)WKUserContentController * userCC;
//1 遵循WKScriptMessageHandler協定
//2 初始化
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];
self.wkWebViw = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
[self.wkWebViw loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.webPageUrl]]];
[self.view addSubview:self.wkWebViw];
self.userCC = config.userContentController;
[self.userCC addScriptMessageHandler:self name:@"callOSX"];
//此處相當于監聽了JS中callFunction這個方法
[self.userCC addScriptMessageHandler:self name:@"callFunction"];
//當JS發出callFunction這個方法指令的時候, WKScriptMessageHandler的協定方法中我們就會收到這個消息
#pragma mark WKScriptMessageHandler delegate
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
//這個回調裡面, message.name代表方法名(‘本例為 callFunction’), message.body代表JS給我們傳過來的參數
}
//最後, VC銷毀的時候一定要把handler移除
-(void)dealloc
{
[_userContentController removeScriptMessageHandlerForName:@"callFunction"];
}
//對應的JS代碼
<button onclick="buttonClick('溫馨提示')">點我</button>
<script>
function buttonClick(string){
//JS調用OC, 格式如下
//(window.webkit.messageHandlers.Method_Name.postMessage(parameterToOC))
window.webkit.messageHandlers.callFunction.postMessage(string)
}
</script>