之前被问过很多次,我浏览了所有内容,还没有明确的答案。
问题简化:是否可以将本地 Javascript 文件(来自资产或存储)注入到 Android Web 视图中加载的远程网页?我知道可以将此类文件注入 Web 视图中加载的本地网页(资产 HTML)。
为什么我需要这个来工作?:为了让浏览体验更快,避免每次下载较大的文件,如 Js 和 CSS 文件。我想避免 Web 视图缓存。
之前被问过很多次,我浏览了所有内容,还没有明确的答案。
问题简化:是否可以将本地 Javascript 文件(来自资产或存储)注入到 Android Web 视图中加载的远程网页?我知道可以将此类文件注入 Web 视图中加载的本地网页(资产 HTML)。
为什么我需要这个来工作?:为了让浏览体验更快,避免每次下载较大的文件,如 Js 和 CSS 文件。我想避免 Web 视图缓存。
有一种方法可以“强制”从本地资产(例如,assets/js/script.js)注入本地 Javascript 文件,并绕过“不允许加载本地资源”:file:///android_assets/js /script.js ...' 问题。
它类似于另一个线程(Android webview,在 assets 文件夹中加载 javascript 文件)中描述的内容,具有额外的 BASE64 编码/解码用于将您的 Javascript 文件表示为可打印字符串。
我使用的是 Android 4.4.2、API 级别 19 虚拟设备。
下面是一些代码片段:
[资产/js/script.js]:
'use strict';
function test() {
// ... do something
}
// more Javascript
[主活动.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");
...
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"}
}
});
是的,您可以使用 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);
}
}
});
小心使用evaluateJavascript
:如果在您的 javascript 中抛出语法错误或异常,它将onReceiveValue
使用 null调用您的。支持 SDK 19 和更低版本的最常见方法似乎是这样的:使用 Javascript 在 WebView 中填写表单
此外,如果您非常渴望某种浏览器功能(在我的情况下,永远无法弄清楚如何让 DRM 正常工作),您可以在普通 chrome 中使用书签,只有在您在多功能框中输入书签名称时才有效但确实有效并且确实注入了javascript。
另请注意,默认情况下WebView
您不能使用 javascript 警报来测试任何内容,它们不会显示。另请注意,默认情况下的“视频”(如 html <video> 标签)在默认情况下并不“真正有效”,而且 DRM 视频在默认情况下也无效,它们都是配置选项:\