Android open pdf file
Asked Answered
A

6

42

I'm developing an Android application and I have to open some files.

This is my code using intent:

public class FacturaActivity extends Activity {

    (...)

    public void downloadInvoice(View view) {
        File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +"/"+ filename);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file),"application/pdf");
        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        startActivity(intent);
    }
}

File is in the root directory of the SD card and I can manually open it.

Problem

Application is closed when it arrives at startActivity(intent). I think the problem is in AndroidManifest.xml file, but I don't know how to put it correctly.

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="8" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:name="###.MyApplication" > <!--cant show complete name-->
    <activity
        android:name="###.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>

    <activity 
        android:name=".FacturaActivity" >
    </activity>

</application>

LogCat

07-03 15:49:13.094: E/AndroidRuntime(1032): FATAL EXCEPTION: main
07-03 15:49:13.094: E/AndroidRuntime(1032): java.lang.IllegalStateException: Could not execute method of the activity
(...)
07-03 15:49:13.094: E/AndroidRuntime(1032): Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=file:///mnt/sdcard/201209_F2012212782.PDF typ=application/pdf flg=0x40000000 }
07-03 15:49:13.094: E/AndroidRuntime(1032):     at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1408)
07-03 15:49:13.094: E/AndroidRuntime(1032):     at android.app.Instrumentation.execStartActivity(Instrumentation.java:1378)
07-03 15:49:13.094: E/AndroidRuntime(1032):     at android.app.Activity.startActivityForResult(Activity.java:2817)
07-03 15:49:13.094: E/AndroidRuntime(1032):     at android.app.Activity.startActivity(Activity.java:2923)

Can you help me to complete AndroidManifest? Or how can I open that pdf?

Argentina answered 3/7, 2013 at 16:16 Comment(3)
it seems your Android has no any pdf reader app installed, add oneJehias
I can open other pdf's files with ThinkFree PDF Viewer.Argentina
This blog post helps if you're trying to use ContentProvider (which is now recommended): blogc.at/2014/03/23/…Bye
S
109

The problem is that there is no app installed to handle opening the PDF. You should use the Intent Chooser, like so:

File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +"/"+ filename);
Intent target = new Intent(Intent.ACTION_VIEW);
target.setDataAndType(Uri.fromFile(file),"application/pdf");
target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

Intent intent = Intent.createChooser(target, "Open File");
try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Instruct the user to install a PDF reader here, or something
}   
Splenic answered 3/7, 2013 at 16:22 Comment(11)
I have tried it in my mobile phone. When I open some pdf of another app, it says to register ThinkFree, I say "Later" and "ThinkFree PDF Viewer Mobile for Android" is openned, showing me pdf file. With your code, it only arrives to ask for ThinkFree registering. If I say "Later", it closes.Argentina
That has nothing to do with this code. You can't control the way ThinkFree handles this intent. Try installing an alternative PDF viewer.Splenic
Thanks, it is ok. One more thing...When I close pdf file (with back button of the phone) my application closes with an error. How can I solve that?Argentina
Are you using startActivity(Intent) or startActivityForResult(Intent, int)? I'd have to see what you're doing in onResume() or onActivityResult(int, int, Intent). What is the error?Splenic
I use Intent intent = new Intent(this, FacturaActivity.class); startActivity(intent); I haven't written anything in onResume(). The error is: "Sorry! The application ### (process com.###) has stopped unespectedly. Please try again. [Force close]" and it returns to another previous activity (not the one that handled pdf viewer) without any data that should have. I want to return to same Activity that startActivity of PDF viewer.Argentina
I meant the actual error (exception stack), from the logs. That "Force Close" message, on the UI, is the same for all exceptions.Splenic
Sorry, I can't see it now because I've had to try it in my mobile phone, not connected to pc, so I can't read log. I'll try it tomorrow and answer you.Argentina
Error given is ArrayIndexOutOfBoundsException because data has been deleted. But this happens with ThinkFree PDF Viewer, with Adobe Reader data is loaded correctly. I don't understand it...Argentina
In my app gives me file does not exist message.A have the file in AndroidStudioProjects/Myapp/app/src/main/res/myfilefolder/test.pdf.Can you give the syntax of the filepath?I am using android studio and I try it in the emulator.Hoes
Is intent will be handled , if my file is in internal storage ?Dicker
ActivityNotFoundException is never be thrown, because it always resolve com.android.internal.app.ChooserActivity.Digitalism
M
13

As of API 24, sending a file:// URI to another app will throw a FileUriExposedException. Instead, use FileProvider to send a content:// URI:

public File getFile(Context context, String fileName) {
    if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        return null;
    }

    File storageDir = context.getExternalFilesDir(null);
    return new File(storageDir, fileName);
}

public Uri getFileUri(Context context, String fileName) {
    File file = getFile(context, fileName);
    return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
}

You must also define the FileProvider in your manifest:

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

Example file_paths.xml:

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

Replace "name" and "path" as appropriate.

To give the PDF viewer access to the file, you also have to add the FLAG_GRANT_READ_URI_PERMISSION flag to the intent:

private void displayPdf(String fileName) {
    Uri uri = getFileUri(this, fileName);

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(uri, "application/pdf");

    // FLAG_GRANT_READ_URI_PERMISSION is needed on API 24+ so the activity opening the file can read it
    intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_GRANT_READ_URI_PERMISSION);

    if (intent.resolveActivity(getPackageManager()) == null) {
        // Show an error
    } else {
        startActivity(intent);
    }
}

See the FileProvider documentation for more details.

Milliemillieme answered 9/8, 2019 at 18:46 Comment(0)
D
8
String dir="/Attendancesystem";

 public void displaypdf() {

        File file = null;
            file = new File(Environment.getExternalStorageDirectory()+dir+ "/sample.pdf");
        Toast.makeText(getApplicationContext(), file.toString() , Toast.LENGTH_LONG).show();
        if(file.exists()) {
            Intent target = new Intent(Intent.ACTION_VIEW);
            target.setDataAndType(Uri.fromFile(file), "application/pdf");
            target.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

            Intent intent = Intent.createChooser(target, "Open File");
            try {
                startActivity(intent);
            } catch (ActivityNotFoundException e) {
                // Instruct the user to install a PDF reader here, or something
            }
        }
        else
            Toast.makeText(getApplicationContext(), "File path is incorrect." , Toast.LENGTH_LONG).show();
    }
Dael answered 13/5, 2015 at 13:2 Comment(1)
Use above code,when your file is stored in internal storage.Dael
U
2

Kotlin version below (Updated version of @paul-burke response:

fun openPDFDocument(context: Context, filename: String) {
    //Create PDF Intent
    val pdfFile = File(Environment.getExternalStorageDirectory().absolutePath + "/" + filename)
    val pdfIntent = Intent(Intent.ACTION_VIEW)
    pdfIntent.setDataAndType(Uri.fromFile(pdfFile), "application/pdf")
    pdfIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)

    //Create Viewer Intent
    val viewerIntent = Intent.createChooser(pdfIntent, "Open PDF")
    context.startActivity(viewerIntent)
}
Unexceptional answered 21/1, 2019 at 3:32 Comment(0)
G
1

The reason you don't have permissions to open file is because you didn't grant other apps to open or view the file on your intent. To grant other apps to open the downloaded file, include the flag(as shown below): FLAG_GRANT_READ_URI_PERMISSION

Intent browserIntent = new Intent(Intent.ACTION_VIEW);
browserIntent.setDataAndType(getUriFromFile(localFile), "application/pdf");
browserIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|
Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(browserIntent);

And for function:

getUriFromFile(localFile)

private Uri getUriFromFile(File file){
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        return Uri.fromFile(file);
    }else {
        return FileProvider.getUriForFile(itemView.getContext(), itemView.getContext().getApplicationContext().getPackageName() + ".provider", file);
    }
}
Gaffrigged answered 21/2, 2021 at 17:43 Comment(0)
L
1

Want to chime in with the answers above. The code is nearly identical, except it's in an Android Jetpack Compose composable (and therefore in Kotlin). That, and I did two videos talking through it. Here's the happy path version, (clocking in at 10 minutes).

For the whole hog, this behemoth 30 minute screenshow has me provide a significant amount of context and a/b options of the code.

If you want to see the code, you can find it in this repo branch.

Leopoldoleor answered 25/8, 2021 at 4:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.