简体   繁体   English

Android 打开 pdf 文件

[英]Android open pdf file

I'm developing an Android application and I have to open some files.我正在开发一个 Android 应用程序,我必须打开一些文件。

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.文件在SD卡的根目录下,可以手动打开。

Problem问题

Application is closed when it arrives at startActivity(intent).应用程序在到达 startActivity(intent) 时关闭。 I think the problem is in AndroidManifest.xml file, but I don't know how to put it correctly.我认为问题出在 AndroidManifest.xml 文件中,但我不知道如何正确放置它。

AndroidManifest.xml 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?你能帮我完成 AndroidManifest 吗? Or how can I open that pdf?或者我怎样才能打开那个 pdf?

The problem is that there is no app installed to handle opening the PDF. 问题是没有安装应用程序来处理打开PDF。 You should use the Intent Chooser, like so: 您应该使用Intent Chooser,如下所示:

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

As of API 24, sending a file:// URI to another app will throw a FileUriExposedException. 从API 24开始,将file:// URI发送到另一个应用程序将抛出FileUriExposedException。 Instead, use FileProvider to send a content:// URI: 相反,使用FileProvider发送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: 您还必须在清单中定义FileProvider:

<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: 示例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: 要为PDF查看器提供对文件的访问权限,还必须向intent添加FLAG_GRANT_READ_URI_PERMISSION标志:

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. 有关更多详细信息,请参阅FileProvider文档

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要授权其他应用程序打开下载的文件,请包括标志(如下所示):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:对于 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);
    }
}

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).代码几乎相同,只是它位于 Android Jetpack Compose 可组合项中(因此在 Kotlin 中)。 That, and I did two videos talking through it.那,我做了两个视频来讨论它。 Here's the happy path version , (clocking in at 10 minutes).这是快乐路径版本,(10 分钟计时)。

For the whole hog, this behemoth 30 minute screenshow has me provide a significant amount of context and a/b options of the code.对于整个猪,这个庞大的 30 分钟屏幕显示让我提供了大量的上下文和代码的 a/b 选项。

If you want to see the code, you can find it in this repo branch .如果你想看代码,你可以在这个 repo 分支中找到它。

Kotlin version below (Updated version of @paul-burke response: 下面的Kotlin版本(@ paul-burke响应的更新版本:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM