一、目标与思路:
在使用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创建工程,并添加平台之后的到的工程),
在使用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; } }