Cara merender file PDF di Android


213

Android tidak memiliki dukungan PDF di perpustakaannya. Apakah ada cara untuk membuat file PDF di aplikasi Android?


5
Ini adalah contoh yang baik untuk Menampilkan file pdf. Perlu merujuk file Readme.txt di tautan di bawah untuk menggunakan ini. github.com/jblough/Android-Pdf-Viewer-Library
Ramesh Akula

1
berikut adalah contoh penggunaan perpustakaan itu: stackoverflow.com/a/16294833/2027232
Nicolas Tyler

Jawaban:


68

Karena API Level 21 (Lollipop) Android menyediakan kelas PdfRenderer :

// create a new renderer
 PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());

 // let us just render all pages
 final int pageCount = renderer.getPageCount();
 for (int i = 0; i < pageCount; i++) {
     Page page = renderer.openPage(i);

     // say we render for showing on the screen
     page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);

     // do stuff with the bitmap

     // close the page
     page.close();
 }

 // close the renderer
 renderer.close();

Untuk informasi lebih lanjut, lihat contoh aplikasi .

Untuk API yang lebih lama saya sarankan perpustakaan Android PdfViewer , sangat cepat dan mudah digunakan, dilisensikan di bawah Apache License 2.0:

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();

12
Pustaka PDFView bagus, tetapi perhatikan bahwa itu di bawah GNU General Public, bukan Lesser GPL. Ini mungkin menyulitkan untuk disertakan dalam perangkat lunak komersial.
Sam

Ya, @Sam benar. Secara pribadi saya harus menggunakan PDF.js karena masalah lisensi pada versi Android yang lebih lama, tetapi renderingnya sangat lambat dan sulit untuk membuatnya berfungsi karena komunikasi Java-JavaScript.
Miloš Černilovský

1
Untuk versi yang lebih lama, apakah ada cara untuk menunjukkannya tanpa mengunduh dan menyimpan file di suatu tempat di aplikasi?
Gokhan Arik

1
Bisakah Anda membuat contoh yang lebih rinci menggunakan PDFView Library? Apa yang harus kita masukkan pdfName? Apa fungsi onDraw, onLoaddan onPageChangependengar terlihat seperti? Terima kasih atas bantuan Anda :)
Triet Doan

2
Menambahkan perpustakaan PDF baru yang dilisensikan di bawah Apache License 2.0 sebagai jawabannya.
Miloš Černilovský

61

Diambil dari blog saya:

public class MyPdfViewActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    WebView mWebView=new WebView(MyPdfViewActivity.this);
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.getSettings().setPluginsEnabled(true);
    mWebView.loadUrl("https://docs.google.com/gview?embedded=true&url="+LinkTo);
    setContentView(mWebView);
  }
}

70
Ini benar-benar tidak terlalu bersih. Pertama, jika Google memutuskan untuk mengubah URL Google Documents mereka, aplikasi Anda akan rusak dan Anda harus mendorong pembaruan agar pengguna dapat melihat dokumen lagi.
Markus

3
ini hanya memungkinkan saya untuk melihat halaman pertama, dan tautan "Unduh" di bagian bawah tidak aktif ... ada ide? Selain itu, sepertinya setPluginsEnabled bukan bagian dari kelas WebView lagi.
whyoz

7
Ini tidak akan berfungsi jika tidak ada koneksi Internet dan Ini memerlukan Izin INTERNET
Mani

4
Dulu bekerja. Namun baru-baru ini, ia terus menunjukkan "Aduh! Ada masalah saat melihat pratinjau dokumen ini" Saya kira google telah mengubah beberapa hal di pihak mereka yang menyebabkan masalah ini.
Lee Yi Hong

1
Bagi saya itu sangat lambat memuat dan menggulir dokumen.
nilsi

33

Saya telah membuat pendekatan hibrida dari beberapa jawaban yang diberikan untuk ini dan tulisan serupa lainnya:

Solusi ini memeriksa apakah aplikasi pembaca PDF diinstal dan melakukan hal berikut: - Jika pembaca diinstal, unduh file PDF ke perangkat dan mulai aplikasi pembaca PDF - Jika tidak ada pembaca yang diinstal, tanyakan kepada pengguna apakah ia ingin melihat file PDF online melalui Google Drive

CATATAN! Solusi ini menggunakan DownloadManagerkelas Android , yang diperkenalkan di API9 (Android 2.3 atau Gingerbread). Ini berarti bahwa itu tidak berfungsi pada Android 2.2 atau sebelumnya.

Saya menulis posting blog tentang hal itu di sini , tetapi saya telah memberikan kode lengkap di bawah ini untuk kelengkapan:

public class PDFTools {
    private static final String GOOGLE_DRIVE_PDF_READER_PREFIX = "http://drive.google.com/viewer?url=";
    private static final String PDF_MIME_TYPE = "application/pdf";
    private static final String HTML_MIME_TYPE = "text/html";

    /**
     * If a PDF reader is installed, download the PDF file and open it in a reader. 
     * Otherwise ask the user if he/she wants to view it in the Google Drive online PDF reader.<br />
     * <br />
     * <b>BEWARE:</b> This method
     * @param context
     * @param pdfUrl
     * @return
     */
    public static void showPDFUrl( final Context context, final String pdfUrl ) {
        if ( isPDFSupported( context ) ) {
            downloadAndOpenPDF(context, pdfUrl);
        } else {
            askToOpenPDFThroughGoogleDrive( context, pdfUrl );
        }
    }

    /**
     * Downloads a PDF with the Android DownloadManager and opens it with an installed PDF reader app.
     * @param context
     * @param pdfUrl
     */
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static void downloadAndOpenPDF(final Context context, final String pdfUrl) {
        // Get filename
        final String filename = pdfUrl.substring( pdfUrl.lastIndexOf( "/" ) + 1 );
        // The place where the downloaded PDF file will be put
        final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), filename );
        if ( tempFile.exists() ) {
            // If we have downloaded the file before, just go ahead and show it.
            openPDF( context, Uri.fromFile( tempFile ) );
            return;
        }

        // Show progress dialog while downloading
        final ProgressDialog progress = ProgressDialog.show( context, context.getString( R.string.pdf_show_local_progress_title ), context.getString( R.string.pdf_show_local_progress_content ), true );

        // Create the download request
        DownloadManager.Request r = new DownloadManager.Request( Uri.parse( pdfUrl ) );
        r.setDestinationInExternalFilesDir( context, Environment.DIRECTORY_DOWNLOADS, filename );
        final DownloadManager dm = (DownloadManager) context.getSystemService( Context.DOWNLOAD_SERVICE );
        BroadcastReceiver onComplete = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if ( !progress.isShowing() ) {
                    return;
                }
                context.unregisterReceiver( this );

                progress.dismiss();
                long downloadId = intent.getLongExtra( DownloadManager.EXTRA_DOWNLOAD_ID, -1 );
                Cursor c = dm.query( new DownloadManager.Query().setFilterById( downloadId ) );

                if ( c.moveToFirst() ) {
                    int status = c.getInt( c.getColumnIndex( DownloadManager.COLUMN_STATUS ) );
                    if ( status == DownloadManager.STATUS_SUCCESSFUL ) {
                        openPDF( context, Uri.fromFile( tempFile ) );
                    }
                }
                c.close();
            }
        };
        context.registerReceiver( onComplete, new IntentFilter( DownloadManager.ACTION_DOWNLOAD_COMPLETE ) );

        // Enqueue the request
        dm.enqueue( r );
    }

    /**
     * Show a dialog asking the user if he wants to open the PDF through Google Drive
     * @param context
     * @param pdfUrl
     */
    public static void askToOpenPDFThroughGoogleDrive( final Context context, final String pdfUrl ) {
        new AlertDialog.Builder( context )
            .setTitle( R.string.pdf_show_online_dialog_title )
            .setMessage( R.string.pdf_show_online_dialog_question )
            .setNegativeButton( R.string.pdf_show_online_dialog_button_no, null )
            .setPositiveButton( R.string.pdf_show_online_dialog_button_yes, new OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    openPDFThroughGoogleDrive(context, pdfUrl); 
                }
            })
            .show();
    }

    /**
     * Launches a browser to view the PDF through Google Drive
     * @param context
     * @param pdfUrl
     */
    public static void openPDFThroughGoogleDrive(final Context context, final String pdfUrl) {
        Intent i = new Intent( Intent.ACTION_VIEW );
        i.setDataAndType(Uri.parse(GOOGLE_DRIVE_PDF_READER_PREFIX + pdfUrl ), HTML_MIME_TYPE );
        context.startActivity( i );
    }
    /**
     * Open a local PDF file with an installed reader
     * @param context
     * @param localUri
     */
    public static final void openPDF(Context context, Uri localUri ) {
        Intent i = new Intent( Intent.ACTION_VIEW );
        i.setDataAndType( localUri, PDF_MIME_TYPE );
        context.startActivity( i );
    }
    /**
     * Checks if any apps are installed that supports reading of PDF files.
     * @param context
     * @return
     */
    public static boolean isPDFSupported( Context context ) {
        Intent i = new Intent( Intent.ACTION_VIEW );
        final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), "test.pdf" );
        i.setDataAndType( Uri.fromFile( tempFile ), PDF_MIME_TYPE );
        return context.getPackageManager().queryIntentActivities( i, PackageManager.MATCH_DEFAULT_ONLY ).size() > 0;
    }

}

8

Unduh kode sumber di sini ( Tampilkan file PDF di dalam aplikasi android saya )

Tambahkan dependensi ini di Grade Anda: kompilasi 'com.github.barteksc: android-pdf-viewer: 2.0.3'

activity_main.xml

<RelativeLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="@color/colorPrimaryDark"
        android:text="View PDF"
        android:textColor="#ffffff"
        android:id="@+id/tv_header"
        android:textSize="18dp"
        android:gravity="center"></TextView>

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


    </RelativeLayout>

MainActivity.java

import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener;
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener;
import com.github.barteksc.pdfviewer.scroll.DefaultScrollHandle;
import com.shockwave.pdfium.PdfDocument;

import java.util.List;

public class MainActivity extends Activity implements OnPageChangeListener,OnLoadCompleteListener{
    private static final String TAG = MainActivity.class.getSimpleName();
    public static final String SAMPLE_FILE = "android_tutorial.pdf";
    PDFView pdfView;
    Integer pageNumber = 0;
    String pdfFileName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        pdfView= (PDFView)findViewById(R.id.pdfView);
        displayFromAsset(SAMPLE_FILE);
    }

    private void displayFromAsset(String assetFileName) {
        pdfFileName = assetFileName;

        pdfView.fromAsset(SAMPLE_FILE)
                .defaultPage(pageNumber)
                .enableSwipe(true)

                .swipeHorizontal(false)
                .onPageChange(this)
                .enableAnnotationRendering(true)
                .onLoad(this)
                .scrollHandle(new DefaultScrollHandle(this))
                .load();
    }


    @Override
    public void onPageChanged(int page, int pageCount) {
        pageNumber = page;
        setTitle(String.format("%s %s / %s", pdfFileName, page + 1, pageCount));
    }


    @Override
    public void loadComplete(int nbPages) {
        PdfDocument.Meta meta = pdfView.getDocumentMeta();
        printBookmarksTree(pdfView.getTableOfContents(), "-");

    }

    public void printBookmarksTree(List<PdfDocument.Bookmark> tree, String sep) {
        for (PdfDocument.Bookmark b : tree) {

            Log.e(TAG, String.format("%s %s, p %d", sep, b.getTitle(), b.getPageIdx()));

            if (b.hasChildren()) {
                printBookmarksTree(b.getChildren(), sep + "-");
            }
        }
    }

}

petunjuk: assetFileNamefile pdf harus ada dalam assetsfolder
ahmednabil88

7

Saya akhirnya bisa memodifikasi kode butelo untuk membuka file PDF apa pun di sistem file Android menggunakan pdf.js. Kode dapat ditemukan di GitHub saya

Apa yang saya lakukan diubah pdffile.jsuntuk membaca argumen HTML fileseperti ini:

var url = getURLParameter('file');

function getURLParameter(name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null}

Jadi yang perlu Anda lakukan hanyalah menambahkan path file setelah index.htmlseperti ini:

Uri path = Uri.parse(Environment.getExternalStorageDirectory().toString() + "/data/test.pdf");
webView.loadUrl("file:///android_asset/pdfviewer/index.html?file=" + path);

Perbarui pathvariabel untuk menunjuk ke PDF yang valid di sistem file Adroid.


hai Paul, saya juga menggunakan contoh ini, tetapi ini menunjukkan layar kosong di WebView di API Level 16, dapatkah Anda memiliki masalah ini ??
Riddhish.Chaudhari

Di mana file pdf disimpan? Anda tidak dapat memuat pdf dari folder aset. Anda dapat memuat dari kartu SD atau penyimpanan internal aplikasi Anda yang dilindungi. Periksa juga logcat Anda untuk setiap kesalahan yang terkait dengan tampilan web.
Shantanu Paul

Uri path = Uri.parse (Environment.getExternalStorageDirectory (). ToString () + "/example4.pdf"); webView.loadUrl ("file: ///android_asset/pdfviewer/index.html? file =" + path);
Riddhish.Chaudhari

@ Paul saya menggunakan kode di atas berfungsi dengan baik dengan API 19 tetapi di bawah itu tidak berfungsi. Mengapa??
Riddhish.Chaudhari

Silakan lihat ini untuk kompatibilitas dengan versi Android yang lebih lama: github.com/pauldmps/Android-pdf.js/issues/1 github.com/pauldmps/Android-pdf.js/issues/2
Shantanu Paul

4

Anda dapat menggunakan metode sederhana dengan mengimpor

implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'

dan kode XML

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

dan cukup deklarasikan dan tambahkan file ke folder aset dan cukup tetapkan namanya

   PDFView  pdfView=findViewById(R.id.pdfv);       
    pdfView.fromAsset("agl.pdf").load();

Bagaimana Anda mendeklarasikan PDFView di Kotlin?
Nicholas Farmer

@NicholasFarmer periksa tautan ini stackoverflow.com/questions/56613766/...
akshay shetty

7
Hanya hati-hati, ini dapat menambah 16 ~ 18MB di atas aplikasi Anda. Perpustakaan ini menggunakan PdfiumAndroidyang sendiri sudah 18,4MB
Pierre

petunjuk: agl.pdffile harus ada dalam assetsfolder
ahmednabil88

1

Untuk menambahkan sedikit cahaya ke ini, saya harus pergi dengan solusi pdf.js dari Mozilla. Berikut ini tautan ke implementasi yang sudah ditulis dengan baik dari ini: https://bitbucket.org/butelo/pdfviewer/ .

Berikut ini suntingan yang saya tambahkan di Aktivitas Android saya:

private String getInternalPDFURL(String interalPDFName){
    return "file:///android_asset/pdfviewer/index.html?pdf=" + interalPDFName + ".pdf";
}

Berikut ini hasil edit yang saya buat pdffile.js:

var url = '../' + getPDFURL();

function getPDFURL(){
    var query = window.location.search.substring(1);
    var vars = query.split("=");
    var pdfPage = vars[1];
    return pdfPage;
}

1

Saya menggunakan kode di bawah ini untuk membuka dan mencetak PDF menggunakan Wi-Fi. Saya mengirim seluruh kode saya, dan saya harap ini membantu.

public class MainActivity extends Activity {

    int Result_code = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button mButton = (Button)findViewById(R.id.button1);

        mButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                 PrintManager printManager = (PrintManager)getSystemService(Context.PRINT_SERVICE);
                String jobName =  " Document";
                printManager.print(jobName, pda, null);
            }
        });
    }


    public void openDocument(String name) {

        Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
        File file = new File(name);
        String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
        String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        if (extension.equalsIgnoreCase("") || mimetype == null) {
            // if there is no extension or there is no definite mimetype, still try to open the file
            intent.setDataAndType(Uri.fromFile(file), "text/*");
        }
        else {
            intent.setDataAndType(Uri.fromFile(file), mimetype);
        }

        // custom message for the intent
        startActivityForResult((Intent.createChooser(intent, "Choose an Application:")), Result_code);
        //startActivityForResult(intent, Result_code);
        //Toast.makeText(getApplicationContext(),"There are no email clients installed.", Toast.LENGTH_SHORT).show();
    }


    @SuppressLint("NewApi")
    PrintDocumentAdapter pda = new PrintDocumentAdapter(){

        @Override
        public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback){
            InputStream input = null;
            OutputStream output = null;

            try {
                String filename = Environment.getExternalStorageDirectory()    + "/" + "Holiday.pdf";
                File file = new File(filename);
                input = new FileInputStream(file);
                output = new FileOutputStream(destination.getFileDescriptor());

                byte[] buf = new byte[1024];
                int bytesRead;

                while ((bytesRead = input.read(buf)) > 0) {
                     output.write(buf, 0, bytesRead);
                }

                callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
            }
            catch (FileNotFoundException ee){
                //Catch exception
            }
            catch (Exception e) {
                //Catch exception
            }
            finally {
                try {
                    input.close();
                    output.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras){

            if (cancellationSignal.isCanceled()) {
                callback.onLayoutCancelled();
                return;
            }

           // int pages = computePageCount(newAttributes);

            PrintDocumentInfo pdi = new PrintDocumentInfo.Builder("Name of file").setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();

            callback.onLayoutFinished(pdi, true);
        }
    };
}

0

Tidak ada cara untuk mempratinjau dokumen pdf di Android webview. Jika Anda ingin mempratinjau base64 pdf. Ini membutuhkan perpustakaan pihak ketiga.

membangun

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

dialog_pdf_viewer

<?xml version="1.0" encoding="utf-8"?>

<!--
  ~ Copyright (c) 2017.
  ~ Samet Öztoprak
  ~ All rights reserved.
  -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/dialog_pdf_viewer_close"
        style="@style/ExitButtonImageViewStyle"
        android:src="@drawable/popup_exit" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@color/white"
        android:orientation="vertical">

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

    </LinearLayout>

    <View style="@style/HorizontalLine" />

    <com.pozitron.commons.customviews.ButtonFont
        android:id="@+id/dialog_pdf_viewer_button"
        style="@style/ButtonPrimary2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="15dp"
        android:text="@string/agreed" />

</LinearLayout>

DailogPDFViewer.java

public class DialogPdfViewer extends Dialog {
    PDFView pdfView;
    byte[] decodedString;

    public interface OnDialogPdfViewerListener {
        void onAgreeClick(DialogPdfViewer dialogFullEula);

        void onCloseClick(DialogPdfViewer dialogFullEula);
    }

    public DialogPdfViewer(Context context, String base64, final DialogPdfViewer.OnDialogPdfViewerListener onDialogPdfViewerListener) {
        super(context);

        setContentView(R.layout.dialog_pdf_viewer);
        findViewById(R.id.dialog_pdf_viewer_close).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onDialogPdfViewerListener.onCloseClick(DialogPdfViewer.this);
            }
        });

        findViewById(R.id.dialog_pdf_viewer_button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onDialogPdfViewerListener.onAgreeClick(DialogPdfViewer.this);
            }
        });

        decodedString = Base64.decode(base64.toString(), Base64.DEFAULT);

        pdfView = ((PDFView) findViewById(R.id.pdfView));
        pdfView.fromBytes(decodedString).load();

        setOnKeyListener(new OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
                    onDialogPdfViewerListener.onCloseClick(DialogPdfViewer.this);
                }
                return true;
            }
        });

    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.