基于cordova实现的webview实现与h5的交互
该片文章讲述项目中遇到的问题,以及相关优化细节。一、项目背景1、项目需要支持hybrid应用,所以部分提供h5调用的通用js保存在客户端本地。优点有:访问速度快和无需额外数据流量。2、项目主页都是h5形式,采用vue框架,支持离线缓存3、使用CordovaWebView加载h5应用。二、问题清单和优化1、h5应用如何读到本地js文件?针对第1个问题,很简单解决。webv
该片文章讲述项目中遇到的问题,以及相关优化细节。
一、项目背景
1、项目需要支持hybrid应用,所以部分提供h5调用的通用js保存在客户端本地。优点有:访问速度快和无需额外数据流量。
2、项目主页都是h5形式,采用vue框架,支持离线缓存
3、使用CordovaWebView加载h5应用。
二、问题清单和优化
1、h5应用如何读到本地js文件?
针对第1个问题,很简单解决。webview提供拦截方法,只要和js端定义好import的格式,匹配好即可。代码编写如下:
拦截方法入口,系统版本不一致,调用方法不一样,请知晓。
/** * URL拦截请求方法(API21以上) * @param webView * @param webResourceRequest 请求信息 * @return */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest) { //21版本 //通过版本控制来将2个入口引入到一个拦截方法中 String method = webResourceRequest != null ? webResourceRequest.getMethod() : null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //OPTIONS请求跳过 if (method != null && method.equalsIgnoreCase("OPTIONS")) { return null; } return customInterceptRequest(webView, webResourceRequest.getUrl().toString(), method, webResourceRequest.getRequestHeaders(), super.shouldInterceptRequest(webView, webResourceRequest)); } return super.shouldInterceptRequest(webView, webResourceRequest); } /** * URL拦截请求方法(API21以下) * @param view * @param url 请求地址 * @return */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { //11版本 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { return customInterceptRequest(view, url, null, null, super.shouldInterceptRequest(view, url)); } return super.shouldInterceptRequest(view, url); }
匹配url,重新写回WebResourceResponse
/** * 加载本地js文件 * @param url * @param injection * @return */ private WebResourceResponse handleInjectUrl(String url,String injection){ try{ String assetPath = url.substring(url.indexOf(injection) + injection.length(), url.length()); String cordovaPath = JS_PATH + assetPath; InputStream fis = new FileInputStream(new File(cordovaPath)); return new WebResourceResponse( "application/javascript", "UTF-8", fis ); }catch (Exception e){ if (ModuleCommImpl.getInstance().isDebug()) { LOG.e(TAG, "handleInjectUrl loading file fail.", e); } } return new WebResourceResponse("application/javascript", "UTF-8", null); }
此处有个优化点,非常耗时,第三点会解释,请继续阅读。
2、无网情况下如何继续访问数据?
首先h5应用需要支持离线缓存,使用localstorage把网络数据暂存起来。Android端需要把缓存开关打开。如图:
// Enable database // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16 String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath(); settings.setDatabaseEnabled(true); settings.setDatabasePath(databasePath); // Enable AppCache // Fix for CB-2282 settings.setCacheMode(WebSettings.LOAD_DEFAULT); // 默认使用缓存 settings.setAppCacheMaxSize(20 * 1048576); settings.setAppCachePath(databasePath); // 可以读取文件缓存(manifest生效) settings.setAllowFileAccess(true); settings.setAppCacheEnabled(true);
网上资料很多,查下即可。
3、加载首页数据缓慢?
h5应用往往遇到加载慢,体验不好的问题。在我们做了离线缓存时,稍微好点。但是此项目中遇到一个问题就是加载数据慢。
排查思路:
a、检查首页webview对象初始化时间
期初怀疑是对象初始化耗时,经打印时间,发现不是。
b、检查onPageStarted 和onPageFinished时间。
如果此处耗时比较大,就存在问题,当初我们这边耗时800ms,后来发现拦截代码,获取路径函数
public static File getCacheDirectory(Context context, boolean preferExternal, boolean persist) { File appCacheDir = null; String externalStorageState; try { externalStorageState = Environment.getExternalStorageState(); } catch (NullPointerException e) { // (sh)it happens (Issue #660) externalStorageState = ""; }
该方法调用时间10ms,单次调用没什么问题。
对于我们加载本地js,比如本地60个js,针对浏览器,并行加载6个js,也就是加载所有的js需要总的时间:600ms,太费时了。
所以我们把路径写出
private static final String JS_PATH = ModuleCommImpl.getInstance().getFileJsPath()+"/plugin.apis/";
时间立马下降了。
此处一个优化点。后续开发者在做拦截时,需要考虑下。
c、页面没有渲染好的问题,需要h5优化。这里就不描述了。
更多推荐
所有评论(0)