Java 如何在 Android 中呈现 PDF 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2456344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:56:59  来源:igfitidea点击:

How to render a PDF file in Android

javaandroidpdfandroid-pdf-api

提问by alexleutgoeb

Android does not have PDF support in its libraries. Is there any way to render PDF files in the Android applications?

Android 在其库中不支持 PDF。有没有办法在 Android 应用程序中渲染 PDF 文件?

回答by Shankar Agarwal

Taken from my blog:

摘自我的博客:

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

回答by JesperB

I have made a hybrid approach from some of the answers given to this and other similar posts:

我从对这个帖子和其他类似帖子的一些答案中提出了一种混合方法:

This solution checks if a PDF reader app is installed and does the following: - If a reader is installed, download the PDF file to the device and start a PDF reader app - If no reader is installed, ask the user if he wants to view the PDF file online through Google Drive

此解决方案检查是否安装了 PDF 阅读器应用程序并执行以下操作: - 如果安装了阅读器,则将 PDF 文件下载到设备并启动 PDF 阅读器应用程序 - 如果未安装阅读器,请询问用户是否要查看通过 Google Drive 在线的 PDF 文件

NOTE!This solution uses the Android DownloadManagerclass, which was introduced in API9 (Android 2.3 or Gingerbread). This means that it doesn't work on Android 2.2 or earlier.

笔记!该解决方案使用了DownloadManager在 API9(Android 2.3 或 Gingerbread)中引入的 Android类。这意味着它不适用于 Android 2.2 或更早版本。

I wrote a blog post about it here, but I've provided the full code below for completeness:

在这里写了一篇关于它的博客文章,但为了完整起见,我提供了下面的完整代码:

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;
    }

}

回答by Droid Chris

To add a little light to this, I would have to go with the pdf.js solution from Mozilla. Here is the link to an already well written implementation of this: https://bitbucket.org/butelo/pdfviewer/.

为了增加一点亮点,我必须使用 Mozilla 的 pdf.js 解决方案。这是一个已经写得很好的实现的链接:https: //bitbucket.org/butelo/pdfviewer/

Here are the edits that I added in my Android Activity:

以下是我在 Android Activity 中添加的编辑:

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

Here are the edits I made in pdffile.js:

以下是我所做的编辑pdffile.js

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

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

回答by Shantanu Paul

I finally was able to modify butelo's codeto open any PDF file in the Android filesystem using pdf.js. The code can be found on my GitHub

我终于能够修改butelo 的代码,使用pdf.js. 代码可以在我的 GitHub 上找到

What I did was modified the pdffile.jsto read HTML argument filelike this:

我所做的是修改pdffile.js以读取 HTML 参数,file如下所示:

var url = getURLParameter('file');

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

So what you need to do is just append the file path after the index.htmllike this:

所以你需要做的就是在index.html这样的后面附加文件路径:

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

Update the pathvariable to point to a valid PDF in the Adroid filesystem.

更新path变量以指向 Adroid 文件系统中的有效 PDF。

回答by Milo? ?ernilovsky

Since API Level 21 (Lollipop) Android provides a PdfRenderer class:

由于 API Level 21 (Lollipop) Android 提供了一个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();

For more information see the sample app.

有关更多信息,请参阅示例应用程序

For older APIs I recommend Android PdfViewer library, it is very fast and easy to use, licensed under Apache License 2.0:

对于较旧的 API,我推荐Android PdfViewer 库,它非常快速且易于使用,在 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();

回答by Murali Mohan

I used the below code to open and print the PDF using Wi-Fi. I am sending my whole code, and I hope it is helpful.

我使用以下代码使用 Wi-Fi 打开和打印 PDF。我正在发送我的整个代码,希望对您有所帮助。

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

回答by Deepshikha Puri

Download the source code here (Display PDF file inside my android application)

在此处下载源代码(在我的 android 应用程序中显示 PDF 文件

Add this dependency in your Grade: compile 'com.github.barteksc:android-pdf-viewer:2.0.3'

在您的成绩中添加此依赖项:compile 'com.github.barteksc:android-pdf-viewer:2.0.3'

activity_main.xml

活动_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

主活动.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 + "-");
            }
        }
    }

}

回答by Samet ?ZTOPRAK

There is no anyway to preview pdf document in Android webview.If you want to preview base64 pdf. It requires to third-party library.

无论如何都无法在Android webview 中预览pdf 文档。如果您想预览base64 pdf。它需要第三方库。

build.Gradle

构建.Gradle

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

dialog_pdf_viewer

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

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

    }
}

回答by akshay shetty

you can use a simple method by import

您可以通过导入使用一个简单的方法

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

and the XML code is

并且 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>

and just declare and add a file to an asset folder and just assign the name

只需声明并将文件添加到资产文件夹并指定名称

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