iOS交互Javascript


2016/8/15 iOS

为了解决 UIWebView 加载速度慢、占用内存大的问题,苹果在 iOS8.0 之后推出了 WKWebView 以替代之,在使用 WKWebView 前先引入 <WebKit/WebKit.h> 框架。

WKWebView 属性

WKWebView 在原有基础上额外添加了几个属性如下:

// 浏览器配置;
@property (nonatomic, readonly, copy) WKWebViewConfiguration *configuration;
// 历史访问列表;
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
// 网页加载进度;
@property (nonatomic, readonly) double estimatedProgress;
1
2
3
4
5
6

WKWebView 代理

WKWebView 可以同时设置 WKNavigationDelegate 和 WKUIDelegate 两个代理,代理方法也有所改变如下:

#pragma mark - WKNavigationDelegate
// 在发送请求前的操作;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {}
// 在收到响应后的操作;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {}
// 在页面重指向时的操作;
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {}
// 页面准备加载;
- (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 withError:(NSError *)error {}
// 页面跳转失败;
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {}

#pragma mark - WKUIDelegate
// 创建新的WebView;
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {}
// 拦截警告框
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {}
// 拦截确认框
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {}
// 拦截提示框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

此外 WKWebView 新增了根据文件加载 WebView 的方法:

- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL NS_AVAILABLE(10_11, 9_0);
1

WebViewJavascriptBridge 实现交互

在项目中使用 WebViewJavascriptBridge 先添加 OC 代码如下:

WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.view.bounds];
webView.navigationDelegate = self;
[self.view addSubview:webView];
// 设置允许桥接
[WKWebViewJavascriptBridge enableLogging];
// 初始化桥接对象并设置代理
_bridge = [WKWebViewJavascriptBridge bridgeForWebView:webView];
[_bridge setWebViewDelegate:self];
// 注册函数testObjcCallback引用JS
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
    NSLog(@"testObjcCallback called: %@", data);
    responseCallback(@"Response from testObjcCallback");
}];
// 回调函数testJavascriptHandler供JS引用
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];

[self renderButtons:webView];
[self loadExamplePage:webView];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

然后在 HTML 文件中添加 js 代码如下:

function setupWebViewJavascriptBridge(callback) {
  if (window.WebViewJavascriptBridge) {
    return callback(WebViewJavascriptBridge)
  }
  if (window.WVJBCallbacks) {
    return window.WVJBCallbacks.push(callback)
  }
  window.WVJBCallbacks = [callback]
  var WVJBIframe = document.createElement('iframe')
  WVJBIframe.style.display = 'none'
  WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
  document.documentElement.appendChild(WVJBIframe)
  setTimeout(function() {
    document.documentElement.removeChild(WVJBIframe)
  }, 0)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

OC 引用 JS

OC 中注册函数:

[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
    NSLog(@"testObjcCallback called: %@", data);
    responseCallback(@"Response from testObjcCallback");
}];
1
2
3
4

JS 中实现回调函数:

setupWebViewJavascriptBridge(function(bridge) {
  bridge.callHandler('testObjcCallback', { foo: 'bar' }, function(response) {
    // 该函数为js中声明的函数;
    log('JS got response', response)
  })
})
1
2
3
4
5
6

JS 引用 OC

JS 中注册函数:

bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
  log('ObjC called testJavascriptHandler with', data)
  var responseData = { 'Javascript Says': 'Right back atcha!' }
  log('JS responding with', responseData)
  responseCallback(responseData)
})
1
2
3
4
5
6

OC 中实现回调并传值:

[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
1

以上就是 WebViewJavascriptBridge 与 WKWebView 的基本交互使用。

上次更新: 10/24/2019, 12:39:39 AM