Intent.ACTION_SEND定位到API级别24 +

时间:2018-07-22 06:41:29

标签: java android

尝试发送具有Intent的文件时,出现android.os.StrictMode.onFileUriExposed异常。据我了解,这是因为我定位到24>并且不再支持file://,应使用content://

首先,我想说的是,我曾经见过类似的问题,例如thisthis,也看到过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

2 个答案:

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