一些說(shuō)明:
在iOS開(kāi)發(fā)中難免會(huì)用到網(wǎng)頁(yè)窗悯,在iOS 8以前区匣,我們更喜歡使用UIWebView,但是UIWebView有很多弊端蒋院,首先它有一個(gè)最讓人頭疼的問(wèn)題就是內(nèi)存會(huì)暴增亏钩,并且釋放不掉,而且蘋果開(kāi)放出來(lái)的接口相對(duì)較少欺旧,目前用Xcode 9進(jìn)行iOS開(kāi)發(fā)姑丑,其支持最低的系統(tǒng)版本號(hào)為iOS 9.0,目前所在的公司也并沒(méi)有要求對(duì)iOS 8.0以前版本進(jìn)行適配于是辞友,在新的項(xiàng)目中打算摒棄UIWebView而采用基于WebKit的WKWebView栅哀。
看完這篇博客你將學(xué)到:
- 如何創(chuàng)建一個(gè)WKWebView
- WK中JS怎么去調(diào)用OC方法
- WK中怎么用OC調(diào)用js代碼
創(chuàng)建一個(gè)WKWebView
此部分相對(duì)簡(jiǎn)單,我們直接看代碼:
//創(chuàng)建一個(gè)控制器称龙,在控制器的ViewDidLoad方法中我們寫在如下代碼
- (void)viewDidLoad {
[self.view addSubview:self.weWebView];
// 此處加載的是本地HTML文件
NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
if (path) {
NSURL *fileURL = [NSURL fileURLWithPath:path];
[self.weWebView loadRequest:[NSURLRequest requestWithURL:fileURL]];
}
}
// 懶加載創(chuàng)建一個(gè)WKWebView
- (WKWebView *)wkWebView {
if (!_wkWebView) {
// 進(jìn)行配置控制器
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
// 實(shí)例化對(duì)象
configuration.userContentController = [WKUserContentController new];
// 調(diào)用JS方法
[configuration.userContentController addScriptMessageHandler:self name:@"btnClick"];
// 進(jìn)行偏好設(shè)置
WKPreferences *preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 40.0;
configuration.preferences = preferences;
// 初始化WKWebView
_weWebView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 64, APP_SCREEN_WIDTH, APP_SCREEN_HEIGHT) configuration:configuration];
}
return _wkWebView;
}
以上代碼就能創(chuàng)建一個(gè)簡(jiǎn)單的WKWebView下面我們來(lái)看看JS 和 OC 之間是怎么進(jìn)行交互的
JS調(diào)用OC
js會(huì)通過(guò)以下方法調(diào)用原生方法
window.webkit.messageHandlers.<#對(duì)象名#>.postMessage(<#參數(shù)#>)
在原生中我們只要實(shí)現(xiàn)WKScriptMessageHandler的代理方法就行了留拾,值得注意的是參數(shù)name需要與上述代碼中對(duì)象名一致
// 添加scriptMessageHandler
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
最后在
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
這個(gè)方法中獲取做下判斷響應(yīng)對(duì)應(yīng)的方法即可,下面奉上事例代碼:
// 初始化WKWebView鲫尊,在實(shí)例化WKWebViewConfiguration對(duì)象的時(shí)候我們同時(shí)添加scriptMessageHandler
//進(jìn)行配置控制器
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
//實(shí)例化對(duì)象
configuration.userContentController = [WKUserContentController new];
//調(diào)用JS方法
[configuration.userContentController addScriptMessageHandler:self name:@"btnClick"];
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"btnClick"]) {
NSDictionary *jsData = message.body;
NSLog(@"%@", message.name, jsData);
//讀取js function的字符串
NSString *jsFunctionString = jsData[@"result"];
//拼接調(diào)用該方法的js字符串(convertDictionaryToJson:方法將NSDictionary轉(zhuǎn)成JSON格式的字符串)
NSString *jsonString = [NSDictionary convertDictionaryToJson:@{@"test":@"123", @"data":@"666"}];
NSString *jsCallBack = [NSString stringWithFormat:@"(%@)(%@);", jsFunctionString, jsonString];
//執(zhí)行回調(diào)
[self.weWebView evaluateJavaScript:jsCallBack completionHandler:^(id _Nullable result, NSError * _Nullable error) {
if (error) {
NSLog(@"err is %@", error.domain);
}
}];
}
}
以上需要注意的是痴柔,由于message的body只能是 NSNumber, NSString, NSDate, NSArray, NSDictionary, NSNull這幾種類型,可以看下圖蘋果官方注釋疫向,所以我們無(wú)法將js函數(shù)直接傳給原生咳蔚,在需要進(jìn)行回調(diào)的環(huán)境下,我們要將js回調(diào)函數(shù)轉(zhuǎn)成String后再傳給原生搔驼,再由原生獲取后進(jìn)行相關(guān)回調(diào)操作谈火,實(shí)際上這是已經(jīng)進(jìn)行了動(dòng)態(tài)js注入(執(zhí)行回調(diào)方法)
OC調(diào)用JS
動(dòng)態(tài)注入js方法就像對(duì)比較簡(jiǎn)單了,我們只要使用相應(yīng)方法即可匙奴。
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
下面奉上一個(gè)事例代碼
// 此處是設(shè)置需要調(diào)用的js方法以及將對(duì)應(yīng)的參數(shù)傳入堆巧,需要以字符串的形式
NSString *jsFounction = [NSString stringWithFormat:@"getAppConfig('%@')", APP_CHANNEL_ID];
// 調(diào)用API方法
[self.weexWebView evaluateJavaScript:jsFounction completionHandler:^(id object, NSError * _Nullable error) {
NSLog(@"obj:%@---error:%@", object, error);
}];
最后貼上測(cè)試HTML代碼
<html>
<header>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
function btnClick() {
test({
testString: "testString",
result: function(data) {
//理論上傳過(guò)來(lái)的是轉(zhuǎn)成JSON格式字符串的MAP,需要統(tǒng)一一下KEY值
// 此處demo相當(dāng)與document.getElementById("demo")
demo.innerHTML = data["data"];
}
})
}
function test(testData) {
var testStr = testData.testString
var result = testData.result
//此處不能直接將回調(diào)函數(shù)傳給iOS需要將回調(diào)函數(shù)轉(zhuǎn)成字符串,其他的保持不變即可
testData.result = result.toString()
window.webkit.messageHandlers.btnClick.postMessage(testData);
}
</script>
</header>
<body bgcolor="red">
<h2> js回調(diào)Test </h2>
<br/>
<br/>
<button type="button" onclick="btnClick()">test回調(diào)</button>
<br/>
<br/>
<p id="demo">暫無(wú)回調(diào)</p>
</body>
</html>
最后,本人水平有限如有錯(cuò)誤歡迎指正>_<