使用Android FileProvider将照片和视频保存到图库

时间:2017-04-06 06:46:13

标签: android security sdk

我的应用程序(使用少于24的SDK)可以使用相机拍摄照片和视频。可以在应用程序外的图库中查看照片和视频。 SDK 24及更高版本要求FileProvider创建用于将照片或视频保存到图库的uri。

在SDK 24之前,我会使用uri和意图拍照:

private void openCameraForResult(int requestCode){
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    picturesDirectoryPhotoFileName = nextFileName();
    File photoFile = makePicturesPhotoFile();
    Uri uri = Uri.fromFile(photoFile);
    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(intent, requestCode);
}

private File makePicturesPhotoFile() {
    File photoGallery = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    File media = new File(photoGallery, picturesDirectoryPhotoFileName);

    return media;
}

使用SDK 24及更高版本会发生异常:

Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Pictures/126cfd69-59c6-4534-9b2e-4af9753d3643.jpg exposed beyond app through ClipData.Item.getUri()

我想使用FileProvider实现相同(没有例外)。下面的实现可以拍摄照片,但它不会出现在图库中。我想知道我做错了什么。

的AndroidManifest.xml:

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>

provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="Pictures" path="Pictures"/>
    <external-path name="Movies" path="Movies"/>
</paths>

拍张照片:

private void openCameraForResult(int requestCode){
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    picturesDirectoryPhotoFileName = nextFileName();
    File photoFile = makePicturesPhotoFile();
    getDependencyService().getLogger().debug(photoFile.getAbsolutePath());
    Uri uri = fileProviderUri.makeUriUsingSdkVersion(photoFile);
    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(intent, requestCode);
}

制作Uri

private static final String AUTHORITY_FORMAT = "%s.fileprovider";

public  Uri makeUriUsingSdkVersion(File file) {
    Uri uri;

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
        uri = Uri.fromFile(file);
    } else {
        String packageName = getApplicationContext().getPackageName();
        String authority = String.format(Locale.getDefault(), AUTHORITY_FORMAT, packageName);
        uri = getUriForFile(getApplicationContext(), authority, file);
    }

    return uri;
}

1 个答案:

答案 0 :(得分:2)

照片出现在GT-I9300 Galaxy S3的图库中,所以我知道代码可以在该设备上运行。在Galaxy 7上,在手机开启和关闭之前,照片不会出现在图库中。

经过多天的研究,答案是使用文件上的媒体扫描更新图库。仅在PICTURES目录中创建照片是不够的。这是一个扫描单个文件的类:

import android.app.Activity;
import android.media.MediaScannerConnection;
import android.net.Uri;

import java.io.File;

class Gallery implements IGallery {

    private Activity activity;

    public Gallery(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void scanFile(File file) {
        if(activity == null || file == null) {
            return;
        }

        MediaScannerConnection.scanFile(activity,
                new String[] { file.getAbsolutePath() }, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    public void onScanCompleted(String path, Uri uri) {
                    }
                });
    }

}