《Android 9 Pie 应用兼容性最佳实践》陈卓

Razor

2019/07/04 发布于 技术 分类

安卓绿色联盟 

文字内容
1. 安卓绿色联盟·第19期技术沙龙 聚焦Android P版本应用兼容性最佳实践 北京场 2018/8/17 主办单位:
2. Android 9 Pie 应用兼容性最佳实践 陈卓 技术推广工程师
3. 应用兼容性指的是? 如果应用能够在上一个 Android 主版本上正常运行, 就可以在最新的 Android 主版本上正常运行。
4. 中国应用兼容性问题 全球 中国
5. 应用为何不兼容? ● ● ● 无意的系统行为变更 有意的系统行为变更 应用代码所依赖的不正确行为或受限制的 API 发生变化
6. Google Play targetSdkVersion 政策 ● ● targetSdkVerion 要求 ○ ○ ○ 2018年8月 2018年11月 2019年之后 https://goo.gl/XM9B5Z 新发布应用 - 必须为 26 或更高 升级现有应用 - 必须为 26 或更高 新发布或升级应用 - 必须为一年内发布的 Android 版本 targetSdkVerion 升级指南 https://goo.gl/YpZ17E
7. 使用非 SDK 接口的问题 ● ● 没有兼容性保证 ○ ○ ○ 可能在将来版本中改变,甚至消失 在不同设备上可能不兼容 兼容性问题在运行时才能被发现 绕过隐私保护 ○ ○ ○ 影响用户体验 妨害用户隐私 被 Google Play Protect 判定为恶意软件
8. 限制非 SDK 接口的目的 ● ● ● ● 使用公开 SDK 接口完成所有应用开发需求 非 SDK 接口仅能在系统内部使用 保证应用在各系统和设备之间的兼容性 推进 Android 新系统被采用的速度
9. 非 SDK 接口限制名单 ● 白名单(Whitelist) ○ ○ Android SDK 本身 没有任何限制
10. 非 SDK 接口限制名单 ● ● 白名单(Whitelist) 黑名单(Blacklist) ○ ○ ○ 只能被 Android 系统及系统应用使用 无论 targetSdkVersion 都禁止使用 对应用开发者来说,相当于没有这些接口
11. 限制各种调用路径 调用方式 结果 Dalvik 指令引用某字段 抛出 NoSuchFieldError Dalvik 指令引用某方法 抛出 NoSuchMethodError 通过 Class.getDeclaredField()、Class.getField() 进行反射 抛出 NoSuchFieldException 通过 Class.getDeclaredMethod()、Class.getMethod() 进行反射 抛出 NoSuchMethodException 通过 Class.getDeclaredFields()、Class.getFields() 进行反射 返回结果中不包含非 SDK 成员 通过 Class.getDeclaredMethods()、Class.getMethods() 进行反 射 返回结果中不包含非 SDK 成员 通过 env->GetFieldID() 调用 JNI 返回 NULL, 抛出 NoSuchFieldError 通过 env->GetMethodID() 调用 JNI 返回 NULL, 抛出 NoSuchMethodError
12. 非 SDK 接口限制名单 ● ● ● 白名单(Whitelist) 黑名单(Blacklist) 深灰名单(Dark Greylist) ○ ○ ○ 没有发现应用在使用,但我们觉得有潜在的可能性 当 targetSdkVersion < P 时允许使用 当 targetSdkVersion >= P 时禁止使用(相当于黑名单)
13. 非 SDK 接口限制名单 ● ● ● ● 白名单(Whitelist) 黑名单(Blacklist) 深灰名单(Dark Greylist) 浅灰名单(Light Greylist) ○ ○ ○ 已有应用在使用的非 SDK 接口,仍然可以继续使用 将来会考虑提供相应的 SDK 接口 当 targetSdkVersion >= P 时系统提示警告
14. 测试应用是否使用到非 SDK 接口 ● ● ● ● Logcat 中记录警告信息 DP 版本在 Activity 开始时显示 Toast 警告 DP2 版本开始,在 StrictMode 中支持设置警告 静态扫描工具 Veridex ○ ○ 自编译版:platform/art/tools/veridex 预编译版:platform/prebuilds/runtime/appcompat
15. 使用了黑名单中的接口? ● ● ● ● 升级第三方库 原则上允许所有已有应用继续在 P 上运行 查看是否可以转换至公开 SDK 接口 合理的理由必须使用某个接口,请告诉我们 https://goo.gl/KM1FMp
16. 应用兼容性注意事项 ● ● ● ● ● ● 不要直接调用 dex2oat 不要直接操作或篡改 dex / so 文件 不要干扰或篡改系统内部加载 dex 的逻辑 注意 NDK 的要求 不要使用 DexFile 类 查看 API 文档和 AOSP
17. 升级第三方 SDK ● ● ● ● ● ● ● ● 加固 热修复框架 推送服务 支付 / 收费 监控 / 分析 广告 游戏引擎 ...
18. 多窗口显示 ● ● ● ● Intent Flag: FLAG_ACTIVITY_LAUNCH_ADJACENT 不要假设暂停的 Activity 一定是不可见的! 多窗口模式的切换与转屏的事件等价 指定不支持多窗口 (API 24+): android:resizeableActivity = “false”
19. 特长屏幕支持 ● ● ● ● 不要假设屏幕纵横比 应用默认的最大屏幕纵横比 ○ ○ API 25(-) 1.86 API 26(+) 无 应用显示声明支持的最大纵横比 ○ ○ API 25(-) android.max_aspect meta data API 26(+) android:MaxAspectRatio 指南文档:https://goo.gl/GUpoiH
20. Android 9 Pie!
21. 加强用户隐私 Running on P Targeting P ● ● 空闲应用无法访问麦克风、摄像头和 SensorManager 传感器 ○ ○ ○ 麦克风报告系统 “无音频信号” 摄像头断开连接 传感器停止报告事件 用户控制是否允许访问平台 build.serial 识别码 ○ ○ 获取 READ_PHONE_STATE 权限 使用 Build.getSerial() 方法
22. 加强用户隐私(续) Running on P ● 以下权限从 PHONE 权限组 移入新的 CALL_LOG 权限组 ○ CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOG, PROCESS_ONGOING_CALLS ○ Running on P ● ○ 应用需要访问呼叫日志或处理拨出呼叫,必须显式申请 CALL_LOG 权限组 里的相应权限,否则系统会抛出 SecurityException 运行时动态权限,用户可能拒绝 读取电话号码或电话状态时必须获取 READ_CALL_LOG 权限 ○ ○ 从 PHONE_STATE intent action 中读取呼叫号码,必须获得 READ_CALL_LOG 和 READ_PHONE_STATE 权限 从 onCallStateChanged() 中读取呼叫号码,仅需 READ_CALL_LOG 权限
23. 加强用户隐私(续) Running on P ● 当设备定位设置关闭或应用无定位权限时,无法从数据连接 API (电话数据、WiFi、蓝牙)中获取位置信息 ○ ○ ○ ACCESS_COARSE FINE_LOCATION 运行权限不再足够 无论应用处于前台或后台 API 返回空值数列、null、或不调用已注册的回调
24. Apache HTTP 客户端 Targeting P ● 从 Android 6.0 开始移除对 Apache HTTP 客户端的支持 ○ ○ ○ Running on P ● 从 Android P 开始,bootclasspath 中不再包括此库 minSdkVersion <= 23 时: <uses-library android:name="org.apache.http.legacy" android:required="false"/> 将 org.apache.http 打包在自己的 apk 中(需要重命名) 系统 ClassLoader 不再支持 Apache HTTP 客户端 ○ ○ 寻找 org.apache.http.* 中的类时,返回 NoClassDefFoundError 应用需要实现自定义的 ClassLoader 并用其加载 Apache HTTP 客户端
25. 前台服务权限 Targeting P ● 应用使用前台服务时必须申请 FOREGROUND_SERVICE 权限 ○ ○ 只需在 manifest 中声明,系统自动授予,无需询问用户 若无此权限即运行前台服务,会发生 SecurityException
26. onSaveInstanceState 事件顺序调整 Targeting P ● onSaveInstanceState 在 onStop 后发生 ○ ○ 帮助降低 Fragment 事务的崩溃(常在 onPause 和 onStop 间发生) onSaveInstanceState 不再是一个独立的生命周期事件,而是不影响 生命周期的快照
27. 在 P 之前:
28. 在 P 上:
29. 屏幕旋转锁定 Running on P ● ● 在 P 之前: 自动旋转 或 纵向锁定 在 P 上: 自动旋转 或 旋转锁定(rotation lock) ○ ○ ○ 可以为纵向或横向 取决于最上层可见 Activity 的 screenOrientation 设置 通过 manifest 或 Activity.setRequestedOrientation() 设置
30. 凹口屏幕(Cutout)支持 Targeting P ● 新的 android:layoutInDisplayCutoutMode 属性 ○ DEFAULT 况下) 应用启动时有黑色边框(纵向时,仅在状态栏隐藏的情 ○ ○ NEVER 应用一直有黑色边框 ○ ○ ○ 也可以在运行时调用 API 设置 - getDisplayCutout() SHORT_EDGES 应用启动时占用凹口周边 getSafeInset(Top Bottom Right Left) 获取内容的安全区域 getBounds() 函数获取凹口区域(支持多个凹口)
31. 加强安全性 Targeting P Targeting P Targeting P ● ● ● 缺省启用网络 TLS ○ 缺省设置 cleartextTrafficPermitted = fasle WebView 数据目录不允许共享 ○ ○ ○ 即使是同一应用的不同进程中 建议:只在一个进程中调用 WebView,其他进程 disableWebView() 不同进程的 WebView 数据目录名必须使用不同的后缀 应用间不可以使用全局 Unix 权限来共享数据 ○ ○ 每个应用的数据目录都由 selinux 保护 应用可以继续使用 ContentProvider 或外部存储共享数据
32. 开始兼容 Android P 1. 2. 下载设备系统映像或模拟器系统映像,安装应用并测试 设置应用的 3. 4. 5. 阅读 P 的应用行为变更,在应用中进行需要的调整 阅读 P 的新功能,在应用中合理地使用 开发工具 ○ targetSdkVersion ‘28’ ○ compileSdkVersion ‘android-28’ ○ ○ ○ Android Studio 3.1 + Android 9 SDK Android Studio 3.2 Beta / 3.3 Canary 版本 支持库的 28.0.0 Beta 1 版本
33. Android 9 Pie 资源 ● ● ● ● ● 行为变更 ○ ○ Running on Pie https://goo.gl/ZnZuEq Targeting Pie https://goo.gl/BSHpu2 适配工作流程 https://goo.gl/rfk7sF Non-SDK 接口限制 https://goo.gl/T6gLNH 开发者网站 https://developer.android.google.cn AOSP “pie-release” branch
34. 谢谢大家! 陈卓