Android Web-View:将本地Javascript文件注入到远程网页

之前已经问过很多次了,我浏览过所有东西,还没有明确的答案。

问题简化:是否可以注入本地JavaScript文件(从资产或存储)到Android Web-View加载的远程网页? 我知道可以将这样的文件注入到Web视图中加载的本地网页(Assets HTML)中。

为什么我需要这个工作? :通过避免每次下载较大的文件(如Js和CSS文件)来加快浏览体验。 我想避免Web-Viewcaching。

有一种方法可以从本地资源(例如assets / js / script.js)强制注入本地Javascript文件,并绕过“不允许加载本地资源:file:/// android_assets / js /script.js …“问题。

它类似于另一个线程( Android webview,在assets文件夹中加载javascript文件 )中描述的内容,以及用于将您的Javascript文件表示为可打印string的附加BASE64编码/解码。

我正在使用Android 4.4.2,API级别19的虚拟设备。

以下是一些代码片段:

[资产/ JS /的script.js]:

'use strict'; function test() { // ... do something } // more Javascript 

[MainActivity.java]:

  ... WebView myWebView = (WebView) findViewById(R.id.webView); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setAllowUniversalAccessFromFileURLs(true); myWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return false; } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); injectScriptFile(view, "js/script.js"); // see below ... // test if the script was loaded view.loadUrl("javascript:setTimeout(test(), 500)"); } private void injectScriptFile(WebView view, String scriptFile) { InputStream input; try { input = getAssets().open(scriptFile); byte[] buffer = new byte[input.available()]; input.read(buffer); input.close(); // String-ify the script byte-array using BASE64 encoding !!! String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP); view.loadUrl("javascript:(function() {" + "var parent = document.getElementsByTagName('head').item(0);" + "var script = document.createElement('script');" + "script.type = 'text/javascript';" + // Tell the browser to BASE64-decode the string into your script !!! "script.innerHTML = window.atob('" + encoded + "');" + "parent.appendChild(script)" + "})()"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); myWebView.loadUrl("http://www.example.com"); ... 

是的,您可以使用shouldInterceptRequest()拦截远程URL加载并返回本地存储的内容。

 WebView webview = (WebView) findViewById(R.id.webview); webview.setWebViewClient(new WebViewClient() { @Override public WebResourceResponse shouldInterceptRequest (final WebView view, String url) { if (url.equals("script_url_to_load_local")) { return new WebResourceResponse("text/javascript", "UTF-8", new FileInputStream("local_url"))); } else { return super.shouldInterceptRequest(view, url); } } }); 

loadUrl只能在旧版本中使用evaluateJavascript

 webview.evaluateJavascript("(function() { document.getElementsByName('username')[0].value='USERNAME';document.getElementsByName('password')[0].value='PASSWORD'; "+ "return { var1: \"variable1\", var2: \"variable2\" }; })();", new ValueCallback<String>() { @Override public void onReceiveValue(String s) { Log.d("LogName", s); // Prints: {"var1":"variable1","var2":"variable2"} } }); 

请小心使用evaluateJavascript :如果在JavaScript中引发了语法错误或exception,则会使用null调用onReceiveValue 。 支持SDK 19以及更低版本的最常见的方式似乎是这样的: 用JavaScript在WebView中填写表单

另外,如果你对某种浏览器function感到非常绝望(在我的情况下,永远不可能弄清楚如何让DRM正常工作),你可以在正常的chrome中使用小书签,只有当你在多function框中input书签名但确实工作,并注入JavaScript。

另外请注意,使用默认的WebView您不能使用JavaScript警报来testing任何东西,它们不会显示。 另外请注意默认的“video”(如html <video>标签)在默认情况下并不“真正起作用”,默认情况下DRMvideo也不起作用,它们都是configuration选项:\