作为一个java后端程序员,我是怎么接手android项目,并完成移动端的pdf处理需求的?

    技术2026-06-15  9

    本篇文章核心:Android调用第三方应用,打开pdf文件 作为一个纯的java后端程序员,最近因为公司需要,不得不暂时负责维护一个android项目。 现在项目到了需要修改的时候了。 App功能涉及到预览pdf,并且还要支持添加注释、书签、查看文档目录等功能,需求还能更复杂一些吗?对于一个纯的java后端程序员来讲,大概很少有更难受的事情了,我太难了。 所以最后我选择了跟我的领导大吵一架,接着愤而辞职!!!来表达我的不满!!! 至于为什么会有这篇文章,哼哼… … 此时… …我想你已经猜到答案了。 什么?你没猜到?那先容我卖个关子,在文章最后,再讲为什么有这篇文章。

    现在,先进入主题。讲一讲android怎么调用第三方应用打开pdf文件。

    当然,你肯定早就在其他地方看到解决方法了,并且他们还提供了各种Intent,比如调用播放mp3的应用,播放mp4的应用,查看图片的应用等等。 这么一讲,我写这篇文章不是显得很鸡肋吗,直接转载别人的文章,不是更轻松吗? 绝对不是!作为一个“资(菜)深(鸡)”的android程序员,我列出了写代码的过程中遇到的所有问题,和思考问题的一些方式,以及解决方案。 其中包括困扰了我这个“大牛”两天的问题。

    调用第三方应用打开pdf文件,也有两种方式。

    方式一

    列出所有能打开pdf的应用,让用户选择一个应用打开。 首先贴出实现效果:

    主要代码如下:

    Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); Uri uri = Uri.fromFile(new File(path)); intent.setDataAndType(uri, "application/pdf"); startActivity(intent);

    你很容易就能在其他博客中看到这种方式对不对?但是在android7.0以上的系统中使用就会有问题了,报错信息如下:android.os.FileUriExposedException: file:///xxx.pdf exposed beyond app through Intent.getData()

    这是因为Android7.0 以上,对于权限相关控制更为严格,更何况笔者是基于android9.0系统进行开发,所以需要按照如下方式做一些配置。

    1.在 res目录下创建provider_paths.xml

    2.provider_paths.xml内容

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

    3. AndroidManifest.xml 添加节点

    <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:roundIcon="@drawable/ic_launcher" android:supportsRtl="true" android:theme="@style/Theme.AppCompat.Light.NoActionBar" android:usesCleartextTraffic="true"> … … <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> </application>

    4.获取uri方式修改

    //Uri uri = Uri.fromFile(new File(path)); Uri 获取方式从上面的代码替换为下面 Uri uri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", new File(path));

    5.提供完整代码

    Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION ); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); Uri uri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", new File(path)); intent.setDataAndType(uri, "application/pdf"); startActivity(intent);

    注意此处,Intent的Flags设置。必须给予读的权限,否则会出现”pdf损坏,无法打开”的提示。 否则出现”pdf损坏,不能读取“。

    方法二

    指定应用启动。即,用户不需要选择,默认使用我们选择的pdf阅读器打开。 同样需要按方法一种的前两步,添加provider_paths.xml,修改AndroidManifest.xml 贴出主要代码:

    Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setPackage("com.buildtoconnect.pdfreader"); intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION ); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); //7.0 兼容 Uri uri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".provider", new File(path)); intent.setDataAndType(uri, "application/pdf"); startActivity(intent);

    最主要的代码是这一行:

    intent.setPackage("com.buildtoconnect.pdfreader");

    设置要使用的pdf阅读器的包名,此处我使用的是17pdf阅读器。如果使用adobe的pdf阅读器,它的包名为“com.adobe.reader”,关于包名的获取,可以使用反编译,也可以利用安卓的api,获取手机中安装的应用,遍历查找,建议自行搜索。网上这类的文章很多,笔者是使用的反编译的方式获取的。

    到此,使用第三方应用打开pdf的两种方式介绍完毕。具体使用哪一种根据各自的业务需求决定。 但是!! 等等… …毕竟说了当前属于“资(菜)深(鸡)”android程序员,事情怎么会如此顺利?? 简单测试后发现,果然还有问题!!! 什么情况,为什么不能添加注释?不能添加书签? 还有这个… …流文件?

    于是,我陷入了深深的沉思。开始“全网搜”历程,诸如“android使用第三方应用打开pdf 不能编辑?”、“android使用第三方应用打开pdf 不能添加注释?” 这一沉思,就是两天,在这期间,我注意到一个细节。看图:

    没错,文件名发生了变化,“软件测试计划.pdf”在阅读器中打开,变成了“122333444.pdf”。 所以我推断出,用这种方式打开pdf,实际上不是打开的原文件,而是生成了一个临时文件,且是只读的临时文件。 这里顺带提一下,这个问题不是pdf阅读器本身的问题,因为在adobe中,用这种方式打开,同样不能编辑,提示“受保护的文件,不能执行操作”。

    接下来就是黑暗的全网搜时段,甚至最后我都要放弃了,打算自己尝试做应用内打开算了,不然就陷入了无底洞呀。

    就在这时候,我翻到一篇博客(博客地址忘记记录啦),提到另一种方式,处理android.os.FileUriExposedException: file:///xxx.pdf exposed beyond app through Intent.getData() 异常。 于是我尝试了以下写法,并且最终问题解决,附上主要源码

    //使用17pdf阅读器 打开pdf com.buildtoconnect.pdfreader Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setPackage("com.buildtoconnect.pdfreader"); intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION ); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); File pdfFile = new File(path); if(!pdfFile.exists()){ Toast.makeText(getApplicationContext(), "pdf文件不存在!", Toast.LENGTH_SHORT).show(); return; } //7.0 兼容 Uri uri = Uri.fromFile(new File(path)); StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); intent.setDataAndType(uri, "application/pdf"); startActivity(intent);

    就是这一段:

    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());

    前后折腾了两天,总算是搞定了。

    最后,如果只是预览pdf,并且需要在应用内打开pdf,推荐使用github上面的一个开源库PdfViewer,项目地址: https://github.com/barteksc/AndroidPdfViewer 使用比较简单,比较容易实现功能。 如果需要在应用内打开pdf,建议可以参考这篇文章:android 在线预览pdf文件(目前最全)

    咳咳,现在揭晓谜底的时候到了。为什么还有这篇文章了? 当然是因为我对技术孜孜不倦的钻研态度,即便是已经离职,还是要把问题解决了!! ???不信。 好吧,辞职当然不能随便辞的,文章开头就随便一说,既然接了项目,还是得做才行。哈哈哈… …

    Processed: 0.009, SQL: 9