Android打开pdf文件

Posted

技术标签:

【中文标题】Android打开pdf文件【英文标题】:Android open pdf file 【发布时间】:2013-07-01 10:40:43 【问题描述】:

我正在开发一个 android 应用程序,我必须打开一些文件。

这是我使用意图的代码:

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

文件在SD卡的根目录下,可以手动打开。

问题

应用程序在到达 startActivity(intent) 时关闭。我认为问题出在 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)

你能帮我完成 AndroidManifest 吗?或者我怎样才能打开那个pdf?

【问题讨论】:

你的安卓似乎没有安装任何pdf阅读器应用,添加一个 我可以使用 ThinkFree PDF Viewer 打开其他 pdf 文件。 如果您尝试使用ContentProvider(现在推荐),这篇博文会有所帮助:blogc.at/2014/03/23/… 【参考方案1】:

问题是没有安装应用程序来处理打开 PDF。您应该使用 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
   

【讨论】:

我在手机上试过了。当我打开另一个应用程序的一些 pdf 文件时,它说要注册 ThinkFree,我说“稍后”并且“ThinkFree PDF Viewer Mobile for Android”已打开,向我显示 pdf 文件。使用您的代码,它只会要求 ThinkFree 注册。如果我说“稍后”,它就会关闭。 这与这段代码无关。您无法控制 ThinkFree 处理此意图的方式。尝试安装替代 PDF 查看器。 谢谢,没关系。还有一件事......当我关闭 pdf 文件(使用手机的后退按钮)时,我的应用程序因错误而关闭。我该如何解决? 您使用的是startActivity(Intent) 还是startActivityForResult(Intent, int)?我得看看你在onResume()onActivityResult(int, int, Intent) 做什么。错误是什么? 我使用 Intent intent = new Intent(this, FacturaActivity.class);开始活动(意图);我没有在 onResume() 中写任何东西。错误是:“抱歉!应用程序###(进程 com.###)已意外停止。请重试。[强制关闭]”它返回到另一个先前的活动(不是处理 pdf 查看器的活动)任何应该有的数据。我想返回与 PDF 查看器的 startActivity 相同的 Activity。【参考方案2】:

从 API 24 开始,将 file:// URI 发送到另一个应用程序将引发 FileUriExposedException。相反,使用 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);

您还必须在清单中定义 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>

示例 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>

酌情替换“名称”和“路径”。

要让 PDF 查看器访问该文件,您还必须将 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);
    

有关详细信息,请参阅FileProvider documentation。

【讨论】:

【参考方案3】:
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();
    

【讨论】:

使用上述代码,当您的文件存储在内部存储中时。【参考方案4】:

以下 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)

【讨论】:

【参考方案5】:

您无权打开文件的原因是您没有授权其他应用按您的意图打开或查看文件。要授予其他应用程序打开下载的文件,请包含标志(如下所示):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);

对于函数:

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

【讨论】:

【参考方案6】:

想附和上面的答案。代码几乎相同,只是它在 Android Jetpack Compose 可组合(因此在 Kotlin 中)。那,我做了两个视频来讨论它。 这是happy path version,(10 分钟打卡)。

对于整个猪来说,这个 behemoth 30 minute screenshow 让我提供了大量的上下文和代码的 a/b 选项。

如果你想看代码,可以在this repo branch找到。

【讨论】:

以上是关于Android打开pdf文件的主要内容,如果未能解决你的问题,请参考以下文章

Android打开pdf文件

android怎么实现在线查看pdf文档

PDF文件未在颤动的android发行版中打开[关闭]

Android 如何本地加载pdf文件

Android:如何在 android 中从服务器打开 pdf 文件 [关闭]

在android模拟器上打开外部PDF文件