当我尝试打开文件时,应用程序崩溃了 . 它可以在Android Nougat下运行,但在Android Nougat上它会崩溃 . 当我尝试从SD卡打开文件而不是从系统分区打开文件时,它只会崩溃 . 一些许可问题?
示例代码:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
日志:
android.os.FileUriExposedException:file:///storage/emulated/0/test.txt通过Intent.getData()暴露在app之外
Edit:
在定位Android Nougat时,不再允许 file://
URI . 我们应该使用 content://
URI . 但是,我的应用程序需要在根目录中打开文件 . 有任何想法吗?
17 回答
https://stackoverflow.com/a/38858040/395097这个答案已经完成 .
这个答案适用于 - 您已经有一个目标低于24的应用程序,现在您正在升级到targetSDKVersion> = 24 .
在Android N中,仅更改了暴露给第三方应用程序的文件uri . (不是我们之前使用它的方式) . 所以只改变你与第三方应用程序共享路径的地方(在我的情况下为Camera)
在我们的应用程序中,我们将uri发送到相机应用程序,在该位置,我们期望相机应用程序存储捕获的图像 .
对于android N,我们生成新的Content://基于uri的url指向文件 .
我们生成相同的基于File api的路径(使用旧方法) .
现在我们有2个不同的uri用于同一个文件 . #1与相机应用共享 . 如果摄像头意图成功,我们可以从#2访问图像 .
希望这可以帮助 .
如果
targetSdkVersion
高于 24 ,则FileProvider用于授予访问权限 .创建一个xml文件(路径:res \ xml) provider_paths.xml
在 AndroidManifest.xml 中添加 Provider
和 replace
至
你很高兴 . 希望能帮助到你 .
首先,您需要为AndroidManifest添加提供程序
现在在xml资源文件夹中创建一个文件(如果使用android studio,你可以在突出显示file_paths后点击Alt Enter并选择创建一个xml资源选项)
接下来在file_paths文件中输入
此示例适用于外部路径,您可以参考here以获取更多选项 . 这将允许您共享该文件夹及其子文件夹中的文件 .
现在剩下的就是按如下方式创建意图:
EDIT :我在file_paths中添加了sd卡的根文件夹 . 我已经测试了这段代码,但确实有效 .
除了使用
FileProvider
的解决方案之外,还有另一种方法可以解决这个问题 . 简单的说在
Application.onCreate()
. 这样,VM会忽略文件URI
曝光 .Method
启用文件曝光检查,如果我们不设置VmPolicy,这也是默认行为 .
我遇到了一个问题,如果我使用
content://
URI
发送内容,有些应用程序根本无法理解它 . 并且不允许降级target SDK
版本 . 在这种情况下,我的解决方案很有用Update:
正如评论中所提到的,StrictMode是诊断工具,不应该用于此问题 . 当我在一年前发布此答案时,许多应用程序只能接收文件uris . 当我尝试向他们发送FileProvider uri时,它们就崩溃了 . 这在大多数应用程序中已得到修复,因此我们应该使用FileProvider解决方案 .
如果您的
targetSdkVersion
是24或更高,you can not use file: Uri values in Intents on Android 7.0+ devices .你的选择是:
将
targetSdkVersion
降至23或更低,或将您的内容放在内部存储上,然后use FileProvider使其有选择地提供给其他应用程序
例如:
(来自this sample project)
在我的情况下,我通过用
SetData
替换SetDataAndType
来摆脱异常 .我的解决方案是将文件路径'Uri.parse'作为字符串,而不是使用Uri.fromFile() .
似乎fromFile()使用了一个文件指针,我认为当内存地址暴露给所有应用程序时,这可能是不安全的 . 但是文件路径字符串从不会伤害任何人,因此它可以在不抛出FileUriExposedException的情况下工作 .
测试API级别9到26!不需要FileProvider,也不需要Android支持库 .
如果您的应用程序针对API 24,并且您仍然需要/需要使用file:// intents,则可以使用hacky方式来禁用运行时检查:
方法
StrictMode.disableDeathOnFileUriExposure
被隐藏并记录为:问题是我的应用程序不是蹩脚的,而是不希望因使用内容而瘫痪://那些许多应用程序无法理解的意图 . 例如,使用content:// scheme打开mp3文件提供的应用程序比在file:// scheme上打开相同的应用程序要少得多 . 我不想通过限制我的应用程序的功能来支付Google的设计错误 .
谷歌希望开发人员使用内容方案,但系统并没有为此做好准备,多年来,应用程序使用文件而不是“内容”,文件可以编辑和保存,而文件服务的内容方案不能(可以他们?) .
使用fileProvider是可行的方法 . 但您可以使用这个简单的解决方法:
更换:
通过
只需在活动onCreate()中粘贴以下代码即可
它将忽略URI暴露
如果您的
targetSdkVersion >= 24
,那么我们必须使用FileProvider
类来授予对特定文件或文件夹的访问权限,以使其可供其他应用程序访问 . 我们创建自己的类继承FileProvider
,以确保我们的FileProvider不会与导入的依赖项中声明的FileProviders冲突,如here所述 .用
content://
URI替换file://
URI的步骤:FileProvider
的类<application>
标签下的AndroidManifest.xml
中添加FileProvider<provider>
标签 . 为android:authorities
属性指定唯一权限以避免冲突,导入的依赖项可能指定${applicationId}.provider
和其他常用权限 .res/xml
文件夹中创建provider_paths.xml
文件 . 如果文件夹不存在,则可能需要创建文件夹 . 该文件的内容如下所示 . 它描述了我们希望在根文件夹(path=".")
上共享对外部存储的访问,名称为 external_files .至
请参考,完整的代码和解决方案已被解释here.
我不知道为什么,我做的一切与Pkosta(https://stackoverflow.com/a/38858040)完全相同,但一直收到错误:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
我在这个问题上浪费了几个小时 . 罪魁祸首?科特林 .
intent
实际上是在设置getIntent().addFlags
而不是在我新发布的playIntent上运行 .只需在活动onCreate()中粘贴以下代码即可
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());
它将忽略URI暴露
快乐的编码:-)
@palash k答案是正确的,适用于内部存储文件,但在我的情况下我也想从外部存储打开文件,我的应用程序在从外部存储打开文件时崩溃,如sdcard和usb,但我设法通过修改来解决问题 provider_paths.xml 来自接受的答案
如下所示更改 provider_paths.xml
并在java类(没有改变,因为接受的答案只是一个小编辑)
这有助于我修复来自外部存储的文件的崩溃,希望这将帮助一些人有同样的问题,如我的:)
Xamarin.Android
Note: 路径xml / provider_paths.xml(.axml)无法解析,即使在资源下创建了xml文件夹(也许它可以放在像Values这样的现有位置,没试过),所以我求助于此这适用于现在 . 测试显示每个应用程序运行只需要调用一次(这有意义的是它改变了主机VM的运行状态) .
Note: xml需要大写,所以Resources / Xml / provider_paths.xml
我使用了Palash上面给出的答案,但它有点不完整,我必须提供这样的许可
要从服务器下载pdf,请在服务类中添加以下代码 . 希望这对你有所帮助 .
是的,不要忘记在清单中添加权限和提供程序 .