Android7.0特性及适配

2022年7月12日11:14:50

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

  • 作者:yufumatou
  • 原文链接:https://blog.csdn.net/yufumatou/article/details/119322555
    更新时间:2022年7月12日11:14:50 ,共 3989 字。