Android Web-View : 将本地 Javascript 文件注入远程网页
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21552912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android Web-View : Inject local Javascript file to Remote Webpage
提问by sumit
It has been asked many times before, I browsed through everything, no clear answers yet.
之前被问过很多次,我浏览了所有内容,还没有明确的答案。
Question simplified: Is it possible to inject local Javascript file (from asset or storage) to remote webpage loaded in an Android Web-View? I know that it is possible to inject such files to local Webpages (Assets HTML) loaded in a Web-View.
问题简化:是否可以将本地 Javascript 文件(从资产或存储)注入到 Android Web 视图中加载的远程网页?我知道可以将此类文件注入 Web 视图中加载的本地网页(资产 HTML)。
Why do I need this to work? : To make browsing experience faster, by avoiding downloading of bigger files such as Js and CSS files every time. I want to avoid Web-View Caching.
为什么我需要这个来工作?:为了让浏览体验更快,避免每次下载较大的文件,如 Js 和 CSS 文件。我想避免 Web 视图缓存。
回答by Raffaele N.
There is a way to 'force' the injection of your local Javascript files from local assets (e.g., assets/js/script.js), and to circumvent the 'Not allowed to load local resource : file:///android_assets/js/script.js ...' issue.
有一种方法可以“强制”从本地资产(例如,assets/js/script.js)注入本地 Javascript 文件,并绕过“不允许加载本地资源”:file:///android_assets/js /script.js ...' 问题。
It is similar to what described in another thread (Android webview, loading javascript file in assets folder), with additional BASE64 encoding/decoding for representing your Javascript file as a printable string.
它类似于另一个线程(Android webview,在 assets 文件夹中加载 javascript 文件)中描述的内容,具有额外的 BASE64 编码/解码用于将您的 Javascript 文件表示为可打印字符串。
I am using an Android 4.4.2, API level 19 Virtual Device.
我使用的是 Android 4.4.2、API 级别 19 虚拟设备。
Here are some code snippets:
下面是一些代码片段:
[assets/js/script.js]:
[资产/js/script.js]:
'use strict';
function test() {
// ... do something
}
// more Javascript
[MainActivity.java]:
[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");
...
回答by cyberflohr
Yes, you could use shouldInterceptRequest() to intercept remote url loading and return local stored content.
是的,您可以使用 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);
}
}
});
回答by rinkesh
loadUrl will work only in old version use evaluateJavascript
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"}
}
});
回答by rogerdpack
Be careful using evaluateJavascript
: if there is a syntax error or exception thrown in your javascript it will call your onReceiveValue
with a null. The most common way to support both SDK 19 as well as lower seems to be like this:Fill form in WebView with Javascript
小心使用evaluateJavascript
:如果在您的 javascript 中抛出语法错误或异常,它将onReceiveValue
使用 null调用您的。支持 SDK 19 和更低版本的最常见方法似乎是这样的:使用 Javascript 在 WebView 中填写表单
Also if you get terribly desperate for some kind of browser functionality (in my case, never could figure out how to get DRM to work well) you could use a bookmarklet within normal chrome, which works only if you type the bookmark name into the omnibox but does work and does inject javascript.
此外,如果您非常渴望某种浏览器功能(在我的情况下,永远无法弄清楚如何让 DRM 正常工作),您可以在普通 chrome 中使用书签,只有当您在多功能框中输入书签名称时才有效但确实有效并且确实注入了javascript。
Also be aware that with the default WebView
you can't use javascript alerts to test anything, they don't show. Also be aware that "video" by default (like html <video> tags) doesn't "really work" by default and also DRM video doesn't work by default, they're all configure options :\
另请注意,默认情况下WebView
您不能使用 javascript 警报来测试任何内容,它们不会显示。另请注意,默认情况下“视频”(如 html <video> 标签)在默认情况下并不“真正有效”,而且 DRM 视频在默认情况下也无效,它们都是配置选项:\