Android - Webview中HTML代码提取不起作用(Javascript)

3
我正在编写一款应用程序,它具有以下功能: - 在Webview中加载URL; - 通过JavaScript代码提取HTML; - 在LOG中显示提取的HTML代码。
由于需要在未启用JavaScript的情况下加载页面(以避免某些页面的行为),我尝试了下面的代码,其中: - 禁用JavaScript的情况下在webview中加载页面; - 页面加载完成后,启用JavaScript; - 然后,应用程序执行提取HTML代码所需的JavaScript。
不幸的是,在Android 4.0.4上以调试模式运行代码时,会出现错误:
01-22 22:37:56.575: E/Web Console(7605): Uncaught TypeError: Cannot call method 'processHTML' of undefined at null:1

如果我移除myBrowserSettings.setJavaScriptEnabled(false);声明,在loadurl调用后,一切都会正确地运行。
我该如何让下面的代码正常工作?
package com.stefano.formfiller;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebSettings.PluginState;

public class MainActivity extends Activity {

    WebView myBrowser;
    String urlToBrowse = "http://www.mywebsite.com";
    String htmlCode = null;
    StringBuffer buffer = new StringBuffer();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

          myBrowser = (WebView)findViewById(R.id.webView1);

          //Browser settings
          WebSettings myBrowserSettings = myBrowser.getSettings();

          //Prevent cache to be used
          myBrowserSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
          myBrowserSettings.setAppCacheEnabled(false);

          //General settings
          myBrowserSettings.setJavaScriptEnabled(true);
          Log.d("Stefano", "JS enabled");

          //FIREFOX user agent
          myBrowserSettings.setUserAgentString("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");


          myBrowser.setWebChromeClient(new WebChromeClient());
          myBrowser.setWebViewClient(new WebViewClient() {
              public void onPageFinished(WebView view, String url) 
              { 

                    WebSettings myBrowserSettings = myBrowser.getSettings();
                    myBrowserSettings.setJavaScriptEnabled(true);
                    Log.d("Stefano", "JS enabled");

                    Log.d("Stefano", "OnPageFinished running"); 

              } });


          //Start the delayed HTML code extraction
          delayedStartHtmlExtractor(16000);
          Log.d("Stefano", "DelayedStart HTML Extractor launched");

          //Prepare Javascript to extract the HTML code from the webview
          myBrowser.addJavascriptInterface(new LoadListener(), "HTMLOUT");

          myBrowser.loadUrl(urlToBrowse);
          Log.d("Stefano", "Main URL requested");

          myBrowserSettings.setJavaScriptEnabled(false);
          Log.d("Stefano", "JS disabled");
    }   


    //Delayed HTML extraction
    public void delayedStartHtmlExtractor(final int delay){
        Handler handler = new Handler();

        handler.postDelayed(new Runnable() 
        {

            @Override
            public void run() 
            {                           


                myBrowser.loadUrl("javascript:window.HTMLOUT.processHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
                Log.d("Stefano", "HTML extraction launched");

                        }
            }, delay);
    }

    //Insert the HTML code in the log information

    class LoadListener{
        public void processHTML(String html)
        {
            Log.d("Stefano", "HTML Extraction in progress...");


            Log.e("HTML CODE",html);
        }
    }

更新: 我有一个疑问:代码在启用Javascript(通过myBrowser.addJavascriptInterface(new LoadListener(), "HTMLOUT");)时实例化了Javascript接口,然后,在URL调用后禁用Javascript,直到页面完全加载后再重新启用Javascript。

当我使用已实例化的接口禁用Javascript时,是否会“切断”Javascipt和Java代码之间的通信渠道?


你的注释不完整... - Stefano
3个回答

1

首先,您应该将适当的注释@JavascriptInterface附加到通过Javascript接口调用的方法上;在您的情况下:

    //..
    @JavascriptInterface
    public void processHTML(String html) {
        Log.d("Stefano", "HTML Extraction in progress...");
        Log.e("HTML CODE",html);
    }
    //..

"请注意,注入的对象在页面加载之前不会出现在JavaScript中"
"我认为使用setJavaScriptEnabled(false)加载页面根本不会注入任何Javascript对象,这就是你遇到这个问题的原因。"
"

可能的解决方法(未经测试)如下:

"
"
  • 始终使用setJavaScriptEnabled(true)加载页面
  • 通过http://www.google.com/gwt/n加载网页(将不使用JS或Flash加载页面)
  • 进行处理
"

感谢提供信息。 "@JavascriptInterface"声明不适用于目标API级别14(我正在使用的那个);我了解到需要API级别17以上。无论如何,我手动测试了"http://www.google.com/gwt/n" ,但它会加载URL而没有其他任何内容(几乎完整的HTML代码也没有)。所以,这是我无法采取的方法。 - Stefano
@bonnyz,你因为@JavascriptInterface的提示而值得获得诺贝尔奖。我有一个完美运行的API 8应用程序,使用这个processHTML()方法没有上述注释。然而,当我将我的应用程序的SDK更新到API 26后,它停止工作了!也就是说,processHTML()从未被调用!添加@JavascriptInterface解决了这个问题!谢谢。 - WebViewer

1
在接口设置后面添加myBrowser.loadData(...),像这样。
myBrowser.addJavascriptInterface(new LoadListener(), "HTMLOUT");
myBrowser.loadData("", "text/html", null);
myBrowser.loadUrl(urlToBrowse);

另外,由于您将在oncreate方法的结束处禁用js,因此没有必要在其首次启用它:)

希望这可以帮助到您


我会尝试并告诉你。你能解释一下为什么它应该行得通吗?我从未见过同时加载loaddata和loadurl的代码。谢谢。 - Stefano
我看到,在addJavascriptInterface的文档中,他们说添加的对象在下一次网页(重新)加载之前不会出现在JavaScript中。你的代码似乎很合理,但是奇怪的是只有在添加第一个loadData时才能正常工作! - medhdj
好的,这里是一个gist,这是我用的代码,基于你的代码。 - medhdj
感谢您的努力。我正在努力解决这个问题,但是如果我将“https://www.google.it/search?q=dog”作为URL加载,它会启用JavaScript加载页面;因此,这不是我需要的;我需要在没有启用JavaScript的情况下加载页面,就像我在问题中写的那样。 - Stefano

0

当您实例化LoadListener对象时,请尝试以下操作:

this.new LoadListener();

我尝试了这个代码 "myBrowser.addJavascriptInterface(new this.LoadListener(), "HTMLOUT");" 但是它会产生一个错误 [“this”上的语法错误,名称无效]。 - Stefano
我将上面的代码行更改为this.new LoadListener(),而不是new this.LoadListener()。试一试并告诉我发生了什么!此外,LoadListener为什么不是静态类? - nick
没有改变,还是原来的情况。不,没有特殊的理由不使用静态。我们可以尝试其他的东西吗?你在想什么? - Stefano
我进行了一些测试,似乎JavascriptInterface没有正确加载。你有什么想法吗? - Stefano
在这一行代码中:myBrowser.loadUrl("javascript:window.HTMLOUT.processHTML... 尝试移除 window. - nick
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接