通过ClipData.Item.getUri在应用程序之外公开


99

我尝试在Android文件系统中添加新功能后解决问题,但出现此错误:

android.os.FileUriExposedException: file:///storage/emulated/0/MyApp/Camera_20180105_172234.jpg exposed beyond app through ClipData.Item.getUri()

所以我希望有人可以帮助我解决这个问题:)

谢谢

private Uri getTempUri() {
    // Create an image file name
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    String dt = sdf.format(new Date());
    imageFile = null;
    imageFile = new File(Environment.getExternalStorageDirectory()
            + "/MyApp/", "Camera_" + dt + ".jpg");
    AppLog.Log(
            TAG,
            "New Camera Image Path:- "
                    + Environment.getExternalStorageDirectory()
                    + "/MyApp/" + "Camera_" + dt + ".jpg");
    File file = new File(Environment.getExternalStorageDirectory() + "/MyApp");
    if (!file.exists()) {
        file.mkdir();
    }
    imagePath = Environment.getExternalStorageDirectory() + "/MyApp/"
            + "Camera_" + dt + ".jpg";
    imageUri = Uri.fromFile(imageFile);
    return imageUri;
}

Answers:


166

对于sdk 24及更高版本,如果您需要在应用程序存储之外获取文件的Uri,则会出现此错误。
@ eranda.del解决方案使您可以更改策略以允许此操作,并且效果很好。

但是,如果您想遵循Google指南而不必更改应用程序的API政策,则必须使用FileProvider。

首先,要获取文件的URI,需要使用FileProvider.getUriForFile()方法:

Uri imageUri = FileProvider.getUriForFile(
            MainActivity.this,
            "com.example.homefolder.example.provider", //(use your app signature + ".provider" )
            imageFile);

然后,您需要在android清单中配置您的提供程序:

<application>
  ...
     <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.homefolder.example.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <!-- ressource file to create -->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths">  
        </meta-data>
    </provider>
</application>

(在“机构”中,使用与getUriForFile()方法的第二个参数相同的值(应用程序签名+“ .provider”))

最后,您需要创建资源文件:“ file_paths”。该文件需要在res / 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>

78
“让开发人员的生活更轻松”-这是每个新API的口号,对Google来说正确吗?
Kirill Karmazin

12
布伦登(Brendon)提供的解决方案是正确的解决方案,但尚未准备好复制粘贴,因此您需要检查其是否适合您的需要。<external-path ...当您需要Environment.getExternalStorageDirectory()时使用。并<files-path ...在需要Context.getFilesDir()时使用。:你最好先检查一下官方的文档developer.android.com/reference/android/support/v4/content/...
基里尔·卡尔马津

9
提醒您,如果您使用的是androidx(新的支持名称空间),则可以在此处找到相应的文档(developer.android.com/reference/androidx/core/content/…)。
Rodrirokr

19
需要注意的是在androidx它是:android:name="androidx.core.content.FileProvider"
smörkex

150

在开始摄像头或文件浏览之前添加以下代码块

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

请参考引荐链接严格模式及其解释的所有用法和技术细节。


24
解决此问题的方法不正确,这将基本上删除严格模式策略。并将忽略安全警告
Ahsan Zaheer,

有一些利弊。请参考以下内容以获取更多信息 stackoverflow.com/questions/18100161/…–
eranda.del

它有效,如果有任何退缩,请让我知道:)
Hanan

该代码为我解决了异常。但是,此处的最高注释指出代码不是解决此问题的正确方法。有谁知道正确的方法是什么?
Shn_Android_Dev '19

Google讨厌程序员。
Joubert Vasconcelos

0

不允许将必需的提供程序配置配置到AndroidManifest中,仅允许“摄像头和存储”权限。使用以下代码启动相机:

final int REQUEST_ACTION_CAMERA = 9;
void openCamra() {
Intent cameraImgIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

cameraImgIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID +".provider",
                new File("your_file_name_with_dir")));
startActivityForResult(cameraImgIntent, REQUEST_ACTION_CAMERA);
}

捕获图像后,您可以在以下位置找到捕获的图像:

"your_file_name_with_dir"

最好说明一下AndroidManifest中provider的配置,而不是给出其他代码。
fury.slay
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.