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 上,然后由 Adob​​e 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中的手机本地存储

RN从IOS中的URL获取blob下载docx或pdf

如何使用 Python 从指向子 URL 的 URL 下载 pdf 文件

从远程 url 从 ios 应用程序下载 PDF

从 API URL 下载 PDF

Android PDF 从内部存储打开后立即关闭