Home > database >  Cannot open pdf file that was generated from an InputStream
Cannot open pdf file that was generated from an InputStream

Time:02-16

I have an API that provides me with InputStream of a pdf file. And my objective is to allow user to view this file with another pdf viewer application.

In order to acheive this, I copied the InputStream to a pdf file that has been created programmatically. Then I tried to open that pdf file.

However, I'm not able to open the pdf file through my application or file explorer. Drive PDF viewer tells in toast that it cannot open the pdf file, Adobe Acrobat tells that the pdf file cannot be accessed, and Mi PDF reader tells that the pdf is in invalid format.

Here's the code inside onResponse() of OkHttpClient's call:

                if (response.isSuccessful()) {
                    InputStream inputStream = responseBody.byteStream();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            File file = null;
                            try {
                                file = MyFileUtils.createPdfFile(PdfViewActivity.this);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            MyFileUtils.copyInputStreamToFile(inputStream, file);
                            String pdfFilePath = file.getAbsolutePath();
                            openPdf(pdfFilePath);
                        }
                    });
                }

Here's the method responsible for opening pdf:

    private void openPdf(String pdfFilePath) {
        Intent pdfViewIntent = new Intent(Intent.ACTION_VIEW);
        pdfViewIntent.setDataAndType(Uri.parse(pdfFilePath), "application/pdf");
        Intent chooser = Intent.createChooser(pdfViewIntent, "Open this note with");
        startActivity(chooser);
        finish();
    }

I created the pdf using MyFileUtils.createPdfFile() method. Here's how I implemented it:

    public static File createPdfFile(Activity associatedActivity) throws IOException {
        String timeStamp = new SimpleDateFormat("HHmmss").format(new Date());
        String pdfFileName = "PDF_"   timeStamp   "_";

        File storageDir = associatedActivity.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
        Log.d(TAG, "createPdfFile: storageDir: "   storageDir.getAbsolutePath());

        return File.createTempFile(
                pdfFileName,  /* prefix */
                ".pdf",         /* suffix */
                storageDir      /* directory */
        );
    }

I copied the InputStream to that file using the following method in MyFileUtils class:

    // Copy an InputStream to a File.
    public static void copyInputStreamToFile(InputStream in, File file) {
        OutputStream out = null;

        try {
            out = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Ensure that the InputStreams are closed even if there's an exception.
            try {
                if (out != null) {
                    out.close();
                }

                // If you want to close the "in" InputStream yourself then remove this
                // from here but ensure that you close it yourself eventually.
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

I've implemented the provider in the following way:

AndroidManifest.xml :

    <application>
        ...
        ...
        ...
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.example.xyz.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>

file_paths.xml :

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="Pictures" />
    <external-files-path name="my_documents" path="Documents" />
</paths>

NOTE:

  • The application has necessary read-write permissions. I've tested it programmatically. I'm not including those codes here because it might not be relevant.
  • The absolute path of the created pdf file is something like this: /storage/emulated/0/Android/data/<package name>/files/Documents/PDF_164257_4832620770047519807.pdf

CodePudding user response:

You need to download on device download directory. Your directory is not visible to other's application that's by its not opening. Only your application can use this directory.

Not able to comment due to less reputation

CodePudding user response:

I am not sure if this helps but I see that the file you copy the InputStream into seems not be closed before you call openPdf(pdfFilePath); which means the pdf viewers get trouble opening it either because it is blocked or not all content has been written into the file.

  • Related