简体   繁体   English

Android Webview 有时无法呈现 pdf,而是显示空白/白页

[英]Android Webview cannot render the pdf sometimes and shows blank/white page instead

  • Open the pdf in the webview using google docs使用 google docs 在 webview 中打开 pdf
  • Open the same pdf or different pdf again and again.一次又一次地打开相同的 pdf 或不同的 pdf。
  • Sometimes it will show the blank/white page in the android untill we refresh the webpage again for 1 or 2 times.有时它会在 android 中显示空白/白色页面,直到我们再次刷新网页 1 或 2 次。

I have made the sample on the pdf.我已经在pdf上制作了样本。 The link for the project is shown below:该项目的链接如下所示:

https://github.com/gopalawasthi123/PdfWebView https://github.com/gopalawasthi123/PdfWebView

Hope this will help you Better.希望这会帮助你更好。

public void SetWebView(WebView webview,string externalUrl){
            webview.Tag = "webview";
            webview.Settings.JavaScriptEnabled = true;
            webview.Settings.SupportZoom ();
            webview.Settings.SetAppCacheEnabled(true);
            webview.Settings.DomStorageEnabled = true;
            webview.ZoomOut ();
            webview.ZoomIn ();
            webview.Settings.BuiltInZoomControls = true;
            webview.Settings.LoadWithOverviewMode = true;
            webview.Settings.UseWideViewPort = true;
            //webview.Settings.SetSupportZoom (true);
            webview.Settings.SetPluginState (WebSettings.PluginState.On);
            webview.Settings.GetPluginState ();
            if (externalUrl.StartsWith("http://") || externalUrl.StartsWith("https://"))
                webview.LoadUrl (externalUrl);
            webview.SetWebViewClient (new MonkeyWebViewClient (imgViewBack, imgViewForward, imgRefresh));
            webview.SetWebChromeClient (new WebChromeClient ());
        }

You can reload the page until it displays the pdf in this way:您可以重新加载页面,直到它以这种方式显示 pdf:

public void onPageFinished(WebView view, String url) {
if (view.getTitle().equals(""))
    view.reload();
}

After testing second PDF URL file, WebView seems like that can not load large PDF file.在测试第二个 PDF URL 文件后,WebView 似乎无法加载大型 PDF 文件。

Reason:原因:

WebView display HTML. WebView 显示 HTML。 The fact that this works at all is by a hack- google will convert simple PDFs into HTML.事实上,这完全有效是由于 hack-google 会将简单的 PDF 转换为 HTML。 It doesn't seem like they support anything that big.他们似乎不支持那么大的东西。 Even if they did, I would expect loading a large page PDF converted to HTML would be so large I highly doubt you'd be able to load it without going OOM.即使他们这样做了,我希望加载一个转换为 HTML 的大页面 PDF 会如此之大,我非常怀疑您是否能够在不出现 OOM 的情况下加载它。 Use an appropriate PDF library, make a real PDF rendering view, and make sure not to render more of the PDF at a time than you need (or else you'll go OOM anyway).使用适当的 PDF 库,制作真实的 PDF 渲染视图,并确保一次渲染的 PDF 数量不要超过您的需要(否则您无论如何都会 OOM)。 In other words, don't rely on hacky solutions you never should have relied on in the first place.换句话说,不要依赖你一开始就不应该依赖的骇人听闻的解决方案。

Solution:解决方案:

You should try alternatives like PDF.js running locally in your device, instead of a service like Google Docs preview.(Or download PDF first to local file path)您应该尝试在您的设备上本地运行PDF.js等替代方案,而不是像 Google Docs 预览这样的服务。(或者先将 PDF 下载到本地文件路径)

Put it in your assets folder and tweak the example:将它放在您的资产文件夹中并调整示例:

wv.loadUrl("file:///android_asset/web/viewer.html");

Also, you can have Out Of Memory situations.此外,您还可能遇到内存不足的情况。 An alternative to try is a native viewer like AndroidPdfViewer .另一种尝试方法是像AndroidPdfViewer这样的本地查看器。

We can solve the Problem in the two ways.我们可以通过两种方式解决问题。 1. One is to use the Js.Pdf Plugin on the server end. 1、一种是在服务端使用Js.Pdf Plugin。 It surely solve the problem but if we have multiple pdf's in the Fragment then it may cause the out of memory situations and app can crash.它肯定可以解决问题,但如果我们在片段中有多个 pdf,则可能会导致内存不足的情况,并且应用程序可能会崩溃。 2. Second option is we can recursively called the function to load webview. 2. 第二种选择是我们可以递归调用函数来加载 webview。 This will also cause the issue but with less frequency Below is the code:这也会导致问题,但频率较低下面是代码:

private void showPdf(final String imageString) {
pdfView.invalidate();
pdfView.getSettings().setJavaScriptEnabled(true);
pdfView.getSettings().setSupportZoom(true);
pdfView.loadUrl("http://docs.google.com/gview?embedded=true&url=" + imageString);
pdfView.setWebViewClient(new WebViewClient() {
    boolean checkhasOnPageStarted = false;

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        checkhasOnPageStarted = true;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        if (checkhasOnPageStarted ) {
            pdfView.loadUrl(removePdfTopIcon);
        } else {
            showPdf(imageString);
        }
    }
});
}

I was having the exact same issue and found that there was always a chance the WebView would not load on the first load attempt, especially if the pdf was on the larger side.我遇到了完全相同的问题,发现 WebView 总是有可能在第一次加载尝试时无法加载,尤其是当 pdf 文件较大时。 The code I put together below works 100% of the time.我放在下面的代码在 100% 的时间内都有效。 From my beginner's understanding, it safely utilizes a separate thread to loop through and test the load status of the WebView, re-attempting a load of the view until successful.根据我初学者的理解,它安全地利用一个单独的线程来循环并测试 WebView 的加载状态,重新尝试加载视图直到成功。 As this question was posted a year ago, I have generalized my solution to best benefit new viewers.由于这个问题是一年前发布的,所以我已经概括了我的解决方案,以最大程度地让新观众受益。

public class WebViewActivity extends AppCompatActivity {

String PDFView;
WebView webView;
String PDFBrowserView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Get the intended "PDFView"
    PDFView = getIntent().getExtras().get("PDFView").toString();
    //Have to manually encode (?) the url to display it
    try {
        PDFView = URLEncoder.encode(PDFView, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    //Full display url
    PDFBrowserView = "https://docs.google.com/gview?embedded=true&url=" + PDFView;

    //Initialize a new "WebView" instance
    webView = new WebView(WebViewActivity.this);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setAllowFileAccessFromFileURLs(true);
    webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
    webView.getSettings().setBuiltInZoomControls(true);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setPluginState(WebSettings.PluginState.ON);
    webView.getSettings().setDomStorageEnabled(true);
    webView.getSettings().setLoadWithOverviewMode(true);
    webView.getSettings().setUseWideViewPort(true);
    //This handles callbacks (?)
    webView.setWebChromeClient(new WebChromeClient());

    //Call this to load page if page is blank with pdf url until page is not blank
    checkPageFinished();
}

public void checkPageFinished() {
    //If view is blank:
    if (webView.getContentHeight() == 0) {

        //Run off main thread to control delay
        webView.postDelayed(new Runnable() {
            @Override
            public void run() {
                //Load url into the "WebView"
                webView.loadUrl(PDFBrowserView);
            }
            //Set 1s delay to give the view a longer chance to load before 
            // setting the view (or more likely to display blank)
        }, 1000);
        //Set the view with the selected pdf
        setContentView(webView);

        webView.postDelayed(new Runnable() {
            @Override
            public void run() {
                //If view is still blank:
                if (webView.getContentHeight() == 0) {
                    //Loop until it works
                    checkPageFinished();
                }
            }
            //Safely loop this function after 1.5s delay if page is not loaded
        }, 1500);

        }
    }
}

There are some ways through which we can identify whether a Page/URL is loaded properly or not from onPageFinished() method of the Webview and based on that reload() url.有一些方法可以通过 Webview 的onPageFinished()方法并基于reload() url 来确定页面/URL 是否正确加载。

Option 1: To check with contentHeight of the webview.选项 1:检查 webview 的contentHeight

override fun onPageFinished(view: WebView?, url: String?) {
    if(view?.contentHeight == 0){
        view?.reload()
        return
    }
    super.onPageFinished(view, url)
}
    

Option 2: To check with title of the webview.选项 2:检查 webview 的title

override fun onPageFinished(view: WebView?, url: String?) {
    if(view?.title.isNullOrEmpty()){
        view?.reload()
        return
    }
    super.onPageFinished(view, url)
}

Tested in multiple devices and working within API 29在多个设备上测试并在 API 29 中工作

in Kotlin在科特林

 val webSettings: WebSettings = webview.settings
    webSettings.javaScriptEnabled = true
    webSettings.useWideViewPort = true
    webSettings.loadWithOverviewMode = true
    webSettings.domStorageEnabled = true

    webview.webViewClient = AppWebViewClients()
// val TERM_CONDITION_URL = "http://docs.google.com/gview?embedded=true&url="
//          + "YOUR_DOC_URL_HERE"

   bindind?.webview?.loadUrl(TERM_CONDITION_URL) 

and here AppWebViewClients class和这里AppWebViewClients

    class AppWebViewClients : WebViewClient() {
    override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean {
        view.loadUrl(url)
        return true
    }

    override fun onPageFinished(view: WebView?, url: String?) {
        if (view?.contentHeight == 0)
            view?.reload();
        else {
            super.onPageFinished(view, url)
        }
    }
}

I think you should do as below:我认为你应该这样做:

public void onPageFinished(WebView view, String url) {

    if (!view.getUrl().equals(url)) {
       view.loadUrl(url);
       return;
    }
}

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

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