【问题标题】:FileUriExposedException in Android [duplicate]Android中的FileUriExposedException [重复]
【发布时间】:2018-10-08 21:41:02
【问题描述】:

我需要在内部存储中打开包含图像的文件夹。

我使用以下代码。

Java

 File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),  "MyPhotos");
Intent intent = new Intent(Intent.ACTION_VIEW);
String path =folder.getPath();
Uri myImagesdir = Uri.parse("file://" + path );
intent.setDataAndType(myImagesdir,"*/*");   
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

路径

 <paths xmlns:android="http://schemas.android.com/apk/res/android">
     <external-path name="images" path="Pictures" />
     <external-path name="external_files" path="."/>
     <external-path name="files_root" path="Android/data/${applicationId}"/> </paths>

清单

  <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.android.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

xml/file_paths

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="images" path="Pictures" />
    <external-path name="external_files" path="."/>
    <external-path name="files_root" path="Android/data/${applicationId}"/>
</paths>

错误

致命异常:主进程:android.apps.bnb.company.myphotos,PID: 22482 android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/MyPhotos 暴露在应用程序之外 通过 Intent.getData()

还有其他方法可以打开内部存储中的文件夹吗?谢谢!

更新 #1

使用这篇文章https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en我替换了

Uri myImagesdir = Uri.parse("file://" + path );

 Uri myImagesdir = Uri.parse("content://" + path );

错误消失了。

无论如何我必须选择总是应用程序来打开这个文件夹。

是否可以默认使用“我的文件”应用打开某个文件夹?

【问题讨论】:

  • 应该更改 Uri 访问权限。查看this答案。
  • @vvy 嗨!是intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);线吗?
  • @SahilKumar 嗨!正是我在发布我的问题之前所做的。我从那里拿了这条线intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  • Is it possibility to use My Files app by default to open certain folder? 你想达到什么目的?能详细点吗?

标签: java android android-intent directory


【解决方案1】:

是否可以默认使用“我的文件”应用打开某个文件夹?

是和否。它不能 100% 保证它适用于所有设备。

编辑 1:

跟随是可以做到的方式之一。我已经在几个模拟器(运行 Android N 和 Android O)上进行了测试并加载了默认文件资源管理器:

MainActivity.java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri dirUri = FileProvider.getUriForFile(this,getApplicationContext().getPackageName() + ".com.example.myapplication",Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        //intent.setDataAndtType(); I will change this value in the alternatives below
    }

AndroidManifest.xml

<provider
        android:name=".GenericFileProvider"
        android:authorities="${applicationId}.com.example.myapplication"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
</provider>

GenericFileProvider.java

public class GenericFileProvider extends FileProvider {
}

file_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>

上述方法不适用于三星这样的大公司

替代方案

1.使用类型DocumentsContract.Document.MIME_TYPE_DIR

intent.setDataAndType(dirUri,DocumentsContract.Document.MIME_TYPE_DIR);

这种方法适用于多个模拟器和有限的设备集。它不适用于三星或华为等大公司。

2。使用类型resource/folder

intent.setDataAndType(dirUri,"resource/folder");

此方法仅在用户安装了 ES 文件浏览器应用时才有效。

如果你选择使用 ,那么你必须检查是否有任何意图可以通过使用来处理它:

PackageManager packageManager = getActivity().getPackageManager();

if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent);
} else {
   // either display error or take necessary action
}

3.使用类型*/*

intent.setDataAndType(dirUri,"*/*");

如果用户从意图选择器中选择文件管理器应用程序并将其标记为默认应用程序以处理*/*,则此方法有效。但是它有一些缺点(感谢@CommonsWare 带来了一些缺点):

  • 此类型将加载设备上的所有应用程序,并允许用户选择其中一个来完成操作。
  • 如果没有文件资源管理器并且用户选择其他应用程序来加载您的意图,那么其他应用程序将崩溃或只是显示黑屏。例如。如果您使用 Gallery 或其他应用程序而不是文件资源管理器来启动它,那么 Gallery 应用程序将崩溃或显示黑屏。
  • 即使有文件浏览器但用户决定使用其他应用程序,其他应用程序也可能崩溃

4.使用类型text/csv

intent.setDataAndType(uri, "text/csv")

这将限制向用户显示的应用程序的数量,但在应用 */* 时的限制相同。会显示可以处理csv 的应用,如果用户选择它,应用会崩溃。

@Academy of Programmer 提到了一些设备特定的实现here,这需要识别默认文件管理器的意图和额外的需求。

结论:

目前没有可用的标准类型来实现它,因为文件管理器没有遵循标准来支持特定类型。未来可能谷歌会想出一些办法。最好的选择是实现您自己的文件管理器,就像 Dropbox 或 Google Drive 一样。有几个库可提供此功能。

【讨论】:

  • Android 设备不需要“默认文件浏览器应用”,更不用说可以处理由文件系统目录支持的content Uri 了。
  • @CommonsWare 好吧,如果没有可用的默认文件资源管理器,则会提示用户从可以处理它的现有应用程序中进行选择
  • 其中许多应用程序会崩溃,因为它们会期望 content Uri 指向一个流。你的没有任何意义。
  • 比如我把你的代码放到了一个废品项目中。我添加了您的答案中未提及的依赖项和 &lt;uses-permission&gt; 元素。我在 Nexus 5X 上运行它。您的startActivity() 电话提供了大约 15 个应用程序,除了我尝试过的应用程序之外,所有应用程序都崩溃或出现内部错误。那是因为您的 Intent 将引入 PDF 查看器、图像查看器和各种其他应用程序。
  • @CommonsWare 你是对的,我尝试使用其他应用程序打开它,其中一些崩溃
【解决方案2】:

我使用以下代码从存储中打开图像:

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

File path = new File(Environment.getExternalStorageDirectory() + "/" + "ParentDirectory" + "/" + "ChildDirectory");

File filepath = new File(path + "/" + yourImageName.png);

Uri uri = Uri.fromFile(filepath);

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/jpeg");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

编辑答案:

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

File path = new File(Environment.getExternalStorageDirectory() + "/" + "ParentDirectory" + "/" + "ChildDirectory");

Uri uri = Uri.fromFile(path);

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/jpeg");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

【讨论】:

  • 嗨!嗯......它可以工作,但仍然有(1)选择应用程序打开文件(2)导航到内部存储图片文件夹。任何线索如何避免它?谢谢!
  • 您是否在清单中添加了提供程序?
  • 当然。请重新检查我更新的答案。谢谢!
  • 请检查编辑的答案,它可以帮助你..
【解决方案3】:

我在这里找到了解决方案 can we open download folder via. intent?

此代码在我的三星 J7 中完美运行,可以使用三星默认应用程序我的文件从内存中打开图片文件夹(和其他文件夹)。

File path = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
Uri uri = Uri.fromFile(path);
Intent intent = getPackageManager().getLaunchIntentForPackage("com.sec.android.app.myfiles");
intent.setAction("samsung.myfiles.intent.action.LAUNCH_MY_FILES");
                    intent.putExtra("samsung.myfiles.intent.extra.START_PATH", path.getAbsolutePath());
startActivity(intent);

好像要反编译各个厂商的文件管理器才能正确调用。 :( 而且工作量太大。嗯...我认为有一些通用的解决方案可以做到这一点。

【讨论】:

    猜你喜欢
    • 2017-12-02
    • 2017-01-07
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 2020-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多