亦余心之所善兮,虽九死其犹未悔。这篇文章主要讲述android 7.0+ FileProvider 访问隐私文件 相册相机安装应用的适配相关的知识,希望能为你提供帮助。
从 android 7.0 开始,Android SDK 中的
StrictMode
策略禁止开发人员在应用外部公开
file://
URI。具体表现为,当我们在应用中使用包含
file://
URI 的 Intent 离开自己的应用时,程序会发生FileUriExposedException
异常
这里我们要使用到的
FileProvider
,就是
ContentProvider
的一个特殊子类,帮助我们将访问受限的
file://
URI 转化为可以授权共享的
content://
URI。
首先 要去 Manifest文件里注册FileProvider
< application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> < activity android:name=".MainActivity"> < intent-filter> < action android:name="android.intent.action.MAIN" /> < category android:name="android.intent.category.LAUNCHER" /> < /intent-filter> < /activity> < provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.FileProvider" //此处的属性值后面获取URI用到 android:grantUriPermissions="true" android:exported="false"> < meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> < /provider> < /application>
其次在 res 目录下新建一个 xml 文件夹 里边添加一个xml文件 名字比如:path.xml
< ?xml version="1.0" encoding="utf-8"?> < paths xmlns:android="http://schemas.android.com/apk/res/android"> < external-path name="my_images" path="."/> < !-- 此处的name可以随便取--!> < /paths>
元素必须包含一到多个子元素。这些子元素用于指定共享文件的目录路径,必须是这些元素之一:
< files-path> :内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;
< cache-path> :内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;
< external-path> :外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;
< external-files-path> :外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;
< external-cache-path> :外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();
获取URI的方法:
在Android7.0以下 获取相册图片URI的方式:
Uri uri= Uri.from ( file );
Android 7.0+获取相册图片的方式:
//注意此处的 第二个参数必须与 Manifest文件中Provider 的 android:authorities 一致
Uri contentUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".FileProvider", outputFile);
Android 7.0以下 安装应用:
Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); startActivity(installIntent);
Android 7.0+ 安装应用:
//采用FileProvider的方式访问文件
File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app_sample.apk");
Uri apkUri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID+".FileProvider", apkFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加此处 是临时对文件的授权 必须加上此句 installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive"); startActivity(installIntent);
调用相机的时候:
public void camera() { Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); tempFile = new File(Environment.getExternalStorageDirectory(),PHOTO_FILE_NAME); Uri uri; if (Build.VERSION.SDK_INT > = Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(this, "com.camera.fileprovider",tempFile);
//此处为Uri临时授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { uri = Uri.fromFile(tempFile); } intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(intent, PHOTO_REQUEST_CAMERA); }
裁剪图片:
public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) { Intent intent = new Intent("com.android.camera.action.CROP"); if (Build.VERSION.SDK_INT > = Build.VERSION_CODES.N) {
//此处为Uri临时授权 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } intent.setDataAndType(orgUri, "image/*"); //此处的Uri为 输入Uri用FileProvider的方式获取 intent.putExtra("crop", "true"); intent.putExtra("aspectX", aspectX); intent.putExtra("aspectY", aspectY); intent.putExtra("outputX", width); intent.putExtra("outputY", height); intent.putExtra("scale", true); //将剪切的图片保存到目标Uri中 intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri); //此处的Uri为输出Uri 需要用Uri.fromFile()的方式获取 intent.putExtra("return-data", false); intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); activity.startActivityForResult(intent, requestCode); }
【android 7.0+ FileProvider 访问隐私文件 相册相机安装应用的适配】
推荐阅读
- 在Termux(非root的安卓Linux模拟器)中安装和使用ftp服务器(pure-ftpd)(原创)[简单极致]
- android开发(底部导航条的实现 | navigation tab)
- android 6.0+ 动态权限获取
- android dumpsys
- android开发(android studio的下载安装与简单使用 | sdk的安装与编译)
- Android 程序结构
- 安卓Recycleview简单的网格布局-初学者的关键点
- 安卓微信中下载apk无反应 微信浏览器无法跳转到apk下载链接方案
- Android实现选择题答题(包括单选多选和答题卡)