Android中的FileUriExposedException

时间:2018-04-28 03:46:51

标签: java android android-intent directory

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

我使用以下代码。

爪哇

 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

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

错误

  

FATAL EXCEPTION:主程序:android.apps.bnb.company.myphotos,PID:   22482                     android.os.FileUriExposedException:file:/// storage / emulated / 0 / Pictures / MyPhotos暴露在app之外   通过Intent.getData()

是否有其他方法可以在内部存储中打开文件夹?谢谢!

更新#1

使用此arcticle 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 );

错误消失了。

无论如何,我必须总是选择app来打开这个文件夹。

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

3 个答案:

答案 0 :(得分:8)

  

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

是&amp;不。它不是100%保证它可以在所有设备上运行。

修改1:

以下是可以做到的一种方式。我已经在少数仿真器(运行Android N&amp; 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,"*/*");

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

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

<强> 4。使用类型text/csv

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

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

@Academy of Programmer 提到了一些特定于设备的实现here,这需要通过以下方式确定默认文件管理器的意图和额外需求它

结论:

没有标准类型可用于实现它,因为目前没有标准文件管理器支持特定类型。将来谷歌可能会拿出一些方法。最好的替代方案是像Dropbox或Google Drive一样实现自己的文件管理器。有几个库提供此功能。

答案 1 :(得分: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);

答案 2 :(得分:1)

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

此代码在我的Samsung 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);

似乎我们必须对每个制造商的文件管理器进行反编译,以了解如何正确调用它。 :(而且工作太多了。嗯......我认为有一些通用的解决方案可以做到。