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文件混乱的问题,从Android Q(Android 10 API 29)开始,Android对外部存储进行一定的限制。

  • 通过Context.getExternalFilesDir("type")Context.getExternalCacheDir()访问应用专属存储目录;
  • 通过申请READ_EXTERNAL_STORAGE权限,使用MediaStore API,访问共享媒体目录(如Photos、Screenshots等目录)。
  • 通过API Storage Access Framework读取手机的Downloads文件夹,不需要任何权限

Android 剪切板 隐私政策说明_Android Q 设备信息_02

1.1 应用专属路径

通过Context.getExternalFilesDir("type")Context.getExternalCacheDir()访问应用专属存储目录,无需任何权限

  • 内部存储路径 /data/data/<包名>/
  • 外部存储路径 /storage/Android/data/<包名>/

1.2 手机共享路径

通过申请READ_EXTERNAL_STORAGE权限,使用MediaStore API,访问共享媒体目录(如Photos、Screenshots等目录):

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

Android 剪切板 隐私政策说明_Android Q 非SDK接口_03

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下载:

veridex使用方法:

appcompat.sh --dex-file=apk.apk

Android 剪切板 隐私政策说明_Android Q 最全适配攻略_04

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 截图

Android 剪切板 隐私政策说明_Android Q 设备信息_05


Android 剪切板 隐私政策说明_Android Q 设备信息_06


Android 剪切板 隐私政策说明_Android Q 非SDK接口_07

2.3、Android Q 加固 与 热修复

关于加固与热修复,官方也提供了相应的API

  • 加固
  • Android 剪切板 隐私政策说明_Android Q 权限_08

  • 热修复
  • Android 剪切板 隐私政策说明_Android Q 最全适配攻略_09

注:
未适配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();

Android 剪切板 隐私政策说明_Android Q 权限_10

targetSdkVersion<29 的应用,其在获取设备ID时,会直接返回nulltargetSdkVersion>=29 的应用,其在获取设备ID时,会直接跑出异常SecurityException

Android 剪切板 隐私政策说明_Android 剪切板 隐私政策说明_11

如果您的App希望在Android 10以下的设备中仍然获取设备IMEI等信息,可按以下方式进行适配:

Android 剪切板 隐私政策说明_Android Q 权限_12

谁能访问设备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 如何标识设备唯一性?

Android 剪切板 隐私政策说明_Android Q 权限_13

Android 剪切板 隐私政策说明_Android Q 设备信息_14

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 权限。
若应用在后台运行时,访问手机位置,需要动态申请该权限,用户则可以选择拒绝。

官方给出的数据,大部分用户对位置信息是比较敏感的。而且大部分用户是不允许应用在后台使用位置信息的。

Android 剪切板 隐私政策说明_Android 剪切板 隐私政策说明_15

Android 剪切板 隐私政策说明_Android Q 权限_16

Android 剪切板 隐私政策说明_Android Q 非SDK接口_17

4.2 从后台启动 Activity 的限制

具体内容请查看官方文档

4.3 屏幕录制

不需要手动申请权限,但官方 API内部会向用户弹窗申请权限

Android 剪切板 隐私政策说明_Android Q 最全适配攻略_18

4.4 摄像头和麦克风

Android 9 摄像头和麦克风 后台权限已经移除了

4.5 活动探知——新增权限

Android 剪切板 隐私政策说明_Android Q 设备信息_19

4.6 剪切板隐私限制

从Android P开始,除非你的应用是默认输入法,否则它无法访问用户的剪贴板数据;但向剪切板写入数据不影响。

五、新功能——夜间模式

关于夜间模式,感兴趣的同学,可以查看我的另一篇文档:

Android Q 深色主题