尝试发送具有Intent的文件时,出现android.os.StrictMode.onFileUriExposed
异常。据我了解,这是因为我定位到24>并且不再支持file://
,应使用content://
。
首先,我想说的是,我曾经见过类似的问题,例如this,this,也看到过this博客文章。
但是问题是,所有帖子在拍照时都引用URI,在我的情况下,文件是使用Uri成功保存的,现在我想使用Intent发送图像,如下所示:
shareBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
Uri screenshotUri = Uri.parse("file://" + directoryToStore + "/" + filename);
//the Uri above - file:///storage/emulated/0/Android/data/myPackageName/files/SavedImages/test.jpeg
sharingIntent.setType("image/jpeg");
sharingIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
startActivity(Intent.createChooser(sharingIntent, "Share image using"));
}
});
通过上述操作,我只会在运行19>的某些设备上崩溃。在我的Samsung J7Pro(Android 7.0 API 24)上进行测试时,我没有崩溃。
我已经看到一些答案说我可以使用:
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
但这不是首选方式。
所以,我的问题是。定位24>时,我应该如何处理发送文件。我应该执行if / else语句来检查if (Build.VERSION.SDK_INT >= 19) {
之类的版本,然后对运行<24的设备使用普通的Uri,如何将file://
更改为content://
?我也不明白为什么崩溃仅发生在某些设备上。
编辑1:
我已经完成了以下建议的答案,但是文件没有故意传递,而是在尝试通过电子邮件发送图像时出现Toast
的说法,Unable to attach file
。
答案 0 :(得分:3)
从应用程序共享文件的正确方法是content provider
,尤其是FileProvider。
将您的FileProvider
添加到AnroidManifest.xml:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.MyFileProvider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/shared_paths"/>
</provider>
接下来,通过添加xml资源来添加引用的资源(Android Studio:右键单击“ app”->“新建”->“文件夹”->“ XML资源”)
然后,在这个新文件夹中创建一个名为shared_paths.xml
的xml文件(应与AndroidManifest.xml中的值匹配)。 shared_paths.xml
的内容:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="SavedImages" path="SavedImages/"/>
</paths>
编辑:每documentation将元素类型从<files-path ../>
更改为<external-path .. />
。
重要提示:更改path
属性以适合您的需求。
最后更改您的代码,如下所示:
shareBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
Uri screenshotUri = FileProvider.getUriForFile(context, context.getPackageName() + ".MyFileProvider", new File(directoryToStore, filename))
//the Uri above - file:///storage/emulated/0/Android/data/myPackageName/files/SavedImages/test.jpeg
sharingIntent.setType("image/jpeg");
sharingIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent chooserIntent = Intent.createChooser(sharingIntent, "Share image using");
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(chooserIntent);
}
});
答案 1 :(得分:1)
如果您将文件保存在内部存储器的公共媒体文件夹中(即用于图像/storage/emulated/0/DCIM/my.package.name/SavedImages/myImage.jpg),则也可以通过它共享文件-的content-media uri(用于图片内容:// media / external / images / media / 4711)。
这样,您不需要自己的FileProvider,但文件对所有人都可用。
在应用程序的私有数据目录中使用lcoal FileProvider时,该文件仅在您的应用程序中可用,并且在您卸载应用程序时将被删除。
contentprovider的目的是您可以将任何uri的内容作为inputStream读取(即,格式为“ uri =“ https://stackoverflow.com/questions/ ...”,“ file:/// storage / emulated / 0 /。 ”,“ ftp:....”,“ content:...”),只要有提供者即可。
使用api 25 Google强制禁止再使用“ file:...” uri-s