最近在幫公司做新版本的時(shí)候夫植,在加載一個(gè)H5界面的時(shí)候椅挣,需要和Javascript交互逗扒,之前只是會(huì)粗略使用WKWebView乒融,今天就認(rèn)真地上網(wǎng)查閱了一下資料
前言
With iOS 8 Apple has added a ton of user-facing goodness. The Health app, Apple Pay, and expanded TouchID capabilities?—?just a few things everyday users will be happy about. On the sdk side they’ve added a lot of cool things as well, but one I’m excited about is the addition of WKWebView. This is very similar to the related–but less powerful–UIWebView available since iOS 2. UIWebView offers simple methods for loading a remote url, navigating forwards and back, and even running basic JavaScript. In contrast WKWebView offers a full-blown configuration (via WKWebViewConfiguration), navigation (via WKNavigationDelegate), estimated loading progress, and evaluating JavaScript.
譯文:相比于iOS2版本推出的UIWebView掰盘,iOS8推出的WKWebView提供了一系列的配置方案(WKWebViewConfiguration/WKNavigationDelegate),預(yù)估加載的進(jìn)度和JavaScript的交互
At a high level passing information from native code to the JavaScript runtime is done by calling the evaluateJavaScript method on a WKWebView object. You can pass a block to capture errors but I’m not exploring that here. Passing information from JavaScript land to the iOS application uses the overly verbose Objective-C-style window.webkit.messageHandlers.NAME.postMessage function where NAME is whatever you call the script handler.
譯文:通過調(diào)用WKWebView的evaluateJavaScript方法來實(shí)現(xiàn)傳遞信息摄悯,達(dá)到原生代碼和JavaScript通訊的效果,你可以通過一個(gè)block來捕獲錯(cuò)誤愧捕,但是我并不會(huì)去關(guān)注那個(gè)部分奢驯,當(dāng)你調(diào)用script handler(處理script操作)你要寫window.webkit.messageHandlers這類冗長(zhǎng)的充滿警告的語句來實(shí)現(xiàn)JavaScript發(fā)送信息到iOS的應(yīng)用
如何創(chuàng)建對(duì)象
WKWebView instance (called webView)
WKWebViewConfiguration instance (called configuration)
WKUserContentController instance (called controller)
The constructor for WKWebView takes a configuration parameter. This allows an instance of WKWebViewConfiguration to be passed and additional settings configured. The important property is userContentController, an instance of WKUserContentController. This controller has a method called addScriptMessageHandler which is how messages from JavaScript land are sent to the native application. This is a big chunk of boilerplate that needs to get setup before the WKWebView can be loaded. Thankfully it’s not all bad.
Oh right, the ViewController needs to match the protocol defined by WKScriptMessageHandler. This means implementing the userContentController delegate method. Onwards to the code examples.
譯文:WKWebView的初始化需要傳入一個(gè)WKWebViewConfiguration參數(shù),因此你需要初始化WKWebViewConfiguration的對(duì)象來設(shè)置配置次绘。比較重要的就是userContentController這個(gè)屬性瘪阁,通過調(diào)用userContentController的addScriptMessageHandler方法來監(jiān)聽JavaScript的調(diào)用,這一步在初始化WKWebView之后就要加上監(jiān)聽 此外對(duì)應(yīng)的控制器需要implement一個(gè)協(xié)議(WKScriptMessageHandler),然后在WKScriptMessageHandler這個(gè)delegate的回調(diào)中處理
實(shí)例代碼
//ViewController.h
#import <WebKit/WebKit.h>
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <WKScriptMessageHandler>
@end
@interface ViewController ()
@property (nonatomic, strong) WKWebView *webView;
@end
#pragma mark - private method
//配置子控件
- (void)configView {
[self.view addSubview:self.webView];
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
// Log out the message received
NSLog(@"Received event %@", message.body);
// Then pull something from the device using the message body
NSString *version = [[UIDevice currentDevice] valueForKey:message.body];
// Execute some JavaScript using the result
NSString *exec_template = @"set_headline(\"received: %@\");";
NSString *exec = [NSString stringWithFormat:exec_template, version];
[_webView evaluateJavaScript:exec completionHandler:nil];
}
#pragma mark - getter
- (WKWebView *)webView {
if(_webView) {
return _webView;
}
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *controller = [[WKUserContentController alloc] init];
configuration.userContentController = controller;
[controller addScriptMessageHandler:self name:@"observe"];
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT-64) configuration:configuration];
_webView.navigationDelegate = self;
_webView.UIDelegate = self;
return _webView;
}
另一種實(shí)例代碼(網(wǎng)上的demo)
<html>
<!--描述網(wǎng)頁信息-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>小黃</title>
<style>
*{
font-size: 50px;
}
.btn{height:80px; width:80%; padding: 0px 30px; background-color: #0071E7; border: solid 1px #0071E7; border-radius:5px; font-size: 1em; color: white}
</style>
<script>
function clear() {
document.getElementById('mobile').innerHTML = ''
document.getElementById('name').innerHTML = ''
document.getElementById('msg').innerHTML = ''
}
//OC調(diào)用JS的方法列表
function alertMobile() {
//這里已經(jīng)調(diào)用過來了 但是搞不明白為什么alert方法沒有響應(yīng)
//alert('我是上面的小黃 手機(jī)號(hào)是:13300001111')
document.getElementById('mobile').innerHTML = '我是上面的小黃 手機(jī)號(hào)是:13300001111'
}
function alertName(msg) {
//alert('你好 ' + msg + ', 我也很高興見到你')
document.getElementById('name').innerHTML = '你好 ' + msg + ', 我也很高興見到你'
}
function alertSendMsg(num,msg) {
//window.alert('這是我的手機(jī)號(hào):' + num + ',' + msg + '!!')
document.getElementById('msg').innerHTML = '這是我的手機(jī)號(hào):' + num + ',' + msg + '!!'
}
//JS響應(yīng)方法列表
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 !!!'])
}
</script>
</head>
<!--網(wǎng)頁具體內(nèi)容-->
<body>
<br/>
<div>
<label>小黃:13300001111</label>
</div>
<br/>
<div id="mobile"></div>
<div>
<button class="btn" type="button" onclick="btnClick1()">小紅的手機(jī)號(hào)</button>
</div>
<br/>
<div id="name"></div>
<div>
<button class="btn" type="button" onclick="btnClick2()">打電話給小紅</button>
</div>
<br/>
<div id="msg"></div>
<div>
<button class="btn" type="button" onclick="btnClick3()">發(fā)短信給小紅</button>
</div>
</body>
</html>
//
// ViewController.m
// OC與JS交互之WKWebView
//
// Created by user on 16/8/18.
// Copyright ? 2016年 rrcc. All rights reserved.
//
#import "ViewController.h"
#import <WebKit/WebKit.h>
@interface ViewController () <WKScriptMessageHandler>
@property (nonatomic, strong) WKWebView *wkWebView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
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];
WKUserContentController *userCC = config.userContentController;
//JS調(diào)用OC 添加處理腳本
[userCC addScriptMessageHandler:self name:@"showMobile"];
[userCC addScriptMessageHandler:self name:@"showName"];
[userCC addScriptMessageHandler:self name:@"showSendMsg"];
}
//網(wǎng)頁加載完成之后調(diào)用JS代碼才會(huì)執(zhí)行邮偎,因?yàn)檫@個(gè)時(shí)候html頁面已經(jīng)注入到webView中并且可以響應(yīng)到對(duì)應(yīng)方法
- (IBAction)buttonClick:(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");
}
}
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
NSLog(@"%@",NSStringFromSelector(_cmd));
NSLog(@"%@",message.body);
if ([message.name isEqualToString:@"showMobile"]) {
[self showMessage:@"我是下面的小紅 手機(jī)號(hào)是:18870707070"];
}
if ([message.name isEqualToString:@"showName"]) {
NSString *info = [NSString stringWithFormat:@"你好 %@, 很高興見到你",message.body];
[self showMessage:info];
}
if ([message.name isEqualToString:@"showSendMsg"]) {
NSArray *array = message.body;
NSString *info = [NSString stringWithFormat:@"這是我的手機(jī)號(hào): %@, %@ !!",array.firstObject,array.lastObject];
[self showMessage:info];
}
}
- (void)showMessage:(NSString *)message {
[[[UIAlertView alloc] initWithTitle:nil message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show];
}
- (IBAction)clear:(id)sender {
[self.wkWebView evaluateJavaScript:@"clear()" completionHandler:nil];
}
@end
總結(jié)
Objective-C 調(diào)用JavaScript
使用方法:evaluateJavaScript: completionHandler:
JavaScript 調(diào)用 Objective-C管跺,app端接收回調(diào)
回調(diào)方法:(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
app端監(jiān)聽使用 addScriptMessageHandler: