目前在写一个半 web 半 native app。业务实现里网页带的 App.js 会在某些事件触发(比如点击元素跳转页面)时执行 window.jsInterface 这个 object 的某些 function,要求 iOS 监听 function 的触发并作出响应(比如 push 一个 ViewController)。
问题是网页本身没有 window.jsInterface,而且 WKWebView 里只能监听 window.webkit.messageHandlers 的事件,所以还需要注入一个 js Object 来转发这些事件。

具体实现写在了 WKWebView 的一个 subclass 里。
@interface YHWebView ()<WKScriptMessageHandler>
实现 WKScriptMessageHandler 协议,只有这么一个函数:
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
用此实现来监听 window.webkit.messageHandlers。
在此基础上需要使用 WKWebViewConfiguration 来自定义接口(比如 jumpToNative )。
- (id)initWithFrame:(CGRect)frame
{
self.webViewConfig = [[WKWebViewConfiguration alloc] init];
self.webViewConfig.userContentController = [[WKUserContentController alloc] init];
[self.webViewConfig.userContentController addScriptMessageHandler:self name:@"jumpToNative"];
self = [super initWithFrame:frame configuration:self.webViewConfig];
#if DEBUG
// 开启 Safari Debug
[self.webViewConfig.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
#endif
return self;
}
这个时候如果 js 调用
window.webkit.messageHandlers.jumpToNative.postMessage()
``` 就可以在 `WKScriptMessageHandler` 的实现里面收到了,比如 js 发送:
window.webkit.messageHandlers.jumpToNative.postMessage({body: dict}); //dict 为一个 JSON String
则代理实现里可以读取:
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([message.name isEqualToString:@"jumpToNative"])
{
NSString *body = [message.body objectForKey:@"body"];
NSData *bodyData = [body dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:bodyData options:0 error:&error];
// 处理 body 内的 key value
}
}
---
现在就差最后一步,注入 js 对象,把所有关于 `window.jsInterface` 的东西都发给 `window.webkit.messageHandlers`。使用 WKUserScript 可以在页面加载前注入这么一个对象:
NSString *jsCode = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"YHWebView" ofType: @"js"] encoding:NSUTF8StringEncoding error:NULL];
self.jsInterfaceUserScript = [[WKUserScript alloc] initWithSource:jsCode injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[self.webViewConfig.userContentController addUserScript:self.jsInterfaceUserScript];
YHWebView.js:
```js
window.jsInterface =
{
jumpToNative: function(dict)
{
window.webkit.messageHandlers.jumpToNative.postMessage({body: dict});
}
};
Done.








