1. 程式人生 > >Android 開發之多種方案PDF閱讀

Android 開發之多種方案PDF閱讀

Android 開發之多種方案PDF閱讀

最近開發中涉及到閱讀港股公告,但是HK股票的公告都是坑,居然是pdf的,所以沒辦法,就要研究安卓pdf閱讀,期間踩了點坑……

安卓的webview與ios 的UIWebView不一樣,不能夠支援線上閱讀pdf,其實PC端的瀏覽器大部分也不支援pdf預覽,雖然谷歌官方給了個“http //docs google com/gviewembedded=true&url=”這樣的解決方案(將pdf、doc當成圖片來看),但是在天朝有一堵牆,所以這個方案直接被拋棄。PC端的Chrome與火狐都是使用js處理才實現了pdf預覽,所以在安卓端現有閱讀並實現相容性的解決方案有兩種:一、使用webview,但本地新增js庫處理(火狐提供了開源的pdf.js),二、修改安卓底層庫,使用自定義view進行pdf預覽。

一、使用JS 處理支援webview閱讀pdf(同樣適用於web前端)

1.伺服器解決

此處將使用到pdf.js(火狐的解決方案)
服務端
//安裝pdf.js

$ npm install -g gulp-cli

//構建

$ gulp generic

構建完成後,把generic拷貝伺服器相對目錄下,就完成了。
啟動服務,使用如下地址預覽

http://localhost:8080/generic/web/viewer.html
這裡寫圖片描述

最後,如果你要開啟指定的pdf,這樣就可以了

http://localhost:8080/generic/web/viewer.html?file=aaa.pdf


是不是很簡單啊。

2.客戶端解決

https://github.com/mozilla/pdf.js/下下來放到專案的assets下面,然後將這些copy到data下或者sd卡中,pdf也下載到相對目錄下,然後就可以同上一樣作為本地伺服器一樣閱讀pdf了,效果如下圖
這裡寫圖片描述

二、修改安卓底層庫,使用自定義view進行pdf預覽

1.官方simple PdfRendererBasic

這裡寫圖片描述

  • pdf開發三部曲

開啟初始化Pdf讀取器PdfRenderer
如果你是在Fragment裡面使用,最好在onAttach方法初始化

    /**
     * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources.
     */
private void openRenderer(Context context) throws IOException { // In this sample, we read a PDF from the assets directory. mFileDescriptor = context.getAssets().openFd("sample.pdf").getParcelFileDescriptor(); // This is the PdfRenderer we use to render the PDF. mPdfRenderer = new PdfRenderer(mFileDescriptor); }

讀取內容
傳入指定頁碼,讀取內容轉換成bitmap圖片設定到ImageView

   private void showPage(int index) {
        if (mPdfRenderer.getPageCount() <= index) {
            return;
        }
        // Make sure to close the current page before opening another one.
        if (null != mCurrentPage) {
            mCurrentPage.close();
        }
        // Use `openPage` to open a specific page in PDF.
        mCurrentPage = mPdfRenderer.openPage(index);
        // Important: the destination bitmap must be ARGB (not RGB).
        Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(),
                Bitmap.Config.ARGB_8888);
        // Here, we render the page onto the Bitmap.
        // To render a portion of the page, use the second and third parameter. Pass nulls to get
        // the default result.
        // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
        mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
        // We are ready to show the Bitmap to user.
        mImageView.setImageBitmap(bitmap);
        updateUi();
    }

關閉Pdf讀取器PdfRenderer
PdfRenderer.Page提供了幾個方法方便與我們使用,例如getIndex(獲取當前頁碼)、getPageCount(總頁碼)等。在我們離開pdf展示頁面時需要對資源進行釋放,關閉Pdf讀取器(fragment在生命週期onDetach呼叫釋放關閉),如果你想做的像小說閱讀一樣,可以記錄當前的index方便下次進入直接跳轉到指定位置,書籤就這個原理

  private void closeRenderer() throws IOException {
        if (null != mCurrentPage) {
            mCurrentPage.close();
        }
        mPdfRenderer.close();
        mFileDescriptor.close();
    }

如果你需要這個simple可以選擇官網simple下面下載,如果你不能訪問可以選擇github上面下載:https://github.com/googlesamples/android-PdfRendererBasic,當然這個simple功能簡單並不完善,僅僅實現了pdf簡單展示,跟為高階功能我們接著往下看。

2、PdfViewPager

這裡寫圖片描述
首先新增專案依賴

compile 'es.voghdev.pdfviewpager:library:0.2.1'

讀寫網路許可權肯定需要的(本地pdf不需要網路),如果是網路pdf檔案需要通過RemotePDFViewPager現在遠端檔案,DownloadFile.Listener回撥下載結果,下載成功了需要為RemotePDFViewPager繫結介面卡PDFPagerAdapter,在Activity銷燬時需要釋放PDFPagerAdapter

public class RemotePDFActivity extends AppCompatActivity implements DownloadFile.Listener {

 public void initPdfView(){
   RemotePDFViewPager remotePDFViewPager =
      new RemotePDFViewPager(context, "http://partners.adobe.com/public/developer/en/xml/AdobeXMLFormsSamples.pdf", this);
 }
 @Override
 public void onSuccess(String url, String destinationPath) {
    // That's the positive case. PDF Download went fine

    adapter = new PDFPagerAdapter(this, "AdobeXMLFormsSamples.pdf");
    remotePDFViewPager.setAdapter(adapter);
    setContentView(remotePDFViewPager);
 }

 @Override
 public void onFailure(Exception e) {
    // This will be called if download fails
 }

 @Override
 public void onProgressUpdate(int progress, int total) {
    // You will get download progress here
    // Always on UI Thread so feel free to update your views here
 }
 @Override
 protected void onDestroy() {
    super.onDestroy();

    adapter.close();
 }
}

根據github上面資料介紹,該庫支援網路pdf、assets檔案下的pdf、SDcard快取的pdf檔案,看上去挺不錯的,但是,但是還是有版本要求

這裡寫圖片描述

3、android-pdfview

這裡寫圖片描述

持多種方式載入pdf,向下相容到API8,Configurator提供了builder的方式配置屬性,讓程式碼更簡潔了,使用時Gradle依賴

compile 'com.joanzapata.pdfview:android-pdfview:1.0.4@aar'

xml佈局

<com.joanzapata.pdfview.PDFView
        android:id="@+id/pdfview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

程式碼呼叫例項

pdfView.fromAsset(pdfName)
    .pages(0, 2, 1, 3, 3, 3)
    .defaultPage(1)
    .showMinimap(false)
    .enableSwipe(true)
    .onDraw(onDrawListener)
    .onLoad(onLoadCompleteListener)
    .onPageChange(onPageChangeListener)
    .load();

pages和onDraw是可選項,pages:它可以讓你過濾和你需要的PDF頁面順序,onDraw:允許您在當前頁面畫布上畫上一個的東西

但是,在使用上面這個庫時以為就ok了,但是pdf有多種標準(按理說是統一了的SO/DIS19005-1),但在我使用中確實有些不行,不過上面這個庫已經滿足了大部分的需求。

3、AndroidPdfViewer

這個處理掉了上面哪個庫部分格式不支援導致崩潰的問題,也是我現在在使用的庫,效果圖如下:

這裡寫圖片描述

工程於API 11及更高版本。根據Apache許可證授權2.0。
加入的build.gradle:

compile 'com.github.barteksc:android-pdf-viewer:2.1.0'

PDFView在佈局

<com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

載入PDF檔案

pdfView.fromUri(Uri)
or
pdfView.fromFile(File)
or
pdfView.fromAsset(String)
    .pages(0, 2, 1, 3, 3, 3) // all pages are displayed by default
    .enableSwipe(true)
    .swipeHorizontal(false)
    .enableDoubletap(true)
    .defaultPage(0)
    .onDraw(onDrawListener)
    .onLoad(onLoadCompleteListener)
    .onPageChange(onPageChangeListener)
    .onPageScroll(onPageScrollListener)
    .onError(onErrorListener)
    .enableAnnotationRendering(false)
    .password(null)
    .scrollHandle(null)
    .load();

enableSwipe 是可選的,它可以讓你改變阻止使用刷卡頁面
pages 是可選的,它可以讓你篩選並定向PDF的頁面,看你需要
onDraw 也是可選的,並允許你畫的東西提供的畫布上,在當前頁面上方

原始碼地址:https://github.com/barteksc/AndroidPdfViewer

但是就是有點大,一整合,包就增大16MB.Android的PDF檢視器取決於PdfiumAndroid,這是許多體系的設定本機庫(將近16 MB)的。APK必須包含所有此庫的每一個市場可用的裝置上執行。幸運的是,谷歌Play可讓我們上傳多個APK,每每建築如之一。有自動拆分您的應用程式分成多個APK。