Java Android 中的 FileUriExposedException
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50072638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
FileUriExposedException in Android
提问by Developer
I need to open folder in internal storage that contains images.
我需要在包含图像的内部存储中打开文件夹。
I use following code.
我使用以下代码。
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
路径
<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>
Manifest
显现
<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
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>
ERROR
错误
FATAL EXCEPTION: main Process: android.apps.bnb.company.myphotos, PID: 22482 android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/MyPhotos exposed beyond app through Intent.getData()
致命例外:主进程:android.apps.bnb.company.myphotos,PID:22482 android.os.FileUriExposedException:file:///storage/emulated/0/Pictures/MyPhotos 通过 Intent.getData() 暴露在应用程序之外
Is any another way to open folder in internal storage? Thanks!
有没有其他方法可以打开内部存储中的文件夹?谢谢!
UPDATE #1
更新 #1
Using this arcticle https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/enI replaced
Uri myImagesdir = Uri.parse("file://" + path );
with
和
Uri myImagesdir = Uri.parse("content://" + path );
And the error gone.
错误消失了。
Anyway I have to choose always app to open this folder.
无论如何,我必须选择始终应用程序来打开此文件夹。
Is it possibility to use My Files app by default to open certain folder?
默认情况下是否可以使用“我的文件”应用程序打开某个文件夹?
采纳答案by Developer
I found solution here can we open download folder via. intent?
我在这里找到了解决方案,我们 可以通过以下方式打开下载文件夹吗?意图?
This code works perfect in my Samsung J7 to open Pictures folder (and others) from internal memory using Samsung default application My files.
此代码在我的三星 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);
It seems like we have to decompile File Managerof each manufacturer to see how to call it properly. :( And it is too much work. Well... I assumed there is some generic solution to do it.
好像要反编译各个厂商的文件管理器,看看如何正确调用。:( 而且工作量太大了。好吧......我认为有一些通用的解决方案可以做到这一点。
回答by Shiva Snape
The Below Code is used by me to open an image from Storage :
我使用以下代码从 Storage 打开图像:
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);
Edited Answer :
编辑答案:
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);
回答by Sagar
Is it possibility to use My Files app by default to open certain folder?
默认情况下是否可以使用“我的文件”应用程序打开某个文件夹?
Yes & No. Its not 100% guaranteed that it will work on all devices.
是和否。它不能 100% 保证它适用于所有设备。
Edit 1:
编辑1:
Following is one of the way with which it can be done. I have tested on few emulators (running Android N & Android O) and loads default file explorer:
以下是可以完成的方法之一。我已经在几个模拟器(运行 Android N 和 Android O)上进行了测试并加载了默认的文件资源管理器:
MainActivity.java
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
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
GenericFileProvider.java
public class GenericFileProvider extends FileProvider {
}
file_paths.xml
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>
The above approach doesn't work on big players like samsung
上述方法不适用于像三星这样的大公司
Alternatives
备择方案
1. Using type DocumentsContract.Document.MIME_TYPE_DIR
1.使用类型 DocumentsContract.Document.MIME_TYPE_DIR
intent.setDataAndType(dirUri,DocumentsContract.Document.MIME_TYPE_DIR);
intent.setDataAndType(dirUri,DocumentsContract.Document.MIME_TYPE_DIR);
This approach works on several emulators and limited set of devices. It doesn't work with big players like Samsung or Huawei.
这种方法适用于多个模拟器和有限的一组设备。它不适用于三星或华为等大公司。
2. Using type resource/folder
2. 使用类型 resource/folder
intent.setDataAndType(dirUri,"resource/folder");
intent.setDataAndType(dirUri,"resource/folder");
This approach works only if user has installed ES file explorer app.
此方法仅在用户已安装 ES 文件浏览器应用程序时才有效。
If you choose to use , then you have to check if any intent is available to handle it by using:
如果您选择使用 ,那么您必须使用以下方法检查是否有任何意图可以处理它:
PackageManager packageManager = getActivity().getPackageManager();
PackageManager packageManager = getActivity().getPackageManager();
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent);
} else {
// either display error or take necessary action
}
3. Using type */*
3. 使用类型 */*
intent.setDataAndType(dirUri,"*/*");
intent.setDataAndType(dirUri,"*/*");
This approach works, if user chooses File Manager app from the Intent Chooser and mark it as default app to handle */*
. However it has some drawbacks (Thanks to @CommonsWare for bringing some of it out):
如果用户从意图选择器中选择文件管理器应用程序并将其标记为默认应用程序来处理*/*
. 但是它有一些缺点(感谢@CommonsWare 带来了一些):
- This type will load all the apps on the device and allow user to choose one of them to complete the action.
- If there is no file explorer and user chooses other apps to load your intent, then the other app will crash or simply show black screen. E.g. You use Gallery or some other app to launch it rather than file explorer, then Gallery app will either crash or show black screen.
- Even if there is file explorer but user decides to use other apps, the other apps could crash
- 这种类型将加载设备上的所有应用程序,并允许用户选择其中一个来完成操作。
- 如果没有文件资源管理器并且用户选择其他应用程序来加载您的意图,那么其他应用程序将崩溃或只是显示黑屏。例如,您使用图库或其他应用程序启动它而不是文件浏览器,那么图库应用程序将崩溃或显示黑屏。
- 即使有文件浏览器但用户决定使用其他应用程序,其他应用程序也可能崩溃
4. Using type text/csv
4. 使用类型 text/csv
intent.setDataAndType(uri, "text/csv")
intent.setDataAndType(uri, "text/csv")
This will limit the number of apps which will displayed to the user but same limitations when */*
used is applied. Apps which can handle csv
will be displayed and if user chooses it then the apps would crash.
这将限制向用户显示的应用程序数量,但在*/*
使用时应用相同的限制。csv
将显示可以处理的应用程序,如果用户选择它,则应用程序将崩溃。
There are some device specific implementations available hereas mentioned by @Academy of Programmerwhich requires to identify the default file manager's intent and extra's need by it.
正如@Academy of Programmer所提到的,这里有一些特定于设备的实现可用,它需要识别默认文件管理器的意图和它的额外需求。
Conclusion:
结论:
There is no standard type available to achieve it since there is no standard followed by the File Managers to support specific type at the moment. In future may be Google will come up with some approach. Best alternative would be to implement your own file manager just like Dropbox or Google Drive does. There are several libraries available which provide this feature.
没有可用的标准类型来实现它,因为目前没有文件管理器遵循的标准来支持特定类型。未来可能谷歌会想出一些办法。最好的选择是像 Dropbox 或 Google Drive 一样实现自己的文件管理器。有几个可用的库提供此功能。