又到了我一年一度写Android适配文章的时间,本身这篇应该会早几个月发出来,但是前两三个月主要忙于Flutter的项目,所以这篇文章才姗姗来迟。不过毕竟是9.0的适配,还不算太晚哈!

1.前言

国内从去年开始就有消息说,应用上架或者更新要求TargetSdkVersion最低要为26以上,也就是最低也要适配到8.0。今年来也都逐步地开始落实。比如下图的小米应用商店公告:

当然Google Play的要求更为严格:

还包括从8月份开始在Google Play上发布的应用必须支持64位架构。可以看到适配工作真的不能像以前一样随心所欲了。好在我之前也有写过相关的适配攻略,Android适配系列:

  • Android 6.0 的动态权限管理

  • Android 7.0脱坑指南

  • Android 8.0适配指北

2.准备工作

进入正题,首先将我们项目中的targetSdkVersion改为 28。接下来运行你的项目,看有没中枪。

3.网络

1.Http请求失败

在9.0中默认情况下启用网络传输层安全协议 (TLS),默认情况下已停用明文支持。也就是不允许使用http请求,要求使用https。

比如我使用的是okhttp,会报错:

java.net.UnknownServiceException: CLEARTEXT communication to xxxx not permitted by network security policy

解决方法是需要我们添加网络安全配置。首先在 res 目录下新建xml文件夹,添加network_security_config.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" />
</network-security-config>

AndroidManifest.xml中的application添加:

<manifest ... ><application android:networkSecurityConfig="@xml/network_security_config">...</application>
</manifest>

以上这是一种简单粗暴的配置方法,要么支持http,要么不支持http。为了安全灵活,我们可以指定支持的http域名:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><!-- Android 9.0 上部分域名时使用 http --><domain-config cleartextTrafficPermitted="true"><domain includeSubdomains="true">secure.example.com</domain><domain includeSubdomains="true">cdn.example1.com</domain></domain-config>
</network-security-config>

当然不止这些配置,还有抓包配置、设置自定义CA以及各种场景下灵活的配置,详细的方法可以查看官方文档。

2.Apache HTTP 客户端弃用

在 Android 6.0 时,就已经取消了对 Apache HTTP 客户端的支持。 从 Android 9.0 开始,默认情况下该库已从 bootclasspath 中移除。但是耐不住有些SDK中还在使用,比如我见到的友盟QQ分享报错问题。

所以要想继续使用Apache HTTP,需要在应用的 AndroidManifest.xml 文件中添加:


<manifest ... ><application><uses-library android:name="org.apache.http.legacy" android:required="false"/>...</application>
</manifest>

4.前台服务

可以试着搜索一下你的代码,看是否有调用startForegroundServicestartForeground 方法来启动一个前台服务。

startForegroundService 主要来源估计都是8.0适配时候加上的:

Intent intentService = new Intent(this, MyService.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {startForegroundService(intentService);
} else {startService(intentService);
}

9.0 要求创建一个前台服务需要请求 FOREGROUND_SERVICE 权限,否则系统会引发 SecurityException

java.lang.RuntimeException: Unable to start service com.weilu.test.MyService@81795be with Intent { cmp=com.weilu.test/.MyService }:
java.lang.SecurityException: Permission Denial: startForeground from pid=28631, uid=10626 requires android.permission.FOREGROUND_SERVICEat android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3723)at android.app.ActivityThread.access$1700(ActivityThread.java:201)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1705)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loop(Looper.java:207)at android.app.ActivityThread.main(ActivityThread.java:6820)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)

解决方法就是AndroidManifest.xml中添加FOREGROUND_SERVICE权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

5.启动Activity

在9.0 中,不能直接非 Activity 环境中(比如ServiceApplication)启动 Activity,否则会崩溃报错:

 java.lang.RuntimeException: Unable to create service com.weilu.test.MyService: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?at android.app.ActivityThread.handleCreateService(ActivityThread.java:3578)at android.app.ActivityThread.access$1400(ActivityThread.java:201)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1690)at android.os.Handler.dispatchMessage(Handler.java:106)at android.os.Looper.loop(Looper.java:207)at android.app.ActivityThread.main(ActivityThread.java:6820)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)

这类问题一般会在点击推送消息跳转页面这类场景,解决方法就是 Intent 中添加标志FLAG_ACTIVITY_NEW_TASK

Intent intent = new Intent(this, TestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

6.异形屏适配

这类异形屏叫法很多,刘海屏、水滴屏、挖孔屏、美人尖。。。

  1. 其实如果你的页面不需要全屏显示,那么不需要额外的适配工作。

  2. 如果页面是全屏显示(比如启动页)。为了防止你的内容被遮挡,大部分场景下都是可以使用获取状态栏高度来处理遮挡的适配问题。因为状态栏的高度都是大于等于刘海的高度。

当然,如果你想利用起来刘海区域,就需要获取刘海位置等信息进行适配。在Android 9.0中官方提供了DisplayCutout 类,可以确定刘海区域的位置,国内的部分厂商在8.0就有了自己的适配方案。

具体的我就不过多介绍了,推荐大家看以下文章:

  • Android P 刘海屏适配全攻略

  • Android刘海屏、水滴屏全面屏适配方案

7.权限

首先是权限组的变更:

上图可以看到,在9.0 中新增权限组CALL_LOG 并将 READ_CALL_LOGWRITE_CALL_LOGPROCESS_OUTGOING_CALLS 权限从PHONE中移入该组。

1.限制访问通话记录

如果应用需要访问通话记录或者需要处理去电,则您必须向 CALL_LOG权限组明确请求这些权限。 否则会发生 SecurityException

2.限制访问电话号码

  • 要通过 PHONE_STATE Intent 操作读取电话号码,同时需要 READ_CALL_LOG 权限和 READ_PHONE_STATE 权限。
  • 要从 PhoneStateListener的onCallStateChanged() 中读取电话号码,只需要 READ_CALL_LOG 权限。 不需要 READ_PHONE_STATE 权限。

8.其他

  • 在 Android 9 中,调用Build.SERIAL 会始终返回 UNKNOWN 以保护用户的隐私。如果你的应用需要访问设备的硬件序列号,那么需要先请求 READ_PHONE_STATE 权限,然后调用 Build.getSerial()

  • 注意非 SDK 接口的限制。主要是一些热修复、插件化框架涉及比较多,注意及时升级新版本。

  • 多进程使用WebView注意无法共用同一数据目录。 详细点击查看


总的来说,9.0的适配工作需要改动和注意的点相比较以前版本的适配来说并不多,从本篇的篇幅就可以看出来,详细的变化可以参看文末的链接。后面如果遇到什么坑,我也会及时补充进来。感谢你的阅读!!

参考

  • Android 9.0 行为变更

  • targetSdkVersion升级28

Android 9.0 适配指南相关推荐

  1. Android 8.0适配指北

    本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. Android适配系列: Android 6.0 的动态权限管理 Android 7.0脱坑指南 Android 8.0适配指北 ...

  2. Android 12应用适配指南

    Android 12应用适配指南 1.Android 12上的主要变更 1.1 兼容性 1.1.1 前台服务启动限制 1.1.2 前台服务通知延迟 1.1.3 待处理 intent 必须声明可变性 1 ...

  3. 小老弟!听说你在搞Android 10.0 适配,看这篇就妥了!

    点击上方"何俊林",马上关注,每天早上8:50准时推送 真爱,请置顶或星标 转载自公众号:刘望舒,作者: 吃猫猫的鱼 地址:https://juejin.im/post/5cad5 ...

  4. 小米7.0 android 图片裁剪失败,Android 7.0适配 -- FileProvider 拍照、选择相册、裁切图片, 小米机型适配...

    需求: 最近把APP的TargetSdk从21提高至25后,测试时, 在Android7.0以上的系统上,爆出了一些异常. 在个别小米等机型也存在一些异常. 问题分析: FileUriExposedE ...

  5. 浅析Android 4.0的通知系统(附Android 4.0设计指南全文翻译)

    通过手机的通知系统,可以将应用程序的一些重要消息告知给用户.流畅.舒适.友好的应用程序离不开精心设计的消息提醒机制.但是并不是所有的通知都是用户想看的,否则只会给用户造成骚扰,所以要谨慎使用通知. 在 ...

  6. Android全面屏适配指南

    何为全面屏 全面屏是手机业界对于超高屏占比手机设计的一个宽泛的定义.从字面上解释就是,手机的正面全部都是屏幕,四个边框位置都是采用无边框设计,追求接近100%的屏占比.但受限于目前的技术,还不能做到手 ...

  7. 小米Android 13 应用适配指南公告

    1.1 小米机器升级Android 13指导 今年我们的4款设备,小米12.小米12 Pro.小米平板5 和 Redmi K50 Pro 首批支持 Android 13 Beta 1 .开发者们现在可 ...

  8. Android 7.0 适配 FileProvider相机 相册 裁剪的使用

    Android7.0又加了一些新的东西,例如多窗口 通知栏发消息 等等,但是这些是一些功能的改变,可以说是很炫的进步,而我要说的是FileProvider这个杀千刀的Api,先来看一下官方解释: 上面 ...

  9. Android 7.0脱坑指南

    本文已授权微信公众号:鸿洋(hongyangAndroid)原创首发. Android适配系列: Android 6.0 的动态权限管理 Android 7.0脱坑指南 Android 8.0适配指北 ...

最新文章

  1. 字符串匹配算法 -- BM(Boyer-Moore) 和 KMP(Knuth-Morris-Pratt)详细设计及实现
  2. Centos6.x搭建lnmp环境
  3. sql datetime比较大小_SQL做题小技巧
  4. 使用.NET为Window Mobile写自动化工具的无奈之处.
  5. Ribbon负载均衡原理,Feign是如何整合Ribbon的?
  6. join实例 oracle_oracle中join联合查询
  7. GP学习(八)—How to access a raster dataset and to create a raster dataset
  8. 记录——《C Primer Plus (第五版)》第十一章编程练习第一题
  9. iis mysql 无法启动_Windows下使用IIS搭建PHP环境无法开启Mysql支持的解决方法
  10. CryoSat-2卫星介绍
  11. [搜片神器]使用C#实现DHT磁力搜索的BT种子后端管理程序+数据库设计(开源)
  12. VS Qt 项目 “fatal error C1083: ”无法打开包括文件
  13. Emby for Mac(多媒体影音库)
  14. mac上彻底删除 搜狗输入法 鼠须管输入法
  15. php高级工程师面试题收集
  16. Excel批量把数字格式变成文本格式且不用双击出现左上绿标
  17. 靠智慧教育“飞升”,科大讯飞前路漫漫
  18. 什么叫低格?怎样执行
  19. 量化交易期货ctp使用说明(企业版,穿透式监管)(值得收藏)
  20. Golang 提取视频中音频,存为WAV格式 | Golang工具

热门文章

  1. B站股权曝光:陈睿持股12.6%有42%投票权 腾讯阿里是股东
  2. 线路光纤差动保护装置
  3. php 模拟GMAIL邮箱登录
  4. kerberos的使用
  5. AcWing 1613. 数独简单版
  6. K11942 雷达安装
  7. 会议OA项目--我的会议
  8. Git配置SSH公钥及创建和克隆远程仓库
  9. 设计模式——装饰模式(Decorator)
  10. 20145209刘一阳《网络对抗》Exp2 后门原理与实践