从 2018 年 3 月初我们发布 Android P 开发者预览版 https://mp.weixin.qq.com/s/9kASHj-L1f-Cj0JCKYouFw 以来, 很多开发者都对当前常见应用在 Android P 上做了一些兼容性测试 https://mp.weixin.qq.com/s/Ogmvdk92rTiyLiXGXmGACQ , 我们在这里总结了一些常见的问题, 以及它们发生的原因和建议的修改措施.
问题 1: 假设 android.os.Build.VERSION.RELEASE 为数值类型
原因:
对于即将推出的 Android 新版本的预览版, 这些值可能是字母数字 (如 "PPR" 或 "P"), 因此在尝试将 "P" 解析为整数时会导致崩溃.
建议:
应用把 RELEASE 的值作为字符串类型来处理.
问题 2: 使用的第三方 SDK 版本过低, 不兼容 Android P
原因:
在中国的 Android 生态中, 应用经常依赖的第三方 SDK (特别是加固和热修复框架) 会和系统底层紧密集成 (如使用非公开的接口), 而导致应用在 Android 版本升级时无法正常运行. 我们也开始与一些常见的 SDK 提供商合作 (并计划覆盖更多), 在 Android 新的预览版本中尽早解决兼容性问题.
建议:
经常检查第三方 SDK 的升级公告, 及时升级至其最新版本.
如果您使用的第三方 SDK 尚不支持 Android 新版本, 请报告给其提供商, 帮助推动它解决兼容性问题.
问题 3: 开启应用时显示 "Detected problems with API compatibility", 或调用非 SDK 接口时遭遇 NoSuchFieldException 或 NoSuchMethodException
原因:
非 SDK 接口指的是 Android 系统内部使用, 并未提供在 SDK 中的接口, 开发者可能通过 Java 反射, JNI 等技术来调用这些接口. 但是, 这么做是很危险的: 非 SDK 接口没有任何公开文档, 必须查看源代码才能理解其行为逻辑.
非 SDK 接口的函数签名 (包括参数列表和返回值), 行为逻辑都有可能在下个 Android 版本中被大幅修改, 甚至 API 本身也可能被删除. 这会导致使用非 SDK 接口的应用在新的 Android 版本中无法运行, 或运行时产生不符合预期的行为, 开发者必须投入相当的研发资源保持其在未来每个 Android 新版本中的适配.
直接使用底层的非 SDK 接口有可能会绕过一些 Android 对用户的安全性和隐私性方面的保护, 不但影响用户体验, 妨害用户隐私, 也很可能会被 Google Play Protect 判定为恶意软件而提示用户卸载应用.
从 Android P 开始, 系统会限制非 SDK 接口的使用 https://mp.weixin.qq.com/s/Wej2CYBQHNXDaf46DseavA .
建议:
只使用 Android SDK 中的公开接口进行应用开发. 公开 SDK 接口有详细的技术文档和支持渠道, 未来的 Android 新版本也会保证公开 SDK 接口的兼容性 (即使有改动, 也会在文档中详细阐明).
请尽早在 Android P 预览版中测试您的应用, 您可以运行并操作应用, 然后在 adb logcat 中查找类似下方的内容, 其中包含了应用调用的非 SDK 接口名, 所属黑 / 灰名单和调用的方式: Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI) Accessing hidden method Landroid/app/ActivityThread;->currentActivityThread()Landroid/app/ActivityThread; (dark greylist, reflection)
如果您有合理的理由, 必须使用某个非 SDK 接口, 请在文章下方留言给我们, 我们非常期待聆听和与您进行讨论, 并会在充分评估必要性和可行性后, 提供可能的方案来满足合理的功能需求.
问题 4: 直接调用 dex2oat, 或者使用不支持 / 不正确的方式编译 dex 文件
原因:
从一开始, dex2oat 就被设计为系统内部使用的编译部署工具, Android 从来都未支持过开发者直接调用 dex2oat 的场景. 我们会持续而不定期地对这个工具进行优化, 而很多时候其行为变更 (如: 生成的文件及其格式) 都是与之前不兼容的. 在大多数情况下, 标准的类加载器 (BaseDexClassLoader / DexClassLoader / PathClassLoader) 无法找到或使用由直接调用 dex2oat 生成的文件.
此外请注意, 从 Android O 开始, BaseDexClassLoader 和 DexClassLoader 构造函数中的 "optimizedDirectory" 参数已废弃, 并在加载 dex 文件时不起作用.
建议:
如果您需要从内存中加载 dex 文件, 而不愿在存储中留下痕迹, 请使用 Android O 中新增的加载器 InMemoryDexClassLoader.
问题 5: 注入或篡改 Android Studio 生成的 dex 和 so 文件
原因:
Android Studio 生成的 dex 文件虽然有公开的布局格式, 但具体内容还是会在运行时被系统在后台进行编译优化. 如果您在 dex 文件中写入自定义的内容, 很可能这些自定义的写入操作与系统优化发生冲突, 以致自定义的内容被擦除或覆盖, 甚至导致优化后的 dex 在执行时直接崩溃.
Android Studio 生成的 so 文件包含一些元数据 (如 ELF headers 和 section headers), 以备动态链接器进行完整性检查. 篡改 so 文件并不会带来安全性的提升 (很多工具可以重新生成元数据), 反而可能导致应用无法在未来的 Android 版本中启动 (由于动态链接器可能执行更严格的检查). 更多关于 so 文件的要求, 您可在公众号平台发送信息 "so 文件" 获取相关链接.
建议:
不要修改 Android Studio 生成的 dex 和 so 文件.
问题 6: 应用在 Android P 上启动时显示 "This app was built for an older version of Android and may not work properly..."
原因:
应用的 targetSdkVersion 太旧 ( <17 )
建议:
升级您应用的 targetSdkVersion 至最新版本, 您可在公众号平台发送信息 "targetsdkversion" 获取相关文档链接.
问题 7: 应用在特长屏幕上未能正确显示, 部分内容超出屏幕
原因:
Android O 开始支持特长屏幕, 而且已经有很多厂商开始发布特长屏幕的手机. 应用对屏幕的显示比例做出错误的假设, 而未能支持 16:9 以上的纵横比, 进而影响用户体验.
建议:
修改您的应用, 使他能够适应不同的屏幕尺寸 (包括 16:9 以上的纵横比).
如果自适应式 UI 不适合您的场景, 可以考虑在 manifest 中的 内设置 resizableActivity = false, 并加上 android:MaxAspectRatio 来声明最大支持纵横比. 这会在特长屏幕的设备上启用兼容模式, 把应用边缘的显示空间以黑色填充.
问题 8: 应用在特长屏幕上未能正确显示, 上下出现黑边
原因:
Android O 开始支持特长屏幕, 而且已经有很多厂商开始发布特长屏幕的手机. 应用对未能支持 16:9 以上的纵横比会在特长屏幕的设备上启用兼容模式, 把应用边缘的显示空间以黑色填充.
建议:
升级您应用的 targetSdkVersion 至最新版本, 您可在公众号平台发送信息 "targetsdkversion" 获取相关文档链接.
请参考下列 Android P 相关文档, 使您的应用尽早兼容 Android P:
设置 SDK 和模拟器 https://developer.android.google.cn/preview/setup-sdk.html
迁移指南 https://developer.android.google.cn/preview/migration.html
行为变更 https://developer.android.google.cn/preview/behavior-changes.html
新功能及 API https://developer.android.google.cn/preview/features.html
来源: https://juejin.im/post/5adff9c5f265da0b8e7f102e