在Android Q(Android 10 API 29)
开始版本中,官方的改动较大,相应的开发者适配成本还是很高的。
这里按照2019.11.11 google android q workshop
流程,大概说明一下Android Q适配需要注意的内容。虽然是大概介绍,但应该是目前最全的适配攻略了…
- 存储变更(Scoped Storage in Android 10)
- 非SDK 接口
- 设备ID
- 权限
- 新功能——夜间模式
官方适配文档:
https://developer.android.com/about/versions/10
一、Android10(API 29)存储变更
从Android Q(Android 10 API 29)开始,即便应用请求了WRITE_EXTERNAL_STORAGE
权限,其对全局外部存储的访问也受到限制,鼓励开发者采用Scoped Storage
的新规范来保护用户隐私和数据安全
。如果应用需要更广泛的访问权限
,需要请求MANAGE_EXTERNAL_STORAGE
权限来访问用户选择的文件和目录
,由于此权限的强大访问能力,Google Play会对申请使用该权限的应用进行严格审查
,确保应用的用途正当且必要。
为了解决Android文件混乱的问题,从Android Q(Android 10 API 29)开始,Android对外部存储
进行一定的限制。
- 通过
Context.getExternalFilesDir("type")
与Context.getExternalCacheDir()
访问应用专属存储目录; - 通过申请
READ_EXTERNAL_STORAGE
权限,使用MediaStore
API,访问共享媒体目录(如Photos、Screenshots等目录)。 - 通过API Storage Access Framework读取手机的
Downloads
文件夹,不需要任何权限
。
1.1 应用专属路径
通过Context.getExternalFilesDir("type")
与Context.getExternalCacheDir()
访问应用专属存储目录,无需任何权限
:
- 内部存储路径
/data/data/<包名>/
- 外部存储路径
/storage/Android/data/<包名>/
1.2 手机共享路径
通过申请READ_EXTERNAL_STORAGE
权限,使用MediaStore
API,访问共享媒体目录(如Photos、Screenshots等目录):
- 图片:Photos、Screenshots 使用MediaStore.Images API访问
- 视频:使用MediaStore.Video API访问
- 音频:使用 MediaStore.Audio API访问
1.3 Downloads文件夹
读取手机的Downloads文件夹,不需要任何权限,需要使用API Storage Access Framework
1.4 Scoped Storage的低版本兼容模式
targetSdk低于29的情况
如果应用的targetSdk低于29
并在Android 10上运行
,那么该应用可以暂时继续使用旧的存储访问方式,但建议对应的开发者尽快迁移到Scoped Storage模型。
1.5 Scoped Storage的过渡性的解决方案
requestLegacyExternalStorage=“true”
对于适配难度较大的应用,Android提供了一种方式可以暂时过渡性的解决方案
。
在androidmanifest配置文件中将requestLegacyExternalStorage
设置为true
,可以让应用在Android 10(API级别29)及更高版本上继续保持对传统外部存储访问方式的支持
。
将requestLegacyExternalStorage
设置为true
,可以迅速适配Android 10
,但Google明确表示这是一个过渡性的解决方案
,并且在未来的Android版本中可能会移除或不再支持。因此,开发者应计划逐步迁移应用至遵循Scoped Storage模型。
requestLegacyExternalStorage="true"的使用方式如下:
<manifest ... >
<application android:requestLegacyExternalStorage="true" >
</application>
</manifest>
官方描述如下:
https://developer.android.google.cn/training/data-storage/use-cases
1.6 官方文档参考:
外部存储访问权限范围限定为应用文件和媒体:
https://developer.android.com/about/versions/10/privacy/changes#scoped-storage
Manage scoped external storage access:
https://developer.android.com/training/data-storage/files/external-scoped
requestLegacyExternalStorage="true"官方描述:
https://developer.android.google.cn/training/data-storage/use-cases
MANAGE_EXTERNAL_STORAGE权限官方描述:
https://developer.android.google.cn/training/data-storage/manage-all-files
二、非SDK接口
官方文档:针对非 SDK 接口的限制
官方从 Android 9(API 级别 28)开始,对应用使用的非 SDK 接口实施了限制。
如果你的APP通过引用非 SDK 接口
或尝试使用反射或 JNI 来获取句柄
,这些限制就会起作用。官方给出的解释是为了提升用户体验、降低应用崩溃
风险。
2.1 非SDK接口检测工具
官方给出了一个检测工具,下载地址
Google官方 veridex下载:
https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat
CSDN资源镜像 veridex下载:
https://download.csdn.net/download/aiwusheng/80980831
veridex使用方法:
appcompat.sh --dex-file=apk.apk
2.2 blacklist、greylist、greylist-max-o、greylist-max-p含义
以上截图中,blacklist、greylist、greylist-max-o、greylist-max-p含义如下:
- blacklist 黑名单:禁止使用的非SDK接口,运行时直接Crash(因此必须解决)
- greylist 灰名单:即当前版本仍能使用的非SDK接口,但在下一版本中可能变成被限制的非SDK接口
- greylist-max-o: 在targetSDK<=O中能使用,但是在targetSDK>=P中被禁止使用的非SDK接口
- greylist-max-p: 在targetSDK<=P中能使用,但是在targetSDK>=Q中被禁止使用的非SDK接口
如果觉得我没有说清楚,可以看以下 2019.11.11 google android q workshop PPT 截图
2.3、Android Q 加固 与 热修复
关于加固与热修复,官方也提供了相应的API
-
加固
-
热修复
注:
未适配Android Q的应用,若使用了blacklist 相关接口,在Android Q系统上打开时,会直接Crash!
未适配Android Q的应用,若使用了blacklist 相关接口,在Android Q系统上打开时,会直接Crash!
未适配Android Q的应用,若使用了blacklist 相关接口,在Android Q系统上打开时,会直接Crash!
三、设备ID
从Android 10 开始 普通应用 已无法完全标识一个设备
,曾经用mac地址、IMEI
等设备信息标识设备的方法,从Android 10开始统统失效。而且无论你的APP是否是配过Android 10。
3.1 IMEI等设备信息
从Android10开始普通应用
不再允许请求权限android.permission.READ_PHONE_STATE
。
而且,无论你的App是否适配过Android Q(既targetSdkVersion
是否大于等于29),均无法再获取到设备IMEI
等设备信息。
受影响的API如下:
Build.getSerial();
TelephonyManager.getImei();
TelephonyManager.getMeid()
TelephonyManager.getDeviceId();
TelephonyManager.getSubscriberId();
TelephonyManager.getSimSerialNumber();
targetSdkVersion<29
的应用,其在获取设备ID时,会直接返回null
targetSdkVersion>=29
的应用,其在获取设备ID时,会直接跑出异常SecurityException
如果您的App希望在Android 10以下的设备中仍然获取设备IMEI等信息
,可按以下方式进行适配:
谁能访问设备ID?
从Android 10开始,哪些应用还能访问设备ID?
Google官方的描述如下:
https://source.android.com/devices/tech/config/immutable-device-ids?hl=zh-cn
- 默认的短信应用。
- 具有 READ_PRIVILEGED_PHONE_STATE 权限,并且在 privapp-permission.xml 文件中列入白名单的应用。
这些应用还必须加载到 system/priv-app 目录中。 - 具有 UICC 运营商权限中定义的运营商权限的应用。
- 具有 READ_PHONE_STATE 权限的设备所有者或资料所有者(无需列入白名单)。
3.2 Mac地址随机分配
从Android10开始,默认情况下,在搭载 Android 10 或更高版本的设备上,系统会传输随机分配的 MAC 地址。(既从Android 10开始,普通应用已经无法获取设备的真正mac地址,标识设备已经无法使用mac地址)
3.3 如何标识设备唯一性?
Google给出的解决方案是:如果您的应用有 追踪非登录用户重装
的需求,可用ANDROID_ID
来标识设备。
- ANDROID_ID的生成规则为:
签名+设备信息+设备用户
- ANDROID_ID重置规则:
设备恢复出厂设置时,ANDROID_ID将被重置
String androidId = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
也就是从Android 10开始已经无法完全标识一个设备
,曾经用mac地址、IMEI
等设备信息标识设备的方法,从Android 10开始统统失效。而且无论你的APP是否是配过Android 10。
求高手留言解答:
在Android 10系统上,目前本人尚未找到标识设备唯一性的办法,如果大家有办法希望留言告知!!!
四、权限相关
主要包括:
- 在后台运行时访问设备位置信息
- 从后台启动 Activity 的限制
- 屏幕录制
- 摄像头和麦克风
- 剪切板隐私限制
4.1 在后台运行时访问设备位置信息
Android 10 引入了 ACCESS_BACKGROUND_LOCATION
权限。
若应用在后台运行时,访问手机位置,需要动态申请该权限,用户则可以选择拒绝。
官方给出的数据,大部分用户对位置信息是比较敏感的。而且大部分用户是不允许应用在后台使用位置信息的。
4.2 从后台启动 Activity 的限制
4.3 屏幕录制
不需要手动申请权限,但官方 API内部会向用户弹窗申请权限
4.4 摄像头和麦克风
Android 9 摄像头和麦克风 后台权限已经移除了
4.5 活动探知——新增权限
4.6 剪切板隐私限制
从Android P开始,除非你的应用是默认输入法,否则它无法访问用户的剪贴板数据;但向剪切板写入数据不影响。
五、新功能——夜间模式
关于夜间模式,感兴趣的同学,可以查看我的另一篇文档: