移动开发已经进入大前端时代。对于混编技术,目前业界流行的方案是H5、React Native、Weex、Flutter。
相对于rn、weex、flutter等混编技术,在App里面内嵌H5实现成本较低,所以目前市面上H5混编仍是主流。
伪协议指的是自己自定义的url协议,通过webview的代理拦截到url的加载,识别出伪协议,然后调用native的方法。伪协议可以这样定义:AKJS:// functionName? param1=value1¶m2=value2。 其中AKJS代表我们自己定义的协议,functionName代表要调用的App方法,?后面代表传入的参数。 1、UIWebView通过UIWebViewDelegate的代理方法-webView: shouldStartLoadWithRequest:navigationType:进行伪协议拦截。 2、WKWebView通过WKNavigationDelegate代理方法实现- webView:decidePolicyForNavigationAction:decisionHandler:进行伪协议拦截。 3、优缺点 优点:实现简单。 缺点:
- 由于url长度大小有限制,导致传参大小有限制,比如h5如果要传一个图片的base64字符串过来,这种方式就无能为力了。
- 需要在代理拦截方法里面写一系列if else处理,难以维护。
- 如果App要兼容UIWebView和WKWebView,需要有两套实现,难以维护。
为了解决伪协议实现的缺点,我们可以往webview里面注入OC对象,不过这种方案只能用于UIWebView中。此种方式的实现步骤如下: 1、在webViewDidFinishLoad方法中通过JSContext注入JS对象
self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext[@"AK_JSBridge"] = self.bridgeAdapter; //往JS中注入OC对象
2、OC对象实现JSExport协议,这样JS就可以调用OC对象的方法了
@interface AKBridgeAdapter : NSOject< JSExport >
- (void)getUID; // 获取用户ID
此种方案的优点是:实现简单、通过暴露类给js实现js调用原生,简洁清晰。缺点是:只能用在UIWebView。
WKWebView可以通过提供实现了WKScriptMessageHandler协议的类来实现JS调用OC,实现步骤如下: 1、往webview注入OC对象。
[self.configuration.userContentController addScriptMessageHandler:self.adapter name:@"AK_JSBridge"]
2、实现- userContentController:didReceiveScriptMessage:获取方法调用名和参数
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.body isKindOfClass:[NSDictionary class]]) {
NSDictionary *dicMessage = message.body;
NSString *funcName = [dicMessage stringForKey:@"funcName"];
NSString *parameter = [dicMessage stringForKey:@"parameter"];
//进行逻辑处理
}
}
此种方案的优点是:实现简单,缺点是:不支持UIWebView。
WKWebViewJavascriptBridge是iOS使用最广泛的JSBridge库,该库通过伪协议+JS消息队列实现了JS与OC交互,此种方案兼容UIWebView和WKWebView。
- 通过黑名单url,防止黑名单url加载。
- 通过白名单url,只允许白名单url加载。
- 对于自己公司的白名单url,允许访问所有JSBridge方法。
- 对于第三方白名单url,不允许访问JSBridge任何方法。
- 对于黑名单url,不允许访问JSBridge任何方法。
通过httpdns方式防止url劫持。
HTTPS可以防止页面被劫持或者注入,然而其副作用也是明显的,网络传输的性能和成功率都会下降,而且HTTPS的页面会要求页面内所有引用的资源也是HTTPS的,对于大型网站其迁移成本并不算低。
页面post请求走原生的网络请求。
webview加载页面过程
初始化 webview -> 请求页面 -> 下载数据 -> 解析HTML -> 请求 js/css 资源 -> dom 渲染 -> 解析 JS 执行 -> JS 请求数据 -> 解析渲染 -> 下载渲染图片
可以在App启动的时候创建全局webview池,webview的大小建议3个以内。后续的webview都重用这些webview。
DNS会在系统级别进行缓存,对于WebView的地址,如果使用的域名与native的API相同,则可以直接使用缓存的DNS而不用再发起请求。
- 在客户端初始化WebView的同时,直接由native开始网络请求数据;
- 当页面初始化完成后,向native获取其代理请求的数据。
同步渲染时如果后端请求时间过长,可以考虑采用chunk编码,将数据放在最后,并优先将静态内容flush。
对于电商app,大促之前先提前下载好资源包,等大促入口放开了,就可以直接加载本地资源。 或者直接预加载一个公共h5,把这个公共h5的公共资源缓存下来,下次打开别的页面就能直接使用这些公共资源了。
可以拦截图片、js等资源的下载,使用本地缓存。
前端开发同学可以从h5布局,js打包、解析、执行等角度进行优化。
React Native是facebook开发的用于统一h5、iOS、Android三端的开源库。其基本原理是通过JSCore实现JS与原生的调用,它的渲染引擎最终会路由到原生的控件上面。目前在业界使用广泛。
Weex是阿里开发的用于统一h5、iOS、Android三端的开源库。其基本原理是通过JSCore实现JS与原生的调用,它的渲染引擎最终会路由到原生的控件上面。业内用得相对少点。
Flutter是google开发的用于统一iOS、Android两端的开源库(不能用在h5)。其基本原理是通过自己的skia渲染引擎实现iOS和Android控件的统一。目前业界使用的越来越多。
- 如果是小公司,建议只使用h5混编,引入其他的混编技术,学习成本高、维护成本高,招人也比较难。
- 如果是中大型公司。一般都会选用h5、rn、flutter混编。如果要统一三端,那就rn。如果只想统一iOS和Android,flutter是个不错的选择。
参考资料: 外卖客户端容器化架构的演进 WebView性能、体验分析与优化 iOS app秒开H5优化探索
如果你正在跳槽或者正准备跳槽不妨动动小手,添加一下咱们的交流群931542608来获取一份详细的大厂面试资料为你的跳槽多添一份保障。