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签名