1、SharedPreferences废弃共享模式,详见
2、文件共享(拍照、截图、分享、安装等),禁用file://URL格式共享文件,即无法通过Uri.fromFile(File file)获取的url进行文件共享,会发生FileUriExposedException,适配方案如下:
(1)manifest中声明FilProvider
<provider android:name="androidx.core.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>
(2)res/xml/定义共享文件路径
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="file" path=""/> <cache-path name="file" path=""/> <external-path name="external" path=""/> <external-files-path name="external-files" path=""/> <external-cache-path name="external-cache" path=""/> </paths>
注:
a、files-path:内部存储空间应用私有目录下的files目录,等同Context.getFilesDis()路径
b、cache-path:内部存储空间应用私有目录下的cache目录,等同Context.getCacheDir()路径
c、external-path:外部存储空间根目录,等同Environment.getExternalStorageDirectory()路径
d、external-files-path:外部存储空间应用私有目录下的files目录,等同Context.getExternalFilesDir()路径
e、external-cache-path:外部存储空间应用私有目录下的cache目录,等同Context.getExternalCacheDir()路径
f、name为自定义名称
g、path为相应根目录下的子路径,为空表示所有子目录
h、files-path、cache-path、external-path、external-files-path、external-cache-path同一类型可以包含多个
(3)生成content://类型Uri
FileProvider.getUriForFile(Context context, String authority, File file)
(4)给Uri授予临时权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
(5)实例:
//拍照 private fun camera(){ val intent = Intent("android.media.action.IMAGE_CAPTURE") val file = File(Environment.getExternalStorageDirectory(), "demo.png") val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", file) }else{ Uri.fromFile(file) } intent.putExtra(MediaStore.EXTRA_OUTPUT, uri) startActivityForResult(intent, REQUEST_CODE_CAMERA) } //裁剪图片 private fun cropImage(fromFile: File, toFile: File, aspectX: Int, aspectY: Int, width: Int, height: Int){ val intent = Intent("com.android.camera.action.CROP") val fromUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", fromFile) }else{ Uri.fromFile(fromFile) } intent.setDataAndType(fromUri, "image/*") intent.putExtra("crop", "true") intent.putExtra("aspectX", aspectX) intent.putExtra("aspectY", aspectY) intent.putExtra("outputX", width) intent.putExtra("outPutY", height) intent.putExtra("scale", true) val toUri = Uri.fromFile(toFile) intent.putExtra(MediaStore.EXTRA_OUTPUT, toUri) intent.putExtra("return-data", true) startActivityForResult(intent, REQUEST_CODE_CROP) } //分享文件 private fun shareFiles(fileList: Array<File>){ val intent = Intent(Intent.ACTION_SEND_MULTIPLE) val uriList = arrayListOf<Uri>() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) fileList.forEach { val uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", it) grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) uriList.add(uri) } }else{ fileList.forEach { uriList.add(Uri.fromFile(it)) } } intent.putExtra(Intent.EXTRA_STREAM, uriList) intent.type = "*/*" startActivityForResult(Intent.createChooser(intent, ""), REQUEST_CODE_SHARE_FILES) } private fun install(file: File){ val intent = Intent(Intent.ACTION_VIEW) val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", file) }else{ Uri.fromFile(file) } intent.setDataAndType(uri, "application/vnd.android.package-archive") intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) startActivityForResult(intent, REQUEST_CODE_INSTALL) }
(6)其他方案,如下则仍可以使用Uri.fromFile(File file)共享文件(不建议)
//在Application的onCreat()方法中添加 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build()); builder.detectFileUriExposure(); }
3、系统广播限制
静态注册网络状态变更广播、拍照广播、录像广播无效,需要动态注册方式
4、支持使用V2签名