最近公司很多項(xiàng)目涉及到在原生中嵌入H5的需求,h5多為vue頁(yè)面,第一個(gè)項(xiàng)目使用的UIWebView加載,第二個(gè)項(xiàng)目使用WKWebView,轉(zhuǎn)為WK的原因是因?yàn)榍罢邔?duì)vue的兼容總會(huì)有些瑕疵,后者是蘋(píng)果主推的控件,像微信這種巨頭也在17年3月1號(hào)起正式啟用WK,用它必有原因的,在此并不陳訴。用起來(lái)還是不是很熟,雖然簡(jiǎn)單但是細(xì)節(jié)較多,故記錄提醒自己,也希望可以幫到其他人。項(xiàng)目中難免遇到兩者選其一的時(shí)候,與web交互總會(huì)出現(xiàn)一些無(wú)法預(yù)知的問(wèn)題,有時(shí)候UIWebView沒(méi)有問(wèn)題WKWebView出問(wèn)題,反之亦然。
此篇介紹了兩者與vue交互的粗略方法。
我們寫(xiě)好一個(gè)vue網(wǎng)頁(yè)片段
<el-button type="primary" id="one" v-on:click="OCcallJSClick()">OC調(diào)用JS方法</el-button>
<el-button type="primary" id="two" v-on:click="clickVUE('我是網(wǎng)頁(yè)的數(shù)據(jù)')">JS調(diào)用OC方法</el-button>
注意:我們?nèi)绻窃诰钟蚓W(wǎng)內(nèi)測(cè)試,比如本文,vue npm run dev后的網(wǎng)址是 localhost:8080/#/,所謂localhost其實(shí)是本機(jī)的ip地址,我們要保證手機(jī)和電腦在同一個(gè)局域網(wǎng)內(nèi),并且,我們需要在vue中稍作修改,在工程文件夾config下index.js中 ,把host:'localhost'改成0.0.0.0,這樣在ios中填寫(xiě)網(wǎng)址時(shí),把0.0.0.0換成pc端ip地址就可以在手機(jī)上訪問(wèn)這個(gè)網(wǎng)頁(yè)了。
UIWebView
先看老家伙
UIWebView *web = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2)];
self.webview = web;
//這里換成pc端ip地址
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://192.168.31.127:8082/#/"]];
[web loadRequest:req];
[(UIScrollView *)[[web subviews] objectAtIndex:0] setBounces:NO];
web.scalesPageToFit = NO;
web.delegate = self;
[self.view addSubview:web];
入正題;
JS調(diào)用OC 并傳參數(shù)給OC使用
要實(shí)現(xiàn)原生與網(wǎng)頁(yè)的交互,我們使用蘋(píng)果自帶的框架 <JavaScriptCore/JavaScriptCore.h> iOS7后引入的新框架。
并且我們?cè)诰W(wǎng)頁(yè)加載完成后創(chuàng)建這個(gè)工具實(shí)例
// 當(dāng)頁(yè)面開(kāi)始加載的時(shí)候調(diào)用
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
self.jsContext = [self.webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//括號(hào)內(nèi)的方法需與vue中的方法相同
self.jsContext[@"JScallOCClick"] = ^(NSString *str) {
NSLog(@"+++++++JScallOCClick+++++++");
return [self jsCallOC:str];
};
}
//注意,這里vue響應(yīng)的是clickVUE方法,JScallOCClick是在這個(gè)方法內(nèi)部,直接去響應(yīng)這個(gè)方法是無(wú)效的
clickVUE(b){
JScallOCClick(b);
},
原生view中創(chuàng)建一個(gè)Button,然后相應(yīng)方法,調(diào)用JS
self.view.backgroundColor = [UIColor lightGrayColor];
self.ocButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.ocButton.frame = CGRectMake(30, SCREEN_HEIGHT - 200, SCREEN_WIDTH - 60, 50);
[self.ocButton setTitle:@"OC按鈕調(diào)用JS代碼" forState:UIControlStateNormal];
[self.ocButton setBackgroundColor:[UIColor redColor]];
[self.ocButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.ocButton];
- (void)buttonClick:(UIButton *)sender
{
//此方法名稱必須與vue中的方法相同 括號(hào)內(nèi)攜帶參數(shù)
NSString *textJS = [NSString stringWithFormat:@"OCcallJSClick('%@')",@"我是參數(shù)"];
[self.jsContext evaluateScript:textJS];
}
OC調(diào)用JS 并傳參數(shù)給JS使用
//這里可以直接調(diào)用,綁定vue的事件 彈出ios傳來(lái)的字符串
OCcallJSClick(a){
alert(a);
console.log(a);
},
這里需要注意的是 oc調(diào)用js需要事先把這個(gè)方法暴露在外部 將方法名字掛載在mounted處
mounted(){
window.OCcallJSClick = this.OCcallJSClick;
},
ios中創(chuàng)建button,并綁定事件
self.view.backgroundColor = [UIColor lightGrayColor];
self.ocButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.ocButton.frame = CGRectMake(30, SCREEN_HEIGHT - 200, SCREEN_WIDTH - 60, 50);
[self.ocButton setTitle:@"OC按鈕調(diào)用JS代碼" forState:UIControlStateNormal];
[self.ocButton setBackgroundColor:[UIColor redColor]];
[self.ocButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.ocButton];
- (void)buttonClick:(UIButton *)sender
{
NSString *textJS = [NSString stringWithFormat:@"OCcallJSClick('%@')",@"我是參數(shù)"];
[self.jsContext evaluateScript:textJS];
}
WKWebView
再看新家伙
頭文件倒入,并遵循三個(gè)協(xié)議
#import <WebKit/WebKit.h>
@interface WKWebViewDemoViewController ()<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>
JS調(diào)用OC 并傳參數(shù)給OC使用
這里在創(chuàng)建WKWebView中,凡是js調(diào)用oc的,需要在創(chuàng)建WKWebView的時(shí)候注冊(cè)一下這個(gè)方法
//創(chuàng)建webview
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userController = [[WKUserContentController alloc] init];
config.preferences.javaScriptEnabled = YES;
config.userContentController = userController;
[userController addScriptMessageHandler:self name:@"JScallOCClick"];
WKWebView *web = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2) configuration:config];
在vue中不能再簡(jiǎn)單的寫(xiě)方法去響應(yīng)了,應(yīng)該改成
//注意,如果是無(wú)參 括號(hào)內(nèi)寫(xiě)null,不能寫(xiě)‘’ 也不能什么都不寫(xiě) 這個(gè)被坑了一天。。。
window.webkit.messageHandlers.JScallOCClick.postMessage(b);
同樣在代理中響應(yīng)js的事件
#pragma mark - 處理與js交互回調(diào)
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
//message中包含了js中所有的信息
//有兩個(gè)重要的屬性,一個(gè)是name,進(jìn)行區(qū)分判斷具體響應(yīng)某個(gè)方法
//body中就是js傳過(guò)來(lái)的參數(shù)
if ([message.name isEqualToString:@"JScallOCClick"]) {
NSLog(@"%@",message.body);
[self jsCallOC:message.body];
}
}
OC調(diào)用JS 并傳參數(shù)給JS使用
- (void)buttonClick:(UIButton *)sender
{
NSString *param = @"我是原生的數(shù)據(jù)";
NSString * jsStr =[NSString stringWithFormat:@"OCcallJSClick('%@')",param];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"--------error %@",error);
//此處可以打印error.
NSLog(@"--------result %@",result);
}];
}
注意 WKWebView加載的web中如果有彈窗,需要額外寫(xiě)一個(gè)代理處理一下彈窗,不然不會(huì)彈出
#pragma mark - WKUIDelegate
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
以上簡(jiǎn)單清晰的描述完了兩個(gè)框架與VUE的交互,簡(jiǎn)單如此,但值得整理一下。
end:如果
看完這篇
web和原生總是沒(méi)有響應(yīng)
別著急
蓋上電腦
然后
砸了吧 ~ ??