简体   繁体   English

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

[英]Android Web-View : Inject local Javascript file to Remote Webpage

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? 问题简化:是否可以将本地Javascript文件(从资产或存储)注入Android Web视图中加载的远程网页? I know that it is possible to inject such files to local Webpages (Assets HTML) loaded in a Web-View. 我知道可以将这些文件注入Web-View中加载的本地Web页面(Assets 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. :通过避免每次都下载较大的文件(如Js和CSS文件)来提高浏览体验。 I want to avoid Web-View Caching. 我想避免Web-View缓存。

There is a way to 'force' the injection of your local Javascript files from local assets (eg, 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文件 )中描述的内容,以及用于将Javascript文件表示为可打印字符串的附加BASE64编码/解码。

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");

    ...

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);
       }
    }
});

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"}
                }
            });

Be careful using evaluateJavascript : if there is a syntax error or exception thrown in your javascript it will call your onReceiveValue with a null. 小心使用evaluateJavascript :如果你的javascript中抛出了语法错误或异常,它将使用null调用你的onReceiveValue The most common way to support both SDK 19 as well as lower seems to be like this: Fill form in WebView with Javascript 支持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. 另请注意,使用默认WebView您无法使用javascript警报来测试任何内容,但它们不会显示。 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 :\\ 另请注意,默认情况下“视频”(如html <video>标签)默认情况下“无法正常工作”,默认情况下DRM视频也不起作用,它们都是配置选项:\\

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM