android 程序 共享文件,适配Android7.0应用间文件共享FileProvider

android编译版本升级到7.0以后,会出现很多适配方面的工作,从android官方文档对于android7.0行为变更可以了解到,android7.0的应用禁止传递类似file:// URI这样的链接,否则应用会抛出FileUriExposedException异常,比较典型的场景就是我们项目中调用摄像头拍照,如果不对这个进行适配,我们按照以前的代码调用摄像头拍照的时候,会出现以下错误:

android.os.FileUriExposedException: file:///storage/emulated/0/photoTest/photo.jpeg exposed beyond app through ClipData.Item.getUri()

1.首先在项目res目录下新建xml目录,并新建file_paths.xml,这个文件主要用来配置应用共享文件的路径

name="root"

path="" />

name="files"

path="" />

name="cache"

path="" />

name="external"

path="" />

name="external_file_path"

path="" />

name="external_cache_path"

path="" />

在paths节点下支持以下几个子节点:

:代表设备的根目录new File("/")

: 代表context.getFilesDir()

: 代表context.getCacheDir()

: 代表Environment.getExternalStorageDirectory()

: 代表context.getExternalFilesDirs()

: 代表getExternalCacheDirs()

path节点支持name和path两个属性,配置了path属性就相当于在相应路径下子目录,例如:

name="external"

path="phototest" />

这样配置就代表应用可以使用Environment.getExternalStorageDirectory()/phototest 目录以及其子目录的文件

2. 在AndroidManifest.xml的application节点下增加FileProvider的声明

...

...

android:name="android.support.v4.content.FileProvider"

android:authorities="com.hua.phototest.fileprovider"

android:exported="false"

android:grantUriPermissions="true">

android:name="android.support.FILE_PROVIDER_PATHS"

android:resource="@xml/file_paths" />

3.FileProvider工具类,参考自鸿洋大神博客

public class FileProvider7 {

public static Uri getUriForFile(Context context, File file) {

Uri fileUri = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

fileUri = getUriForFile24(context, file);

} else {

fileUri = Uri.fromFile(file);

}

return fileUri;

}

private static Uri getUriForFile24(Context context, File file) {

Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(context,

context.getPackageName() + ".fileprovider",

file);

return fileUri;

}

public static void setIntentDataAndType(Context context,

Intent intent,

String type,

File file,

boolean writeAble) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

intent.setDataAndType(getUriForFile(context, file), type);

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

if (writeAble) {

intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

}

} else {

intent.setDataAndType(Uri.fromFile(file), type);

chmod("777", file.getAbsolutePath());//apk放在cache文件中,需要获取读写权限

}

}

public static void chmod(String permission, String path) {

try {

String command = "chmod " + permission + " " + path;

Runtime runtime = Runtime.getRuntime();

runtime.exec(command);

} catch (IOException e) {

e.printStackTrace();

}

}

public static void setIntentData(Context context,

Intent intent,

File file,

boolean writeAble) {

if (Build.VERSION.SDK_INT >= 24) {

intent.setData(getUriForFile(context, file));

intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

if (writeAble) {

intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

}

} else {

intent.setData(Uri.fromFile(file));

}

}

public static void grantPermissions(Context context, Intent intent, Uri uri, boolean writeAble) {

int flag = Intent.FLAG_GRANT_READ_URI_PERMISSION;

if (writeAble) {

flag |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;

}

intent.addFlags(flag);

List resInfoList = context.getPackageManager()

.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);

for (ResolveInfo resolveInfo : resInfoList) {

String packageName = resolveInfo.activityInfo.packageName;

context.grantUriPermission(packageName, uri, flag);

}

}

}

4.最后在传递URI的时候调用相应的方法获取URI即可,例如下面代码是调用摄像头拍照:

private String mTempPhotoPath;

private Uri imageUri;

private void takePhoto() {

Intent intentToTakePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

File fileDir = new File(Environment.getExternalStorageDirectory() + File.separator + "photoTest" + File.separator);

if (!fileDir.exists()) {

fileDir.mkdirs();

}

File photoFile = new File(fileDir, "photo.jpeg");

mTempPhotoPath = photoFile.getAbsolutePath();

//适配android7.0应用间文件共享

imageUri = FileProvider7.getUriForFile(this, photoFile);

intentToTakePhoto.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

startActivityForResult(intentToTakePhoto, RC_TAKE_PHOTO);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值