Android 从 URL 下载 PDF,然后使用 PDF 阅读器打开它
Posted
技术标签:
【中文标题】Android 从 URL 下载 PDF,然后使用 PDF 阅读器打开它【英文标题】:Android download PDF from URL then open it with a PDF reader 【发布时间】:2014-09-04 14:06:11 【问题描述】:我正在尝试编写一个应用程序来从 URL 下载 PDF,将它们存储在 SD 上,然后由 Adobe PDF 阅读器或其他应用程序(能够打开 PDF)打开。
到目前为止,我已经“成功下载并存储在 SD 卡上”(但每次我尝试使用 PDF 阅读器打开 PDF 时,阅读器都会崩溃并说出现意外错误),例如,@987654321 @
这是我的下载器的代码:
//........code set ui stuff
//........code set ui stuff
new DownloadFile().execute(fileUrl, fileName);
private class DownloadFile extends AsyncTask<String, Void, Void>
@Override
protected Void doInBackground(String... strings)
String fileUrl = strings[0]; // -> http://maven.apache.org/maven-1.x/maven.pdf
String fileName = strings[1]; // -> maven.pdf
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File folder = new File(extStorageDirectory, "testthreepdf");
folder.mkdir();
File pdfFile = new File(folder, fileName);
try
pdfFile.createNewFile();
catch (IOException e)
e.printStackTrace();
FileDownloader.downloadFile(fileUrl, pdfFile);
return null;
public class FileDownloader
private static final int MEGABYTE = 1024 * 1024;
public static void downloadFile(String fileUrl, File directory)
try
URL url = new URL(fileUrl);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(directory);
int totalSize = urlConnection.getContentLength();
byte[] buffer = new byte[MEGABYTE];
int bufferLength = 0;
while((bufferLength = inputStream.read(buffer))>0 )
fileOutputStream.write(buffer, 0, bufferLength);
fileOutputStream.close();
catch (FileNotFoundException e)
e.printStackTrace();
catch (MalformedURLException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
在调试模式下,我可以看到应用下载它并将此 PDF 存储在 /storage/sdcard/testpdf/maven.pdf 上。但是,我猜该文件可能在下载过程中以某种方式损坏,因此无法正常打开...
这是我打算如何用另一个阅读器应用程序打开它的代码:
File pdfFile = new File(Environment.getExternalStorageDirectory() + "/testthreepdf/" + fileName); // -> filename = maven.pdf
Uri path = Uri.fromFile(pdfFile);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
startActivity(pdfIntent);
catch(ActivityNotFoundException e)
Toast.makeText(documentActivity, "No Application available to view PDF", Toast.LENGTH_SHORT).show();
【问题讨论】:
byte[] buffer = new byte[MEGABYTE];
这条线是什么意思?它是否为缓冲区分配了 1 GB 的空间?
【参考方案1】:
String imageurl = response.optString("PdfUrl");
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(imageurl));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
dm.enqueue(request);
【讨论】:
【参考方案2】:您好,问题出在 FileDownloader 类中
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
您需要删除以上两行,一切都会正常工作。如果问题按预期工作,请将问题标记为已回答。
同一问题的最新解决方案更新android PDF Write / Read using Android 9 (API level 28)
用屏幕截图附加工作代码。
MainActivity.java
package com.example.downloadread;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
public void download(View v)
new DownloadFile().execute("http://maven.apache.org/maven-1.x/maven.pdf", "maven.pdf");
public void view(View v)
File pdfFile = new File(Environment.getExternalStorageDirectory() + "/testthreepdf/" + "maven.pdf"); // -> filename = maven.pdf
Uri path = Uri.fromFile(pdfFile);
Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
pdfIntent.setDataAndType(path, "application/pdf");
pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try
startActivity(pdfIntent);
catch(ActivityNotFoundException e)
Toast.makeText(MainActivity.this, "No Application available to view PDF", Toast.LENGTH_SHORT).show();
private class DownloadFile extends AsyncTask<String, Void, Void>
@Override
protected Void doInBackground(String... strings)
String fileUrl = strings[0]; // -> http://maven.apache.org/maven-1.x/maven.pdf
String fileName = strings[1]; // -> maven.pdf
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File folder = new File(extStorageDirectory, "testthreepdf");
folder.mkdir();
File pdfFile = new File(folder, fileName);
try
pdfFile.createNewFile();
catch (IOException e)
e.printStackTrace();
FileDownloader.downloadFile(fileUrl, pdfFile);
return null;
FileDownloader.java
package com.example.downloadread;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class FileDownloader
private static final int MEGABYTE = 1024 * 1024;
public static void downloadFile(String fileUrl, File directory)
try
URL url = new URL(fileUrl);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
//urlConnection.setRequestMethod("GET");
//urlConnection.setDoOutput(true);
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(directory);
int totalSize = urlConnection.getContentLength();
byte[] buffer = new byte[MEGABYTE];
int bufferLength = 0;
while((bufferLength = inputStream.read(buffer))>0 )
fileOutputStream.write(buffer, 0, bufferLength);
fileOutputStream.close();
catch (FileNotFoundException e)
e.printStackTrace();
catch (MalformedURLException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.downloadread"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.downloadread.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/button1"
android:layout_
android:layout_
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="15dp"
android:text="download"
android:onClick="download" />
<Button
android:id="@+id/button2"
android:layout_
android:layout_
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/button1"
android:layout_marginTop="38dp"
android:text="view"
android:onClick="view" />
</RelativeLayout>
【讨论】:
嗨,扎克,通过删除这两行,它可以工作,我可以在我的移动设备上下载和阅读。但不知何故,每次我尝试在模拟器上阅读 DLed pdf 时,它都会崩溃,知道为什么吗?我使用这个 adobe reader apk -> appsapk.com/adobe-reader 你是在模拟器还是你的设备上阅读的?谢谢 另外,我想知道为什么通过删除这两行,应用程序可以工作?幕后故事是什么?谢谢 我的理解是从桌面应用程序下载 PDF 时需要指定 GET / POST,但是在 Android 中根据响应代码决定如何下载。因此,不需要该行。另外 doOutput 不是必需的,因为我们正在流式传输和写入 pdf 文件。如果您需要更多详细信息,请告诉我。感谢您将其标记为已回答。祝你有美好的一天。 @MohammedZackria-Zack 你的例子很好,但是当我打开另一个 Pdf 以前的文件自动删除时出现问题。请告诉我如何防止文件删除请帮助我 @Spritzig 我已经更新了你的问题的解决方案***.com/questions/55816746/…【参考方案3】:从这里下载源代码 (Open Pdf from url in Android Programmatically)
MainActivity.java
package com.deepshikha.openpdf;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
public class MainActivity extends AppCompatActivity
WebView webview;
ProgressBar progressbar;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webview = (WebView)findViewById(R.id.webview);
progressbar = (ProgressBar) findViewById(R.id.progressbar);
webview.getSettings().setjavascriptEnabled(true);
String filename ="http://www3.nd.edu/~cpoellab/teaching/cse40816/android_tutorial.pdf";
webview.loadUrl("http://docs.google.com/gview?embedded=true&url=" + filename);
webview.setWebViewClient(new WebViewClient()
public void onPageFinished(WebView view, String url)
// do your stuff here
progressbar.setVisibility(View.GONE);
);
谢谢!
【讨论】:
【参考方案4】:这是下载和查看 PDF 文件的最佳方法。您可以从任何地方调用它
PDFTools.showPDFUrl(context, url);
下面放代码。它会正常工作
public class PDFTools
private static final String TAG = "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";
public static void showPDFUrl(final Context context, final String pdfUrl )
if ( isPDFSupported( context ) )
downloadAndOpenPDF(context, pdfUrl);
else
askToOpenPDFThroughGoogleDrive( context, 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 );
String filename = "";
try
filename = new GetFileInfo().execute(pdfUrl).get();
catch (InterruptedException e)
e.printStackTrace();
catch (ExecutionException e)
e.printStackTrace();
// The place where the downloaded PDF file will be put
final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), filename );
Log.e(TAG,"File Path:"+tempFile);
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 );
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 DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
openPDFThroughGoogleDrive(context, pdfUrl);
)
.show();
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 );
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 );
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;
// get File name from url
static class GetFileInfo extends AsyncTask<String, Integer, String>
protected String doInBackground(String... urls)
URL url;
String filename = null;
try
url = new URL(urls[0]);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
conn.setInstanceFollowRedirects(false);
if(conn.getHeaderField("Content-Disposition")!=null)
String depo = conn.getHeaderField("Content-Disposition");
String depoSplit[] = depo.split("filename=");
filename = depoSplit[1].replace("filename=", "").replace("\"", "").trim();
else
filename = "download.pdf";
catch (MalformedURLException e1)
e1.printStackTrace();
catch (IOException e)
return filename;
@Override
protected void onPreExecute()
super.onPreExecute();
@Override
protected void onPostExecute(String result)
super.onPostExecute(result);
// use result as file name
试试看。它会起作用的,享受吧
【讨论】:
这个过程有点长 在替换 openPDF(context, FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".my.package.name.provider", tempFile) 等 openPDF 方法后,这对我有用);它在这里描述:***.com/a/38858040/1492681 请注意,尽管 Google 网络服务http://drive.google.com/viewer
并未作为 API 正式推出供公众使用,而且他们可以随时将其撤下,而无需任何公开通知。以上是关于Android 从 URL 下载 PDF,然后使用 PDF 阅读器打开它的主要内容,如果未能解决你的问题,请参考以下文章
从url下载pdf,在flutter中保存到android中的手机本地存储