基于cordova实现的webview实现与h5的交互

该片文章讲述项目中遇到的问题,以及相关优化细节。

一、项目背景

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优化。这里就不描述了。


你可能感兴趣的:(android笔记)