一、修改targetSdkVersion为30

将build.gradle的目标版本targetSdkVersion修改为30(Android 11)

targetSdkVersion 30

Android11的改变改变主要影响以Adnroid11 为目标版本的应用(targetSdkVersion>=30才有影响),和所有应用在Android11设备上适配改动(无论targetSdkVersion是多少,只要在Android11设备上运行的应用都有影响)

二、Android11需要适配的地方

1、分区存储

分区存储,将公共区域划分成了不同的集合,并且在媒体文件和其他文档之间建立了清楚的分割。经过划分之后应用不可以随意访问外部存储区中的文件,而只能访问媒体文件。如果想访问包含更多细节数据的其他文档,应用专门向用户申请有关文档的访问权限。

关于分区存储,在Android10就已经推行了,简单的说,就是应用对于文件的读写只能在沙盒环境,也就是属于自己应用的目录里面读写。其他媒体文件可以通过MediaStore进行访问。

但是在android10的时候,Google还是为开发者考虑,留了一手。在targetSdkVersion = 29应用中,设置android:requestLegacyExternalStorage=“true”,就可以不启动分区存储,让以前的文件读取正常使用。但是targetSdkVersion = 30中不行了,强制开启分区存储,设置android:requestLegacyExternalStorage="true"已经无效了。

四种访问文件的方法:

1)应用专属目录

//分区存储空间
val file = File(context.filesDir, filename)//应用专属外部存储空间
val appSpecificExternalDir = File(context.getExternalFilesDir(), filename)

2)访问公共媒体目录文件

val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc")
        if (cursor != null) {
            while (cursor.moveToNext()) {
                val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
                val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
                println("image uri is $uri")
            } cursor.close()
        }

3)SAF(存储访问框架–Storage Access Framework)

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
        intent.addCategory(Intent.CATEGORY_OPENABLE)
        intent.type = "image/*"
        startActivityForResult(intent, 100)
        @RequiresApi(Build.VERSION_CODES.KITKAT) 
        override fun onActivityResult(requestCode:Int, resultCode:Int, data:Intent ?){
            super.onActivityResult(requestCode, resultCode, data)
            if (data == null || resultCode != Activity.RESULT_OK) returnif(requestCode == 100) {
                val uri = data.dataprintln("image uri is $uri")
            }
        }

4)获取所有文件权限MANAGE_EXTERNAL_STORAGE(官方不推荐),这个权限是给文件管理类软件、杀毒软件使用的
在清单文件中添加权限,这个权限就是用来获取所有文件的管理权限

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
val intent = Intent()
        intent.action = Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
        startActivity(intent)
        //判断是否获取MANAGE_EXTERNAL_STORAGE权限:
        val isHasStoragePermission= Environment.isExternalStorageManager()

2、应用包可见性

在 Android 11 之前,我们可以通过 PackageManager.getInstalledPackages(0) 获取其他所有应用的包名等信息。
Android 11 为了增加安全性,更好地保护用户的隐私,对应用包的可见性做出了一些改动。

当 targetSdkVersion 为 30 时,如果我们用getPackageInfo(“another.app”,0) 获取其他应用包信息时 ,会出现 NameNotFoundException 的异常。

我们可以在 AndroidMainfest 中添加 来适配特定的使用场景:(该配置相当于是添加应用白名单)

已知想获取的包名:

<queries>
		<package android:name="com.test.application1"/>
		<package android:name="com.test.application2"/>
		<package android:name="com.test.application3"/>
	</queries>

3、权限变化

在 Android 11 中,系统为用户的私人数据提供了更多可供选择的授权方式,应用也加大了后台对位置的访问权限限制。

对应摄像头、位置信息和麦克风这几个数据类型,用户可以授予一次性的临时访问权限。

android 读取本地Bitmap android11读取data_Android


这个一次性权限的生效周期指的是:

应用 Activity 可见期间
应用转为后台后的短时间内
前台服务存活期间
当用户撤销单次授权后,应用进程退出,再次打开之后需要对应用进行重新授权期间

4、位置权限

在Android10 之前,我们通过ACCESSCOARRSELOCATION 或 ACCESSFINELOCATION(精确位置) 配置即可申请前后台位置权限。

Android 11将位置权限分为前台和后台两种权限。前文说的主要是前台权限,授权方式没有变化。应用想要申请后台权限,除了需要在清单文件中额外添加 ACCESSBACKGROUNDLOCATION 权限外,还需要应用主动引导用户到指定页面授权。

Android 11 要求面向 API 级别为 30 的应用使用递增式位置权限请求。任何同时申请前台位置权限 (无论是粗略位置还是精确位置) 和后台位置权限的请求都会被忽略并且报错。

需要先申请前台位置权限,然后在稍晚些再申请后台位置权限。

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />//后台位置权限