手机APP的开发越来越敏捷,很多地方如果可以用webView的形式代替原生开发,成为了不少团队的技术选择。webView虽然灵活,但是在操作体验和用户交互上还存在不少的缺陷。但因为webView应用的场景越来越多,原生WebView与JS的交互变得非常重要。本文主要记录了WebView与JS交互的几种主要方式,并且补充了自己使用过程中踩过的坑和心得。
方式1: WebViewJavascriptBridge
Issues
- WKWebViewJavascriptBridge 在Xcode9上导致crash的解决方法:
- 官方给出的issue
- 解决方式一:1234567891011121314151617181920212223- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {if (webView != _webView) { return; }NSURL *url = navigationAction.request.URL;__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;if ([_base isWebViewJavascriptBridgeURL:url]) {if ([_base isBridgeLoadedURL:url]) {[_base injectJavascriptFile];} else if ([_base isQueueMessageURL:url]) {[self WKFlushMessageQueue];} else {[_base logUnkownMessage:url];}decisionHandler(WKNavigationActionPolicyCancel);} else {/// 在这新添加了elseif (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {[_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];} else {decisionHandler(WKNavigationActionPolicyAllow);}}}
- 解决方式二:123456789101112131415161718192021222324- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {if (webView != _webView) { return; }NSURL *url = navigationAction.request.URL;__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;if ([_base isWebViewJavascriptBridgeURL:url]) {if ([_base isBridgeLoadedURL:url]) {[_base injectJavascriptFile];} else if ([_base isQueueMessageURL:url]) {[self WKFlushMessageQueue];} else {[_base logUnkownMessage:url];}decisionHandler(WKNavigationActionPolicyCancel);/// 在这新添加了returnreturn;}if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) {[_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];} else {decisionHandler(WKNavigationActionPolicyAllow);}}
方式2: JavascriptCore
前情提要
JavaScriptCore 是 Objective-C 的API,作用于链接JS语言和OC语言。通过较少的代码,开发者可以从OC运行JS或者从JS调用OC。
JavaScriptCore具有如下优势:
- 让你能够在UIWebView之外使用JS,运行简单的JS脚本无需依赖于web view.
- 可以使用现代OC的特性比如blocks和collection subscripting.
- 可以很方便的在两种语言之间进行值传递或者对象传递。
- 可以创建混合对象:OC的对象能够拥有JS的值甚至函数作为属性。(比如一个原生的按钮在点击的时候触发JS的函数)
合适的使用场景:
- 用在业务和原型经常会变化的地方。例如游戏。
- 用在不同的团队协作开发的时候。比如iOS程序员和前端程序员共同做一个项目。
- 用在需要能立刻看到变化的地方。JS语言是解释型的,所以更改JS代码我们可以看到app的实时变化。
原则上苹果不允许使用的场景:
- 从远程服务器下载并运行JS代码。(即使是开发者自己的服务器用内购的方式也不行)
- 用户在app内编写JS代码并运行。
JavaScriptCore 概览
主要的类和协议
- JSValue: 用来代表JS实体的OC对象。
- JSManagedValue: 本质上还是JSValue对象,但是引入了内存管理的特性用来协调OC的引用计数和JS的GC。
- JSContext:代表JS运行环境的对象。所有的JSValue对象都要依赖于JSContext。
- JSExport:协议。可以用这个协议把原生对象转化成JS对象,把原生的属性和方法转化成JS的属性和方法。
- JSVirtualMachine: 代表对象空间,拥有自己的heap和garbage collector.