方案對比
| 方案 | 原理 | 優點 | 缺點 | 推薦度 |
| Google Docs Viewer | iframe 嵌入 https://docs.google.com/gview?embedded=true&url=... | 零成本、支持多格式 | 國內無法訪問、隱私風險、限流 | ❌ 不可用 |
| Mozilla PDF.js | WebView 加載本地/服務端部署的 PDF.js 查看器 | 純前端、開源、無依賴、功能全 | 需部署靜態資源、大文件加載慢 | ⭐⭐⭐⭐⭐ 首選 |
| Android PdfRenderer API | 原生渲染 PDF 頁面為 Bitmap,自定義 View 顯示 | 性能最好、系統級、無第三方庫 | API 21+、需手寫 UI(縮放/翻頁/選中) | ⭐⭐⭐⭐ 原生首選 |
| 第三方 SDK (MuPDF/PDFium) | 集成 C++ 渲染庫經 JNI 調用 | 功能強、商業級支持 | 體積大、授權費用、集成複雜 | ⭐⭐⭐ 企業級 |
方案一:WebView + PDF.js(推薦通用方案)
步驟 1:獲取 PDF.js
- 下載:GitHub Releases (預構建版
pdfjs--dist.zip)
- 解壓得到
build/ (核心) 和 web/ (查看器 UI) 目錄。
步驟 2:放入 Android 項目
app/src/main/assets/
├── pdfjs/
│ ├── build/
│ │ ├── pdf.js
│ │ ├── pdf.worker.js
│ │ └── ...
│ └── web/
│ ├── viewer.html
│ ├── viewer.css
│ ├── viewer.js
│ ├── locale/zh-CN/ (可選:中文語言包)
│ └── images/
步驟 3:修改 viewer.html 支持動態 URL
<!-- viewer.html 關鍵修改 -->
<script>
// 接收 Android 傳遞的 PDF URL
var pdfUrl = decodeURIComponent(location.search.substring(1).split('url=')[1]);
if (pdfUrl) {
PDFViewerApplication.open(pdfUrl);
}
</script>
步驟 4:WebView 加載代碼
WebView webView = findViewById(R.id.webView);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setAllowContentAccess(true);
settings.setDomStorageEnabled(true);
// 關鍵:允許 file:// 協議加載本地 assets 中的 js/css
settings.setAllowFileAccessFromFileURLs(true);
settings.setUniversalAccessFromFileURLs(true);
String pdfUrl = "https://example.com/document.pdf"; // 你的 PDF 鏈接
String viewerUrl = "file:///android_asset/pdfjs/web/viewer.html?url=" + URLEncoder.encode(pdfUrl, "UTF-8");
webView.loadUrl(viewerUrl);
步驟 5:處理大文件/權限/下載
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
if (url.endsWith(".pdf")) {
// 攔截 PDF 直接在當前 WebView 打開
String newUrl = "file:///android_asset/pdfjs/web/viewer.html?url=" + URLEncoder.encode(url, "UTF-8");
view.loadUrl(newUrl);
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
// 處理加載失敗:網絡錯誤、跨域、文件不存在等
}
});
// 長按下載/另存為
webView.setOnLongClickListener(v -> {
WebView.HitTestResult result = webView.getHitTestResult();
if (result.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
String url = result.getExtra();
// 啟動下載服務或彈出菜單
}
return false;
});
方案二:Android PdfRenderer (API 21+,原生高性能)
// 核心渲染邏輯
PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
int pageCount = renderer.getPageCount();
for (int i = 0; i < pageCount; i++) {
PdfRenderer.Page page = renderer.openPage(i);
Bitmap bitmap = Bitmap.createBitmap(pageWidth, pageHeight, Bitmap.Config.ARGB_8888);
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
// 將 bitmap 顯示在 ImageView/RecyclerView 中
page.close();
}
renderer.close();
- 優勢:流暢度最好、內存可控、支持密文 PDF(需密碼)。
- 缺點:需自行實現縮雙指縮放、頁面切換、文本選中、目錄導航等 UI 交互。
- 開源封裝庫:AndroidPdfViewer (基於 PdfRenderer 封裝完整 UI)。
方案三:Mozilla PDF.js 服務端部署(解決大文件/離線)
- 將 PDF.js 部署到你的服務器 (Nginx/Apache 靜態托管)。
- App 中 WebView 加載
https://yourdomain.com/pdfjs/web/viewer.html?url=...。
- 優勢:App 體積小、PDF.js 可獨立升級、支持 CDN 加速。
關鍵問題解決
| 問題 | 解決方案 |
| 跨域 (CORS) 導致 PDF 無法加載 | 服務端配置 Access-Control-Allow-Origin: *;或 App 端下載 PDF 到本地文件,再用 file:// 協議加載 |
| 大文件 (>50MB) 加載極慢/崩潰 | 使用 PdfRenderer 分頁渲染;或服務端預生成縮略圖/分頁圖片 |
| 加密 PDF 無法打開 | PDF.js 支持輸入密碼回調;PdfRenderer 需 openPage(password) |
| WebView 白屏/JS 報錯 | 啟用 setWebContentsDebuggingEnabled(true) 調試;檢查 assets 路徑、JS 語法錯誤 |
總結建議
- 通用項目、快速集成:WebView + 本地 PDF.js (assets 部署),功能完整、無原生開發成本。
- 高性能、原生體驗、API 21+:PdfRenderer + AndroidPdfViewer 庫。
- 企業級、加密、批註、簽名:考慮商業 SDK (Foxit、PDFTron、MuPDF 商業版)。
- 完全離線、無服務端:PDF.js assets 方案最佳。
參考資源