最新Android Q (10) 适配指南,让你少走一堆弯路!
原文:https://juejin.im/post/5cad5b7ce51d456e5a0728b0
1.导读
Android Q Beta 1刚出,讲道理国内是不到下半年不用理会Q的,但是上月末的一封华为要求适配Q的邮件要求我们在5月底之前完成相关适配,不然应用会被下架。
一开始还心生奇怪,为什么这次华为的邮件来的那么早以及严格。当我仔细阅读了官方文档之后发现Q的升级特别多,且不适配应用可能无法正常运行(不论targetSDK能否为Q)。
国内相关的文章还比较少,本文将总结归纳AndroidQ官方文档并将自己所踩过的坑记录下来,以便大家少走弯路。
本文将从三个角度详情Android Q的部分适配问题,也是大家开发适配过程中大概率会遇到的问题:
Q 行为变更:所有应用 (不论targetSdk是多少,对所有跑在Q设施上的应用均有影响)
Q 行为变更:以 Android Q 为目标平台的应用(targetSDK == Q 才有影响)
项目更新遇到的问题
至于Q的新功能及SDK,我粗略扫了一眼,项目中并没有涉及,故暂不详情,只放出链接AndroidQ新API及功能。
2.Q 行为变更:所有应用
客户隐私权限变更
AndroidQ引入了大量更改和限制以加强对客户隐私的保护。
官方文档将这一部分内容独立于Q 行为变更:所有应用来详情,是由于这一部分内容庞大且重要,个人认为Q的最大升级就是客户隐私权限变更。具体变更的权限如下:
| 权限 | 受影响应用 | 如何启用(影响范围) |
|---|---|---|
| 存储权限 | 访问和共享外部存储设施中的文件的应用 | adb shell sm set-isolated-storage on(下文详述) |
| 定位权限 | 在后端时请求访问客户位置信息的应用 | 这种权限策略在 Android Q 上始终处于启用状态 |
| 从后端启动 Activity | 不需要客户互动就启动 Activity 的应用 | 关闭允许系统执行后端活动开发者选项就可启用限制 |
| 设施标识符(deviceId) | 访问设施序列号或者 IMEI 的应用 | 在搭载 Android Q 的设施上安装应用 |
| 无线扫描权限 | 使用 WLAN API 和 Bluetooth API 的应用 | 以 Android Q 为目标平台 |
由于从后端启动Activity权限和无线扫描权限两种权限的变更影响较少。本文不作详述,如有涉及请查阅官方文档。
从后端启动Activity权限变更仅针对与客户毫无交互就启动一个Activity的情况,(比方微信登陆受权)
以下会着重详情存储权限,定位权限和设施标识符三种权限的变更与适配。
存储权限
Android Q 在外部存储设施中为每个应用提供了一个“隔离存储沙盒”(例如 /sdcard)。任何其余应用都无法直接访问您应用的沙盒文件。因为文件是您应用的私有文件,因而您不再需要任何权限就可在外部存储设施中访问和保存自己的文件。此变更可让您更轻松地保证客户文件的隐私性,并有助于减少应用所需的权限数量。
沙盒,简单而言就是应用专属文件夹,并且访问这个文件夹无需权限。谷歌官方推荐应用在沙盒内存储文件的地址为Context.getExternalFilesDir()下的文件夹。比方要存储一张图片,则应放在Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)中。
以下将按访问的目标文件的地址详情如何适配。
1. 访问自己文件:Q中用更精细的媒体特定权限替换并取消了 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE权限,并且无需特定权限,应用就可访问自己沙盒中的文件。
2. 访问系统媒体文件:Q中引入了一个新定义媒体文件的共享集合,假如要访问沙盒外的媒体共享文件,比方照片,音乐,视频等,需要申请新的媒体权限:READ_MEDIA_IMAGES,READ_MEDIA_VIDEO,READ_MEDIA_AUDIO,申请方法同原来的存储权限。
3. 访问系统下载文件:对于系统下载文件夹的访问,暂时没做限制,但是,要访问其中其余应用的文件,必需允许客户使用系统的文件选择器应用来选择文件。
4. 访问其余应用沙盒文件:假如你的应用需要使用其余应用在沙盒内创立的文件,请点击使用其余应用的文件,本文不做详情。
所以请判断当应用运行在Q平台上时,取消对READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE两个权限的申请。并替换为新的媒体特定权限。
关于存储权限的(如何启用)影响范围
模拟器
在Android Q Beat1中,谷歌暂未开放存储权限的改动。我们需要使用adb命令
adb shell sm set-isolated-storage on来开启模拟器对于存储权限的变更来进行适配。
真机
当满足以下每个条件时,将开启兼容模式,即不开启Q设施中的存储权限改动:
应用targetSDK<=P。
应用安装在从 Android P 更新到 Android Q 的设施上。
但是当应用重新安装(升级)时,不会重新开启兼容模式,存储权限改动将生效。
所以按官方文档所说,无论targetSDK能否为Q,必需对应用进行存储权限改动的适配。
在我的测试中,当targetSDK<=P,在Q Beat1版上申请两个旧权限时会自动改成申请三个新权限,不会影响应用正常使用,但当targetSDK==Q时,申请旧权限将失败并影响应用正常使用。
定位权限
为了让客户更好地控制应用对位置信息的访问权限,Android Q 引入了新的位置权限 ACCESS_BACKGROUND_LOCATION。
与现有的 ACCESS_FINE_LOCATION 和 ACCESS_COARSE_LOCATION 权限不同,新权限仅会影响应用在后端运行时对位置信息的访问权。除非应用的某个 Activity 可见或者应用正在运行前端服务,否则应用将被视为在后端运行。
与iOS系统一样,Q中也加入了后端位置权限ACCESS_BACKGROUND_LOCATION,假如应用需要在后端时也取得客户位置(比方滴滴),就需要动态申请ACCESS_BACKGROUND_LOCATION权限。
当然假如不需要的话,应用就无需任何改动,且谷歌会按照应用的targetSDK作出不同解决:
targetSDK <= P 应用假如请求了ACCESS_FINE_LOCATION 或者 ACCESS_COARSE_LOCATION权限,Q设施会自动帮你申请ACCESS_BACKGROUND_LOCATION权限。
设施唯一标识符
从 Android Q 开始,应用必需具备 READ_PRIVILEGED_PHONE_STATE 签名权限才能访问设施的不可重置标识符(包含 IMEI 和序列号)。
许多用例不需要不可重置的设施标识符。假如您的应用没有该权限,但您仍尝试查询标识符的相关信息。会返回空值或者报错。
设施唯一标识符需要特别注意,原来的READ_PHONE_STATE权限已经不能取得IMEI和序列号,假如想在Q设施上通过
((TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()取得设施ID,会返回空值(targetSDK<=P)或者者报错(targetSDK==Q)。且官方所说的READ_PRIVILEGED_PHONE_STATE权限只提供给系统app,所以这个方法算是废了。
谷歌官方给予了设施唯一ID最佳做法,但是此方法给出的ID可变,可以按照具体需求具体处理。
本文给出一个不变和基本不重复的UUID方法。
public static String getUUID() {String serial = null;String m_szDevIDShort = "35" + Build.BOARD.length() % 10 + Build.BRAND.length() % 10 + Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 + Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 + Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 + Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 + Build.TAGS.length() % 10 + Build.TYPE.length() % 10 + Build.USER.length() % 10; //13 位try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { serial = android.os.Build.getSerial(); } else { serial = Build.SERIAL; } //API>=9 使用serial号 return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();} catch (Exception exception) { //serial需要一个初始化 serial = "serial"; // 随意一个初始化} //使用硬件信息拼凑出来的15位号码 return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();}尽管因为唯一标识符权限的更改会导致android.os.Build.getSerial()返回unknown,但是因为m_szDevIDShort是由硬件信息拼出来的,所以依然保证了UUID的唯一性和持久性。
经测试上述方法完全相同的手机有可能重复,网上还有其余方案比方androidID,但是androidID可能因为机型起因返回null,所以个人任务两种方法半斤八两。设施ID的获取一个版本比一个版本艰难,假如有好的方法欢迎指出。
minSDK警告
在 Android Q 中,当客户初次运行以 Android 6.0(API 级别 23)以下的版本为目标平台的任何应用时,Android平台会向客户发出警告。
假如此应用要求客户授予权限,则系统会先向客户提供调整应用权限的机会,而后才会允许此应用初次运行。
谷歌要求运行在Q设施上的应用targetSDK>=23,不然会向客户发出警告。
3.Q 行为变更:以 Android Q 为目标平台的应用
非 SDK 接口限制
非SDK接口限制在Android P中就已提出,但是在Q中,被限制的接口的分类有较大变化。
非SDK接口详情
为了确保应用稳固性和兼容性,Android 平台开始限制您的应用可在 Android 9(API 级别 28)中使用哪些非 SDK 接口。Android Q 包含升级后的受限非 SDK 接口列表(基于与 Android 开发者之间的协作以及最新的内部测试)。
非SDK接口限制就是某些SDK中的私用方法,如private方法,你通过Java反射等方法获取并调用了。那么这些调用将在target>=P或者target>=Q的设施上被限制使用,当你使用了这些方法后,会报错:
| 获取方法 | 报错信息 |
|---|---|
| Dalvik instruction referencing a field | NoSuchFieldError thrown |
| Dalvik instruction referencing a method | NoSuchMethodError thrown |
| Reflection via Class.getDeclaredField() or Class.getField() | NoSuchFieldException thrown |
| Reflection via Class.getDeclaredMethod(), Class.getMethod() | NoSuchMethodException thrown |
| Reflection via Class.getDeclaredFields(), Class.getFields() | Non-SDK members not in results |
| Reflection via Class.getDeclaredMethods(), Class.getMethods() | Non-SDK members not in results |
| JNI via env->GetFieldID() | NULL returned, NoSuchFieldError thrown |
| JNI via env->GetMethodID() | NULL returned, NoSuchMethodError thrown |
非SDK接口查找
假如您不确定自己的应用能否使用了非 SDK 接口,则可以测试该应用进行确认。
当你调用了非SDK接口时,会有相似Accessing hidden XXX的日志:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)但是一个大项目究竟哪里使用了这些方法,靠review代码和看日志一定是不现实的,谷歌官方也提供了官方检查器veridex用来检测一个apk中哪里使用了非SDK接口。veridex下载。
其中有windows,linux和mac版本,对应下载就可。
下载解压后命令行cd到veridex目录下使用./appcompat.sh –dex-file=Q.apk就可自动扫描。Q.apk为包的绝对路径,假如包与veridex在相同目录下直接输入包文件名就可。
扫描结果分为两部分,一部分为被调用的非SDK接口的位置,另一部分为非SDK接口数量统计,例如:

greylist: 灰名单,即当前版本仍能使用的非SDK接口,但在下一版本中可能变成被限制的非SDK接口
blacklist:黑名单,使用了就会报错。也是我们项目中必需处理的非SDK接口
greylist-max-o:在targetSDK<=O中能使用,但是在targetSDK>=P中被限制的非SDK接口
greylist-max-p:在targetSDK<=P中能使用,但是在targetSDK>=Q中被限制的非SDK接口
所以从适配Q的角度出发,除了greylist我们可以暂时不处理以外,其他三种类型的非SDK接口需要我们进行适配。
非SDK接口适配
假如您的应用依赖于非 SDK 接口,则应该开始计划迁移到 SDK 替代方案。假如您无法为应用中的某项功能找到使用非 SDK 接口的替代方案,则应该请求新的公共 API。
官方要求targetSDK>=P的应用不使用这些方法,并寻觅其余的公共API去替代这些非SDK接口,假如找不到,则可以向谷歌申请,请求一个新的公共API https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces#feature-request (一般不需要)。
就我个人扫描并定位的结果来看,项目中使用非SDK接口大概率有以下两种情况:
在自己设置View的过程中为了方便,使用反射修改某个参数。
三方SDK中使用了非SDK接口(这种情况比较多)。
第一种是好处理的,毕竟是我们自己写的代码。
第二种就头疼了,只能升级到最新的三方SDK版本,或者者提工单、换库(也是整个适配过程中工作量最庞大的部分)。
4.项目更新遇到的问题
模拟器X86,项目中SO库为v7
找到so库源代码,编译成x86
假如so库只是某个功能点使用,对APP整体没大影响,即可以屏蔽特定so库功能或者略过测试
假如so库是项目核心库必需加载,也可使用腾讯云测,上面有谷歌亲儿子Q版本。腾讯云测有adb远程连接调试功能(我没成功过)。adb连不上也没关系,直接安装就行,云测上也可以直接看日志。
至于inter的houdini我尝试研究过,理论上能安装在x86模拟器上让它编译v7的so库,但是因为关于houdini的详情比较少也比较旧,建议大家时间不充裕的话就别研究了。
Requires development platform Q but this is a release platform.
因为目前Q是preview版,所以targetSDK==Q 的应用只能在Q设施上跑。
INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2
这个错误是因为打包压缩so库时造成的,具体起因可见
https://issuetracker.google.com/issues/37045367
在AndroidManifest.xml的application节点下加入android:extractNativeLibs="true"可能有人加了上面代码还是不行,在app/build.gradle中的defaultConfig节点下加入
packagingOptions{ doNotStrip "/armeabi/.so" doNotStrip "/armeabi-v7a/.so" doNotStrip "/x86/.so" }Didn’t find class “org.apache.http.client.methods.HttpPost”
在AndroidManifest.xml的application节点下加入
<uses-library android:name="org.apache.http.legacy" android:required="false"/>假如你的项目没有适配过android O或者P,那么你需要注意:
android O的读取已安装应用权限(对应用内自动升级有影响)
android P的默认禁止访问http的API
这两个版本的适配问题本文就不做详述,网上有很多详细的详情。
总结
适配还是不能拉下,假如你一下子从6.0更新到Q,你真的会哭的。
平常也多注意三方库的升级,由于安卓版本的升级势必导致了需要升级三方库。
官方文档的永远是最精确的。
参考文献
官方文档
非SDK接口
分享推荐;
Android高级架构技术群【964557053】。免费分享安卓进阶学习视频,源码,面试资料,群内有大牛一起交流探讨技术 (包括跨平台开发(Flutter,Weex)、java基础与原理,自己设置控件、NDK、架构设计、性能优化、完整商业项目开发等)
高级进阶脑图.png
阿里P7系列视频教程.png
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 最新Android Q (10) 适配指南,让你少走一堆弯路!