当我试图打开一个文件时,应用程序崩溃了。它可以在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: ///storage/emulated/0/test.txt Intent.getData ()

编辑:

当针对Android Nougat时,file:// uri不再被允许。我们应该使用content:// uri。但是,我的应用程序需要打开根目录下的文件。什么好主意吗?


当前回答

简单地让它忽略URI暴露… 在创建之后添加它

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

其他回答

我不知道为什么,我所做的一切与Pkosta (https://stackoverflow.com/a/38858040)完全相同,但一直得到错误:

Permission Denial:从ProcessRecord{reacted} (reacted)打开提供者,而不是从uid reacted导出

我在这个问题上浪费了好几个小时。罪魁祸首吗?芬兰湾的科特林。

val playIntent = Intent(Intent.ACTION_VIEW, uri)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

intent实际上是设置getIntent()。addFlags而不是在我新声明的playIntent上操作。

我刚刚做了以下如果android版本> 24

File fl = new File(url);
    Uri uri = Uri.fromFile(fl);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    if (android.os.Build.VERSION.SDK_INT>=24)
    {
        Context context = getApplicationContext();
        uri = FileProvider.getUriForFile(
                context,
                context.getApplicationContext()
                        .getPackageName() + ".provider", fl);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    }
    intent.setDataAndType(uri, mimetype);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);

点击这个链接,然后https://medium.com/@ali.muzaffar/what-is-android-os- fileuriexposedexceptionand what-you-can-do-about-it 70b9eb17c6d0#.54odzsnk4

如果你的targetSdkVersion是24或更高,你不能在Android 7.0+设备的intent中使用file: Uri值。

你的选择是:

将targetSdkVersion降至23或更低,或者 把你的内容放在内部存储,然后使用FileProvider使它对其他应用程序有选择性地可用

例如:

Intent i=new Intent(Intent.ACTION_VIEW, FileProvider.getUriForFile(this, AUTHORITY, f));

i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(i);

(来自这个示例项目)

只需将下面的代码粘贴到Activity onCreate()中:

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

它将忽略URI公开。

如果你的应用程序目标API 24+,你仍然想要/需要使用file:// intents,你可以使用hack方法禁用运行时检查:

if(Build.VERSION.SDK_INT>=24){
   try{
      Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
      m.invoke(null);
   }catch(Exception e){
      e.printStackTrace();
   }
}

StrictMode方法。disableDeathOnFileUriExposure被隐藏并记录为:

/**
* Used by lame internal apps that haven't done the hard work to get
* themselves off file:// Uris yet.
*/

问题是我的应用程序不是蹩脚的,而是不想被使用内容://意图所削弱,这是许多应用程序无法理解的。例如,以content:// scheme打开mp3文件,提供的应用程序比打开相同的over file:// scheme时少得多。我不想为谷歌的设计缺陷买单,限制我的应用程序的功能。

谷歌希望开发者使用内容方案,但系统并没有为此做好准备,多年来应用程序都是使用文件而不是“内容”,文件可以编辑和保存,而通过内容方案提供的文件则不能(可以吗?)