与早期版本一样,Android 11 包含一些行为变更,这些变更可能会影响您的应用。以下行为变更仅影响以 Android 11 或更高版本为目标平台的应用。如果您的应用将 targetSdkVersion
设置为 30
,您应酌情修改自己的应用,以便正确支持这些行为。
一、分区存储
首先看下Android存储位置分类:
1、内存存储的/data/data/App包名/,App的内部存储,App的特定目录
Context.getFilesDir()
/data/user/0/com.xxx/files
Context.getDataDir()
/data/user/0/com.xxx
Context.getCacheDir()
/data/user/0/com.xxx/cache
2、外部存储的/sdcard/Android/data/App包名/,App的外部存储的位置,App特定目录。Android8之后不允许其他应用直接访问。Android 10以后推荐使用,Android 11强制使用。
Context.getExternalCacheDir()
/storage/emulated/0/Android/data/com.xxx/cache
Context.getExternalFilesDir(Environment.DIRECTORY_MUSIC)
/storage/emulated/0/Android/data/com.xxx/files/Music
3、外部存储的/sdcard/Android/media/App包名/,App的外部存储的位置,App特定目录。
Context.getExternalMediaDirs()
/storage/emulated/0/Android/media/com.xxx/ 返回的是file[]
4、外部存储的/sdcard/公共目录(Music/,DCIM/等等),App的外部存储的公共部分,分区存储还可以访问。
Android Q之前通过Environment.getExternalStoragePublicDirectory(type)访问的目录。
type可以是:
Environment.DIRECTORY_MUSIC -> Music/
Environment.DIRECTORY_PODCASTS -> Podcasts/
Environment.DIRECTORY_RINGTONES -> Ringtones/
Environment.DIRECTORY_ALARMS -> Alarms/
Environment.DIRECTORY_NOTIFICATIONS -> Notifications/ Environment.DIRECTORY_PICTURES -> Pictures/
Environment.DIRECTORY_MOVIES -> Movies/
Environment.DIRECTORY_DOWNLOADS -> Download/
Environment.DIRECTORY_DCIM -> DCIM/
Environment.DIRECTORY_DOCUMENTS -> Documents
Android Q以后 :
通过MediaStore
通过File的方式访问。
Android 10 不支持 通过存储访问框架 (SAF)
例如:
//插入
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);// 设置显示名称
contentValues.put(MediaStore.Images.Media.DESCRIPTION, fileName); //设置文件说明
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");//设置图片类型
Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);//用getContentResolver.insert()外部存储存放
//查询
Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
5、通过Environment访问
当应用卸载时候,这部分数据不会被删除。公共目录部分(DCIM等等目录)还可以在分区存储模型中访问,但基本只能是媒体文件。而非公共部分,Android10不开启分区存储还可继续使用,但Android11强制不让使用,我们适配的关键也就是这部分内容。
Environment.getExternalStorageDirectory()
/storage/emulated/0
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
/storage/emulated/0/DCIM //公共目录还可以在Android10/Android11中使用,但只能查询媒体文件。
6、数据迁移
Android 10新增requestLegacyExternalStorage ,此标志为在Android10系统中是否开启分区存储,如果在manifest中配置成requestLegacyExternalStorage = true ,Android10将不使用分区存储
Android 11新增了preserveLegacyExternalStorage。大多数应用都不需要使用 preserveLegacyExternalStorage。此标记仅适用于这样一种情况:应用数据需要迁移SDcard的数据到分区存储目录下,此时希望更新应用时保留对数据的访问权限。
如果使用了 preserveLegacyExternalStorage,旧版存储模型只在用户卸载应用之前保持有效。如果用户在搭载 Android 11 的设备上安装或重新安装您的应用,那么无论 preserveLegacyExternalStorage 的值是什么,应用都无法停用分区存储模型。
/storage/emulated/0/dealmoon/post_cache/
/storage/emulated/0/Android/data/com.xxx/cache/post_cache/
/storage/emulated/0/dealmoon/post_draft/
/storage/emulated/0/Android/data/com.xxx/cache/post_draft/
/storage/emulated/0/dealmoon/data_cache/
/storage/emulated/0/Android/data/com.xxx/cache/data_cache/
delete:/storage/emulated/0/xx
二、数据共享
相关联的app之间数据共享,需要将android:sharedUserId设置为一样即可:
北美站与加拿大站登录信息共享。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx"
android:installLocation="auto"
android:sharedUserId="@string/shared_user_id">
......
三、相机的使用
从 Android 11 开始,只有预装的系统相机应用可以响应以下 intent 操作:
- android.media.action.VIDEO_CAPTURE
- android.media.action.IMAGE_CAPTURE
- android.media.action.IMAGE_CAPTURE_SECURE
如果有多个预装的系统相机应用可用,系统会显示一个对话框,供用户选择应用。如果您希望自己的应用使用特定的第三方相机应用来代表其捕获图片或视频,可以通过为 intent 设置软件包名称或组件来使这些 intent 变得明确。
此项变更是说在使用Intent创建拍照,录像隐式请求的时候,只有手机预装的系统相机才会响应。举个例子,当用户需要更新头像,选择拍摄上传的时候,如果用户手机上有多款能响应该Intent的相机应用可供选择的话,
Android11之前是这个样子的
如果开发者没有进行适配的话,Android11上就直接跳转到系统相机去了。对于很多使用美颜,滤镜和贴纸功能的用户影响还是挺大的。
真机通过隐式Intent启动Activity的时候,我们总是需要查询一下:
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(captureIntent, PackageManager.MATCH_DEFAULT_ONLY);
Android R:
Android Q:
可以看出Android R以后直接跳转到系统相机。
打开第三方相机应用:
//可以通过 intent 设置软件包名称或组件来打开 美颜相机
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
captureIntent.setClassName("com.meitu.meiyancamera", "com.meitu.myxj.selfie.merge.activity.SelfieCameraActivity");
context.startActivityForResult(captureIntent, requestCode);
四、权限
https://developer.android.google.cn/preview/privacy/permissions#auto-reset
五、应用打包和安装
以 Android 11(API 级别 30)或更高版本为目标平台的应用包含压缩的 resources.arsc 文件或者如果此文件未按 4 字节边界对齐,应用将无法安装。如果存在其中任意一种情况,系统将无法对此文件进行内存映射。无法进行内存映射的资源表必须读入 RAM 中的缓冲区,从而给系统造成不必要的内存压力,并大大增加设备的 RAM 使用量。
以 Android 11(API 级别 30)为目标平台,且目前仅使用 APK 签名方案 v1 签名的应用,现在还必须使用 APK 签名方案 v2 或更高版本进行签名。用户无法在搭载 Android 11 的设备上安装或更新仅通过 APK 签名方案 v1 签名的应用。