UIWebView/WKWebView 拦截请求
- Native 调用 JS
1 | [webView stringByEvaluatingJavaScriptFromString:@"Math.random();"]; |
- JS 调用 Native
Native 拦截 UIWebView 的所有请求,判断 Scheme,如果是约定好的 Schema 就拦截请求、解析参数并调用 Native 相应的逻辑
JS 发起请求有两种方式:1. 通过 localtion.href;2. 通过 iframe 方式
前者如果短时间内连续多次修改 localtion.href 的值,Native 只会收到最后一次请求,因此 JS 侧采用 iframe 的方式发起请求
1 | var url = 'jsbridge://doAction?title=标题'; |
1 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType |
- 优点:不需要等到整个 HTML 页面加载完成就能调用 Native?
- 缺点:需要繁琐地解释字符串得到相应的方法名和传值,且调用的方法也不能传递返回值;
UIWebView 获取 JSContext
在 webViewDidFinishLoad 通过 KVC 的方法获取 JSContext
1 | - (void)webViewDidFinishLoad:(UIWebView *)webView |
JSContext 属于 JSCore,见下节
- 优点:需要等到整个 HTML 页面加载完成才能调用 JS?
- 缺点:WKWebView 无法使用 JSCore
WKWebView 使用 userContentController
WKWebView 无法使用 JSCore
- Native 调用 JS
1 | @property (nonatomic, strong) WKUserContentController *userContentController; |
Native 和 H5 交互基本全靠这个对象, 在 WKWebVeiw 中,我们使用我们有两种方式来调用 JS,
- 使用 WKUserScript
- 直接调用 JS 字符串
1.1 使用 WKUserScript
1 | // source 就是我们要调用的 JS 函数或者我们要执行的 JS 代码 |
至此,我们已经构建了一个 WKUserScript,然后呢,我们要做的就是要把它添加进来
1 | - addUserScript: |
至此使用 WKUserScript 调用 JS 完成
1.2 直接调用 JS 字符串
在 WKWebView 中,我们也可以直接执行 JS 字符串
1 | - (void)evaluateJavaScript:completionHandler: |
我们通过调用这个方法来执行 JS 字符串,然后在 completionHandler 中拿到执行这段 JS 代码后的返回值。
至此,Native 调用 JS 完成
- JS 调用 Native
2.1 向 JS 注入一个字符串
1 | [_webView.configuration.userContentController addScriptMessageHandler:self name:@"nativeMethod"]; |
我们向 JS 注入了一个方法,叫做 nativeMethod
2.2 JS 调用 Native
1 | window.webkit.messageHandlers.nativeMethod.postMessage(value); |
一句话调用,我们就可以在 Native 中接收到 value
2.3 接收 JS 调用
上边我们调用 addScriptMessageHandler:name 的时候,我们要遵守 WKScriptMessageHandler 协议,然后实现这个协议。
1 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message |
完了,Native 调用 JS 就这么简单
优点:简单易用
缺点:JS 调用 Native 后回调较难,见 https://juejin.im/entry/59f6e836f265da431a427a57
JSCore
- Native 调用 JS
1 | JSContext *context = [[JSContext alloc] init]; |
- JS 调用 Native
借助 JSCore,我们并不一定要写 JS,可以直接使用 JSCore 模拟 JS 调用
1 | JSContext *context = [[JSContext alloc] init]; |
Native 注入函数到 JS
1 | JSContext *context = [[JSContext alloc] init]; |
Native 实现 JSExport
1 | @protocol QLJSProtocol <JSExport> |
JS 调用 Native,可以使用 JSCore 模拟,也可以在 JS 侧调用(需要把 JS 文件注入到 JSContext)
1 | JSContext *context = [[JSContext alloc] init]; |
or
1 | function f() |
- 优点:不依赖 WebView