简体   繁体   English

WebViewClient onPageFinished从未调用

[英]WebViewClient onPageFinished never called

I've looked at several similar posts on S/O but I can't find an answer to my problem. 我在S / O上看过几篇类似的文章,但找不到我的问题的答案。 I'm trying to grab the html from a web view but I can't get my "onPageFinished() callback to fire. I've even tried using the progress callback on the WebChromeClient but nothing is working. neigh the web client or web chrome client receive any callbacks. I am running this code as an Android unit test and using a test HTML from the assets directory which I've confirmed via assert and debug is being located. What am I missing? 我正在尝试从Web视图中获取html,但是无法启动“ onPageFinished()回调。我什至尝试在WebChromeClient上使用进度回调,但没有任何作用。 chrome客户端会收到任何回调。我正在将此代码作为Android单元测试运行,并使用资产目录中的测试HTML(已通过assert和debug进行确认),该丢失了什么?

** Update ** I've stepped through the test method in debug. ** 更新 **我在调试中逐步完成了测试方法。 It does load the html (it's a unit test so I cannot actually see the rendered content). 它确实加载了html(这是一个单元测试,所以我实际上看不到渲染的内容)。 It then blocks on the wait() call, times out then performs the assert at the bottom without ever receiving a callback from either client. 然后,它阻塞wait()调用,超时然后在底部执行断言,而从未从任何一个客户端接收到回调。 (Both the web client and chrome client should/would call notify()) (Web客户端和chrome客户端均应/将调用notify())

The difference here would be that I am running within an Android unit test. 此处的区别是我正在Android单元测试中运行。 The WebView is NOT attached to any Activity or container. WebView未附加到任何活动或容器。 I'm wondering if that has anything to do with the missing callbacks. 我想知道这是否与缺少的回调有关。 I'll try sticking it on an Activity to see if it makes any difference. 我将尝试将其粘贴在活动上,以查看是否有任何区别。 ** / Update ** ** / 更新 **

public class MyWebViewTest extends InstrumentationTestCase {

    private WebView webView;
    private String html;

    public void setUp() throws Exception {
        super.setUp();
        Context context = getInstrumentation().getContext();
        this.webView = new WebView(context);
        assertTrue("requires test.html",
                Arrays.asList(context.getResources().getAssets().list("www")).contains("test.html"));
    }

    public void tearDown() throws Exception {

    }

    @JavascriptInterface
    public void viewContent(String content) {
        this.html = content;
    }
    public void testCanLoadAndReadWebContentFromWebView() throws Exception {
        webView.addJavascriptInterface(this, "_webContainer");
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView webView, String url) {
                super.onPageFinished(webView, url);
                onPageLoaded(webView);
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }
        });

        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                if(newProgress==100)
                    onPageLoaded(webView);
            }
        });

        webView.loadUrl("file:///android_asset/www/test.html");
        synchronized (this) {
            wait(5000);
        }
        assertNotNull(html);
    }


    private void onPageLoaded(WebView webView) {
        webView.loadUrl("javascript:window._webContainer.viewContent(document.documentElement.innerHTML);");
        synchronized (this) {
            notify();
        }
    }
}

I was correct in my assumption! 我的假设是正确的! When the WebView is not attached to an Activity it will not load, render, or do much of anything. 当WebView未附加到Activity时,它将不会加载,呈现或执行任何其他操作。 I ended up extending ActivityInstrumentationTestCase2 and attaching the web view to an Activity. 我最终扩展了ActivityInstrumentationTestCase2并将Web视图附加到Activity。 At that point my breakpoints in the callbacks started lighting up. 那时,我在回调中的断点开始亮起。 Here's my working test case: 这是我的工作测试用例:

public class MyWebViewTest extends ActivityInstrumentationTestCase2<TestMeActivity> {

    private WebView webView;
    private String html;

    public MyWebViewTest() {
        super(TestMeActivity.class);
    }

    public void setUp() throws Exception {
        super.setUp();
        Context context = getInstrumentation().getContext();
        this.webView = getActivity().getView();
        assertTrue("requires test.html",
                Arrays.asList(context.getResources().getAssets().list("www")).contains("test.html"));
    }

    public void tearDown() throws Exception {

    }

    @JavascriptInterface
    public void viewContent(String content) {
        this.html = content;
    }

    public void testCanLoadAndReadWebContentFromWebView() throws Exception {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                configureWebView();
            }
        });
        synchronized (MyWebViewTest.this) {
            MyWebViewTest.this.wait(25000);
        }
        assertEquals("<head></head><body>\n" +
                "Hello\n" +
                "\n" +
                "</body>",html);
    }

    private void configureWebView() {
        webView.addJavascriptInterface(this, "_webContainer");
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView webView, String url) {
                super.onPageFinished(webView, url);
                onPageLoaded(webView);
            }
        });

        webView.loadUrl("file:///android_asset/www/test.html");
    }


    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void onPageLoaded(WebView webView) {
        webView.evaluateJavascript("javascript:window._webContainer.viewContent(document.documentElement.innerHTML);",
                new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        synchronized (MyWebViewTest.this) {
                            MyWebViewTest.this.notify();
                        }
                    }
                }
        );
    }
}

and here's the Activity I threw together to back it: 这是我一起支持的活动:

public class TestMeActivity extends Activity{

    private WebView view;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        view = new WebView(this);
        setContentView(view);
    }

    public WebView getView() {
        return view;
    }
}

In short there is quite a bit of work involved in testing the contents of a WebView from an Android TestCase. 简而言之,从Android TestCase测试WebView的内容涉及很多工作。 You have to add a Javascript interface to the web view, insert some Javascript to invoke the internal Javascript interface object, passing the contents of the web view, through the interface and finally collect it in your test case. 您必须向Web视图添加Javascript接口,插入一些Javascript来调用内部Javascript接口对象,并通过该接口传递Web视图的内容,最后将其收集到测试用例中。 I sure wish it were easier but this is the best I can come up with. 我当然希望它更容易,但这是我能想到的最好的方法。

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

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