cordova工程webview注入本地js库的方法

一、目标与思路:
在使用cordova(webview)的Android工程里,需要加载远程的h5页面,为了减少流量的消耗,同时也为了提高h5的加载速度,
我们可以把h5页面用到的js库,通过本地注入,替代从网络上加载。
二、实现原理:
在loadurl("http://xxx");之后,在onPageFinished消息收到后,进行js注入。注入的方法参考了一个cordova插件的实现:
https://github.com/TruckMovers/cordova-plugin-remote-injection
从源码,可以获取到注入方法。
三、实现步骤(需要添加的代码)
我测试使用的环境:加入了cordova(webview)的Android工程(参见cordoava创建工程,并添加平台之后的到的工程),

也可以参考我的另一篇文章:

http://blog.csdn.net/robert_cysy/article/details/77072961

四、实现代码只有以下部分:h5页面不提供

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Base64;
import android.util.Log;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Toast;

import org.apache.cordova.CordovaActivity;
import org.apache.cordova.CordovaWebViewEngine;
import org.apache.cordova.engine.SystemWebChromeClient;
import org.apache.cordova.engine.SystemWebViewEngine;

public class MainActivity extends CordovaActivity {
    private WebView mWebView;
    private CordovaWebViewEngine mEngine;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WebView.setWebContentsDebuggingEnabled(true);
        }

        loadUrl("file:///android_asset/index.html");//这里可以是远程地址
        mWebView = (WebView)appView.getView();
        mEngine = appView.getEngine();
    }

    @Override
    public Object onMessage(String id, Object data) {

        if (id.equals("onPageFinished")) {
            if (data instanceof String) {
                String url = (String) data;
                if (isRemote(url)) {
                    injectCordova();  //在js里没有注入。在这里注入
                }
            } else {
                onMessageTypeFailure(id, data);
            }
        } 

        return null;
    }

    private final ArrayList<String> preInjectionFileNames = new ArrayList<String>();
    // preInjectionFileNames.add("www/init.js");在这里添加其他自定义的js库
    // preInjectionFileNames.add("www/init2.js");
    //以下函数为参考cordova-plugin-remote-injection里的代码

    /**
     * 使用范围:app应用本来有了cordova使用环境,只是加载的url的页面里面没有调用js,但是使用的时候
     * 需要这些js,就用这个函数来插入js文件
     * 目录从assets之后开始写起
     */
    private void injectCordova() {
        List<String> jsPaths = new ArrayList<String>();
        for (String path: preInjectionFileNames) {
            jsPaths.add(path);
        }

        jsPaths.add("js/cordova/cordova.js");

        // We load the plugin code manually rather than allow cordova to load them (via
        // cordova_plugins.js).  The reason for this is the WebView will attempt to load the
        // file in the origin of the page (e.g. https://truckmover.com/plugins/plugin/plugin.js).
        // By loading them first cordova will skip its loading process altogether.
        jsPaths.addAll(jsPathsToInject(getResources().getAssets(), "js/cordova/plugins"));

        // Initialize the cordova plugin registry.
        jsPaths.add("js/cordova/cordova_plugins.js");

        // The way that I figured out to inject for android is to inject it as a script
        // tag with the full JS encoded as a data URI
        // (https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs).  The script tag
        // is appended to the DOM and executed via a javascript URL (e.g. javascript:doJsStuff()).
        StringBuilder jsToInject = new StringBuilder();
        for (String path: jsPaths) {
            jsToInject.append(readFile(getResources().getAssets(), path));
        }
        String jsUrl = "javascript:var script = document.createElement('script');";
        jsUrl += "script.src=\"data:text/javascript;charset=utf-8;base64,";

        jsUrl += Base64.encodeToString(jsToInject.toString().getBytes(), Base64.NO_WRAP);
        jsUrl += "\";";

        jsUrl += "document.getElementsByTagName('head')[0].appendChild(script);";

        //webView.getEngine().loadUrl(jsUrl, false);
        mEngine.loadUrl(jsUrl, false);//false参数表示,不重启plugin,用于加载js库文件
    }

    private String readFile(AssetManager assets, String filePath) {
        StringBuilder out = new StringBuilder();
        BufferedReader in = null;
        try {
            InputStream stream = assets.open(filePath);
            in = new BufferedReader(new InputStreamReader(stream));
            String str = "";

            while ((str = in.readLine()) != null) {
                out.append(str);
                out.append("\n");
            }
        } catch (MalformedURLException e) {
        } catch (IOException e) {
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return out.toString();
    }

    /**
     * Searches the provided path for javascript files recursively.
     *
     * @param assets
     * @param path start path
     * @return found JS files
     */
    private List<String> jsPathsToInject(AssetManager assets, String path){
        List jsPaths = new ArrayList<String>();

        try {
            for (String filePath: assets.list(path)) {
                String fullPath = path + File.separator + filePath;

                if (fullPath.endsWith(".js")) {
                    jsPaths.add(fullPath);
                } else {
                    List<String> childPaths = jsPathsToInject(assets, fullPath);
                    if (!childPaths.isEmpty()) {
                        jsPaths.addAll(childPaths);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsPaths;
    }
}


猜你喜欢

转载自blog.csdn.net/robert_cysy/article/details/77453803
今日推荐