Рендеринг PDF-файла с помощью Java на Android

Я понял, что Android не имеет встроенного метода отображения файлов PDF.

Как я могу сделать PDF-файл с помощью Java на Android?

Solutions Collecting From Web of "Рендеринг PDF-файла с помощью Java на Android"

Взято из моего блога:

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

Поскольку API уровня 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(); 

Для получения дополнительной информации см. Пример приложения .

Для более старых 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(); 

Я сделал гибридный подход из некоторых ответов на эту и другие подобные должности:

Это решение проверяет, установлено ли приложение для чтения PDF, и делает следующее: – если читатель установлен, загрузите файл PDF на устройство и запустите приложение для чтения PDF. Если ни один читатель не установлен, спросите пользователя, хочет ли он просмотреть Файл PDF через Google Диск

ЗАМЕТКА! В этом решении используется класс DownloadManager Android, который был представлен в API9 (Android 2.3 или Gingerbread). Это означает, что он не работает на Android 2.2 или ранее.

Я написал сообщение в блоге об этом здесь , но я дал полный код ниже для полноты:

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

Наконец, я смог изменить код butelo, чтобы открыть любой файл PDF в файловой системе Android, используя pdf.js Код можно найти на моем GitHub

То, что я сделал, было изменено pdffile.js чтобы прочитать file аргументов HTML следующим образом:

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

Итак, вам нужно просто добавить путь к файлу после index.html следующим образом:

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

Обновите переменную path чтобы указать допустимый PDF-файл в файловой системе Adroid.

Загрузите исходный код здесь ( отобразите файл PDF внутри моего приложения для Android )

Добавьте эту зависимость в свой класс: compile '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 + "-"); } } } } 

Чтобы добавить немного света к этому, мне пришлось бы пойти с решением pdf.js из Mozilla. Вот ссылка на уже хорошо написанную реализацию этого: https://bitbucket.org/butelo/pdfviewer/ .

Вот изменения, которые я добавил в свою Android-активность:

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

Вот изменения, которые я сделал в pdffile.js :

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

Я использовал приведенный ниже код, чтобы открыть и распечатать PDF с помощью Wi-Fi. Я отправляю весь свой код, и я надеюсь, что это будет полезно.

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