Android 11版本特性
Android 11 新特性,Scoped Storage又有了新花样
Android 11上强制启用了 Scoped Storage
需要适配的地方:关注Android 11的权限变更,这部分内容在 PermissionX现在支持Java了!还有Android 11权限变更讲解 这篇有比较详细的详解。
下文是关于 Scoped Storage 的探讨
Scoped Storage不是Android 11上新推的功能,在Android 10上就有,可以参考 Android 10适配要点,作用域存储 ,之前这篇并没有过时在Android 11上依然适用。
1 | <manifest ... > |
这个配置在Android 11上依然有效,前提是 targetSdkVersion 必须小于等于 29
在 targetSdkVersion 等于 30 时强制启用了 Scoped Storage(上述配置不起效)
强制启用 Scoped Storage 后应用程序按照 Android 10适配要点适配就可以了。
但有一类应用程序非常特殊,即文件浏览器,如Root Explorer、ES Explorer等。就会有影响,无法以文件的真实路径来对文件进行管理。针对这类应用的解决方案:
管理设备上所有的文件
大部分应用程序来说,使用 MediaStore API 就可以满足开发需求了。以下是针对文件浏览器应用的。
文件浏览器需要对设备的整个SD卡进行管理,这类危险程度比较高的权限,Google通常采用的做法是,使用Intent跳转到一个专门的授权页面,引导用户手动授权,比如悬浮窗,无障碍服务等。
在Android 11上想要管理整个设备的文件也是使用类似的技术。做法:
在
AndroidManifest.xml
中声明MANAGE_EXTERNAL_STORAGE
权限1
2
3
4
5
6
7
8<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.scopedstoragedemo">
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
</manifest>多了tools:ignore=”ScopedStorage”,不加这个的话 Android Studio会用一个警告提醒我们不应该申请这个权限。
使用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION这个action来跳转到指定的授权页面,可以通过Environment.isExternalStorageManager()这个函数来判断用户是否已授权
1
2
3
4
5
6
7
8
9
10
11
12
13if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R ||
Environment.isExternalStorageManager()) {//低于Android 11或已经拥有管理整个SD卡的权限,即可直接使用传统的写法,以文件真实路径的形式对文件进行操作
Toast.makeText(this, "已获得访问所有文件权限", Toast.LENGTH_SHORT).show()
} else {
//没有管理SD卡的权限。弹出一个对话框,告知用户申请权限的原因,然后使用Intent跳转到指定的授权页面,让用户手动授权
val builder = AlertDialog.Builder(this)
.setMessage("本程序需要您同意允许访问所有文件权限")
.setPositiveButton("确定") { _, _ ->
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivity(intent)
}
builder.show()
}注意:就算获得了管理SD卡的权限,对于Android这个目录下的很多资源仍然是访问受限的。比如
Android/data
这个目录在Android 11是无法访问的,它放的是其他应用程序的数据信息。
Batch operations
Scoped Storage规定,每个应用程序都有权向MediaStore贡献数据,也可以权读取其他应用程序贡献的数据,但不能修改其他应用程序贡献的数据。但有些应用需要修改其他应用程序共享的数据(如美图秀秀、Photoshop等),针对这个问题,Android 10中提供了一种解决方案:
1 | /** |
上述方法缺点是操作每张图片都要授权。Android 11中引入一个新功能Batch operations
允许我们一次性对多个文件的操作权限进行申请。
关于Batch operations的用法也很好理解,Google一共提供了4种类型的权限申请API,如下所示:
- createWriteRequest() 用于请求对多个文件的写入权限。
- createFavoriteRequest() 用于请求将多个文件加入到Favorite(收藏)的权限。
- createTrashRequest() 用于请求将多个文件移至回收站的权限。
- createDeleteRequest() 用于请求将多个文件删除的权限。
以createWriteRequest()
举例:
1 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { |
对于权限申请结果,在onActivityResult()
中进行监听:
1 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
上述的Android 10(依赖异常捕获机制)和Android 11(依赖Batch operations)的API用法不一样。如果不想在一个项目中写两套代码进行适配的话,那么做法是在代码中使用 Batch operations只针对 Android 11进行适配,在AndroidManifest.xml
中添加requestLegacyExternalStorage
标记让Android 10不需要适配。