如何在 Webview 中显示 PDF 文档?

137

我想在webview上显示PDF内容。 这是我的代码:

WebView webview = new WebView(this); 
setContentView(webview);
webview.getSettings().setJavaScriptEnabled(true); 
webview.loadUrl("http://www.adobe.com/devnet/acrobat/pdfs/pdf_open_parameters.pdf");

我得到了一个空白屏幕。我已经设置了互联网权限。

12个回答

197
您可以使用Google PDF查看器在线阅读PDF文档:

您可以使用Google PDF查看器在线阅读您的pdf文档:

WebView webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setJavaScriptEnabled(true); 
String pdf = "http://www.adobe.com/devnet/acrobat/pdfs/pdf_open_parameters.pdf";
webview.loadUrl("https://drive.google.com/viewerng/viewer?embedded=true&url=" + pdf);

61
经过连续测试两天,在谷歌文档中出现了一个错误提示:您已达到查看或下载非谷歌文档格式文件的带宽限制......。看起来不太可靠。 - Shobhit Puri
6
文档的URL现在被重定向到Drive页面:"https://drive.google.com/viewerng/viewer?embedded=true&url="。 - Murphy
65
这个解决方案绝对糟糕。许多人考虑在他们的应用程序中使用这么丑陋的东西,这让我很担心。此页面是为桌面设计的,该网站明显优化了桌面体验,使用移动设备浏览并不是一个良好的移动体验。 - shoke
8
如果你离线了,该怎么办? - yerlilbilgin
5
@LyteSpeed 想知道是什么让我们在应用程序中添加如此丑陋的解决方案吗?是的,你已经知道了:谷歌强大的Android团队。 - Farid
显示剩余16条评论

42
如果您使用仅查看URL,用户将不会提示登录到他们的Google帐户。
https://docs.google.com/viewer?url=http://my.domain.com/yourPdfUrlHere.pdf

1
它正在要求登录。 - LincyTonita
哪一个登录是那个? - gumuruh
它只使用您当前活动的帐户。 - slott

15

使用Google Docs打开PDF文件对用户体验来说并不是一个好主意,速度非常慢且反应迟钝。

API 21之后的解决方案

从API 21开始,我们可以使用PdfRenderer将PDF转换为位图。我从未使用过它,但似乎相当容易。

适用于任何API级别的解决方案

另一种解决方案是下载PDF文档,并通过Intent传递给专门的PDF应用程序进行显示。快速且良好的用户体验,特别是如果此功能不是您的应用程序的核心所在。

使用以下代码下载并打开PDF文档:

public class PdfOpenHelper {

public static void openPdfFromUrl(final String pdfUrl, final Activity activity){
    Observable.fromCallable(new Callable<File>() {
        @Override
        public File call() throws Exception {
            try{
                URL url = new URL(pdfUrl);
                URLConnection connection = url.openConnection();
                connection.connect();

                // download the file
                InputStream input = new BufferedInputStream(connection.getInputStream());
                File dir = new File(activity.getFilesDir(), "/shared_pdf");
                dir.mkdir();
                File file = new File(dir, "temp.pdf");
                OutputStream output = new FileOutputStream(file);

                byte data[] = new byte[1024];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    total += count;
                    output.write(data, 0, count);
                }

                output.flush();
                output.close();
                input.close();
                return file;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<File>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(File file) {
                    String authority = activity.getApplicationContext().getPackageName() + ".fileprovider";
                    Uri uriToFile = FileProvider.getUriForFile(activity, authority, file);

                    Intent shareIntent = new Intent(Intent.ACTION_VIEW);
                    shareIntent.setDataAndType(uriToFile, "application/pdf");
                    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    if (shareIntent.resolveActivity(activity.getPackageManager()) != null) {
                        activity.startActivity(shareIntent);
                    }
                }
            });
}

}

要使Intent正常工作,您需要创建一个FileProvider来授予接收应用程序打开文件的许可。

以下是实现方法: 在您的清单文件中:

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">

        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />

    </provider>

最后在资源文件夹中创建一个file_paths.xml文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="shared_pdf" path="shared_pdf"/>
</paths>

希望这能有所帮助 =)


1
shared_pdf是assets目录下的文件夹吗? - Mehdi Haghgoo
1
这是一个不错的解决方案。 - Mehdi Haghgoo

14

使用此代码

private void pdfOpen(String fileUrl){

        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setPluginState(WebSettings.PluginState.ON);

        //---you need this to prevent the webview from
        // launching another browser when a url
        // redirection occurs---
        webView.setWebViewClient(new Callback());

        webView.loadUrl(
                "http://docs.google.com/gview?embedded=true&url=" + fileUrl);

    }

    private class Callback extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(
                WebView view, String url) {
            return (false);
        }
    }

1
@Athira kidilam 的回答。 - Samwinishere Here
1
setPluginState现已弃用。 - Täg
那么被弃用的方法有什么替代方案呢? - gumuruh

7
你可以使用 Mozilla pdf.js 项目,基本上它会将 PDF 显示出来。看一下他们的示例
我只在浏览器(桌面和移动设备)上使用它,效果很好。

嗨@paulo,你能否提供一个关于如何在Android上使用这个的例子给我吗? - Khalid ElSayed
1
@KhalidElSayed 我认为butelo已经成功地实现了你的目标:http://stackoverflow.com/a/21383356/505893 - bluish
pdf.js可以在本地使用吗?我的意思是它能否在一个没有互联网访问但与本地服务器通信的局域网应用程序中使用? - Mehdi Haghgoo

7

在这里使用进度对话框加载。如果不使用WebClient,则会强制在浏览器中打开:

final ProgressDialog pDialog = new ProgressDialog(context);
    pDialog.setTitle(context.getString(R.string.app_name));
    pDialog.setMessage("Loading...");
    pDialog.setIndeterminate(false);
    pDialog.setCancelable(false);
    WebView webView = (WebView) rootView.findViewById(R.id.web_view);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            pDialog.show();
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            pDialog.dismiss();
        }
    });
    String pdf = "http://www.adobe.com/devnet/acrobat/pdfs/pdf_open_parameters.pdf";
    webView.loadUrl("https://drive.google.com/viewerng/viewer?embedded=true&url=" + pdf);

我该如何在Webview中启用PDF搜索功能? - Anant Shah

3

实际上,所有的解决方案都相当复杂,而我找到了一个非常简单的解决方案(我不确定它是否适用于所有的SDK版本)。它将在预览窗口中打开PDF文档,用户可以查看、保存/共享文档:

webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
     val i = Intent(Intent.ACTION_QUICK_VIEW)
     i.data = Uri.parse(url)
     if (i.resolveActivity(getPackageManager()) != null) {
            startActivity(i)
     } else {
            val i2 = Intent(Intent.ACTION_VIEW)
            i2.data = Uri.parse(url)
            startActivity(i2)
     }
})

(Kotlin)


1
可以给我一个 DownloadListener 类的示例代码吗? - mohammedragabmohammedborik
1
@mohammedragabmohammedborik DownloadListener类已经包含在Android中,您不需要任何额外的类来运行上述代码。 - Dion
2
请注意,ACTION_QUICK_VIEW 仅支持 Android N 及以上版本。 - pumpkee
@pumpkee 你说得对,那在我的情况下会引起问题。我添加了上面的代码以检查是否可用快速预览。否则它将在浏览器中打开。 - Dion

1
这是在评论中提到的错误出现之前,谷歌允许的实际使用限制。如果用户只会在应用程序中打开一次生命周期内的pdf文件,则我认为它是完全安全的。虽然建议使用Android 5.0 / Lollipop中内置的框架PDFRenderer,采用本机方法。

“PDFRenderer”的链接已损坏。” - Nate
@Nate感谢你让我注意到这个问题,我非常感激。我已经更新了链接。由于PDF渲染器是原生的Android API,他们已经将东西移动到了网站上,所以如果未来更新的链接再次失效,最好在Android开发者网站上搜索。 - Mightian

-1

您可以使用

webView.getSettings().setJavaScriptEnabled(true);

val url = "http://your.domain.com/your_pdf_urlHere.pdf"
webView.loadUrl("https://docs.google.com/gview?embedded=true&url=$url")

如果你想在Web视图中打开嵌套的PDF链接
webView.webViewClient = object : WebViewClient() {
        override fun shouldOverrideUrlLoading( view: WebView, request: WebResourceRequest): Boolean {
            if (request.url.toString().endsWith(".pdf")) {
                val url = "https://docs.google.com/gview?embedded=true&url=${request.url}"
                view.loadUrl(url)
            }
            return false
        }
    }

这不会要求登录谷歌账户


-1
String webviewurl = "http://test.com/testing.pdf";
webView.getSettings().setJavaScriptEnabled(true); 
if(webviewurl.contains(".pdf")){
    webviewurl = "http://docs.google.com/gview?embedded=true&url=" + webviewurl;        }
webview.loadUrl(webviewurl);

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