Android 9.0适配及部分新特性介绍

1、Android 9.0应用迁移

1.1 概述

在最开始针对速贷进行Android9.0版本的适配时,我使用的是真机是vivo X21A,将targetSdkVersion升到28,运行发现网络请求全报400 Bad Request,查阅了网上针对android9.0网络请求问题的解决方案以及其他的一些迁移到Android9.0需注意的点(下文会讲到),做了些适配和调整,发现仍有问题,通过抓包也并没有发现问题的原因所在。随后试了下模拟器以及借来的google pixel(9.0)真机运行了下,能正常使用,并没有发现什么问题,于是猜想是机子本身系统的问题。

  • 11.01更新:莫名又正常运行了。
1.2 Android9的迁移和适配

在模拟器上的适配我这边做的不多,官网有比较详细的介绍: 将应用迁移到 Android 9

1.2.1 针对Android 9设备上运行的所有应用都有影响的关键变化有(列举了常用的,具体看官方文档):
  • * 对非 SDK 接口的限制:现已禁止访问特定的非 SDK 接口,无论是直接访问,还是通过 JNI 或反射进行间接访问。尝试访问受限制的接口时,会生成 NoSuchFieldException 和 NoSuchMethodException 之类的错误。
  • 移除加密提供程序:从 Android 9 开始,Crypto JCA 提供程序已被移除。调用 SecureRandom.getInstance("SHA1PRNG", "Crypto") 将会引发 NoSuchProviderException。
  • 更严格的 UTF-8 解码器:在 Android 9 中,针对 Java 语言的 UTF-8 解码器比以往更严格,并且遵循 Unicode 标准。
  • 强制执行 FLAG_ACTIVITY_NEW_TASK :在 Android 9 中,您不能从非 Activity 环境中启动 Activity,除非您传递 Intent 标志 FLAG_ACTIVITY_NEW_TASK。 如果您尝试在不传递此标志的情况下启动 Activity,则该 Activity 不会启动,系统会在日志中输出一则消息。
1.2.2 targetSdkVersion 设置为 28 时影响应用的关键变化(列举了常用的,具体看官方文档):
  • * 默认情况下启用网络传输层安全协议 (TLS):如果应用以 Android 9 或更高版本为目标平台,则默认情况下 isCleartextTrafficPermitted() 函数返回 false。 如果您的应用需要为特定域名启用明文,您必须在应用的网络安全性配置中针对这些域名将 cleartextTrafficPermitted 显式设置为 true。
  • * 前台服务:针对 Android 9 或更高版本并使用前台服务的应用必须请求 FOREGROUND_SERVICE 权限。 这是普通权限,因此,系统会自动为请求权限的应用授予此权限。
  • 按进程分设基于网络的数据目录:为改善 Android 9 中的应用稳定性和数据完整性,应用无法再让多个进程共用同一 WebView 数据目录。 此类数据目录一般存储 Cookie、HTTP 缓存以及其他与网络浏览有关的持久性和临时性存储。
  • 构建序列号弃用:在 Android 9 中,Build.SERIAL 始终设置为 "UNKNOWN" 以保护用户的隐私。 如果您的应用需要访问设备的硬件序列号,您应改为请求 READ_PHONE_STATE 权限,然后调用 getSerial()。

其中星号*标注的是我在项目中添加的修改部分。

1.3、适配详解(重要部分)
1.3.1、non-sdk 接口限制

non-sdk即非 SDK 接口,它们是不属于官方 Android SDK 的 Java 字段和函数,它们属于实现详情,不提倡被调用或者被禁止调用的,需要通过反射等其他手段来实现;而SDK接口是官方提供的,公开的标准接口,可以被我们调用。

我们可以通过查看日志消息来得知调用的非SDK接口属于灰名单还是黑名单:

也可以使用命令扫描整个app里面存在的非 SDK 接口:

1appcompat.sh --dex-file=apk路径

如:

/Users/Clem/常用工具/runtime-master-appcompat/veridex-mac/appcompat.sh --dex-file=/Users/Clem/常用工具/runtime-master-appcompat/app-jianrongsudai-debug.apk 结果如图:

  • 白名单:即SDK
  • 浅灰名单(72个):仍可以访问的非 SDK 函数/字段
  • 深灰名单(7个):对于目标 SDK 低于 API 级别 28 的应用,允许使用深灰名单接口; 对于目标 SDK 为 API 28 或更高级别的应用:行为与黑名单相同
  • 黑名单(0个):受限,无论目标 SDK 如何,平台将表现为似乎接口并不存在

列入浅灰名单的非 SDK 接口包含可以在 Android 9 中继续工作的函数和字段,但不能保证在未来版本的平台中能够继续访问,主要需要关注深灰名单和黑名单,需要找到可以替代的SDK接口进行适配。网上有人发现了绕过API检查的方法,也有专门的库允许在Android P上使用反射而没有任何限制,如FreeReflection:

1//允许在Android P上使用反射而不受任何限制
2implementation 'me.weishu:free_reflection:1.2.0'
3
4//在App.java中加入即可:
5Reflection.unseal(this);
1.3.2、http网络请求的问题

在我们项目中,使用OKHttp请求会出现如下异常:

1java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy

也就是说,当API级别为28及以上时,应用使用的如果是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,https则不会受影响,网上提供了三种方案:

  • APP改用https请求
  • targetSdkVersion 降到27及以下
  • 在 res 下新增一个 xml 目录,然后创建一个名为:network_security_config.xml 文件(名字可自定),大概意思就是允许开启http请求,内容如下:
1<?xml version="1.0" encoding="utf-8"?>
2<network-security-config>
3    <base-config cleartextTrafficPermitted="true" />
4</network-security-config>

然后在APP的AndroidManifest.xml文件下的application标签增加以下属性即可完成:

1<application
2...
3 android:networkSecurityConfig="@xml/network_security_config"
4...
5/>
1.4、后续问题

在完成上述的适配修改后,交给测试测了以后发现了如下问题:

  • 1、绑定公积金,选择城市时,页面会崩溃
  • 2、环境切换功能,点击测试入口时,页面会崩溃
  • 3、需支持支付宝h5支付
  • 4、偶现人脸识别不成功,反复进入活体认证页面

针对问题一和二:我测试了下Android9.0的模拟器以及google pixel(9.0)真机,发现并没有这些问题,而在vivo X21A真机上面,当页面崩溃时也没有任何明确的错误日志,只看到如图的信息:

通过打断点调试发现在vivo X21A真机上,无法使用Spinner和RadioButton控件(目前看到的就这两个),一旦使用就会造成崩溃,这个比较头疼,猜测是系统问题。

  • 11.07更新:使用新机子华为 Mate 20发现并没有这个问题。

针对问题三:测试了一下只有targetSdkVersion 设置为 28时才会出现该问题,与设备的系统版本无关,上蚂蚁金服平台查了下最新文档发现,App支付功能近期有了更新和升级,具体来说就是:打包方式更换为 AAR,替代之前的 JAR 打包,SDK 支付接口部分不变(亲测有效)。下载官方demo可以发现附带的更新日志文档中也有记录这些,如图:

针对问题四,由于是偶现,且也没有任何明确的报错日志,需要多个真机进行多次测试。

2、新特性介绍(功能及API)

2.1、显示屏缺口支持:layoutInDisplayCutoutMode

Android P的真机设备或模拟器上都可以模拟屏幕缺口,提供了三种样式。

  • 11.07更新:使用新机子华为 Mate 20发现开发者选项中没有提供模拟屏幕缺口,且该机也自带有凹口位置,状态栏也一直处于刘海区域。下面提到的模式针对该机效果都不变。

API 28也提供了新的类: DisplayCutout 类,该类主要用于获取凹口位置和安全区域的位置等。 主要接口如下:

方法

接口说明

getBoundingRects()

返回Rects的列表,每个Rects都是显示屏上非功能区域的边界矩形

getSafeInsetLeft ()

返回安全区域距离屏幕左边的距离,单位是px。

getSafeInsetRight ()

返回安全区域距离屏幕右边的距离,单位是px。

getSafeInsetTop ()

返回安全区域距离屏幕顶部的距离,单位是px。

getSafeInsetBottom()

返回安全区域距离屏幕底部的距离,单位是px。

此外,API 28中还提供了新的布局参数属性 layoutInDisplayCutoutMode ,包含了三种不同模式:

模式

模式说明

LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT

只有当DisplayCutout完全包含在系统栏中时,才允许窗口延伸到DisplayCutout区域。 否则,窗口布局不与DisplayCutout区域重叠。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

该窗口决不允许与DisplayCutout区域重叠。

LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES

该窗口始终允许延伸到屏幕短边上的DisplayCutout区域。

注:在Android P之前,各大手机厂商针对刘海适配方案都不太一样。

2.2、适用于可绘制对象和位图: ImageDecoder

可以将PNG, JPEG, WEBP, GIF, or HEIF 格式的图片的转换成Drawable 或者Bitmap 对象的类,可不再使用BitmapFactoryBitmapFactory.Options API。

 1ImageDecoder.OnHeaderDecodedListener listener = new ImageDecoder.OnHeaderDecodedListener() {
 2                @Override
 3                public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info, ImageDecoder.Source source) {
 4                //将解码的图像缩放到精确尺寸
 5                    decoder.setTargetSampleSize(2);
 6                }
 7            };
 8            ImageDecoder.Source source = ImageDecoder.createSource(getResources(), R.mipmap.ic_launcher);
 9            //转换成Drawable对象
10            Drawable drawable = ImageDecoder.decodeDrawable(source, listener);
11            //转换成Bitmap对象
12            //Bitmap bitmap = ImageDecoder.decodeBitmap(source);
2.3、动画:AnimatedImageDrawable

Android 9 引入了 AnimatedImageDrawable 类,用于绘制和显示 GIF 和 WebP 动画图像。 AnimatedImageDrawable 的工作方式与 AnimatedVectorDrawable 的相似之处在于,都是渲染线程驱动 AnimatedImageDrawable 的动画。 渲染线程还使用工作线程进行解码,因此,解码不会干扰渲染线程的其他操作。 这种实现机制允许您的应用在显示动画图像时,无需管理其更新,也不会干扰应用界面线程上的其他事件。

1private void decodeImage() throws IOException {
2    Drawable decodedAnimation = ImageDecoder.decodeDrawable(
3        ImageDecoder.createSource(getResources(), R.drawable.my_drawable));
4
5    if (decodedAnimation instanceof AnimatedImageDrawable) {
6        // 如果属于动画,则优先开启动画,展示第一帧
7        ((AnimatedImageDrawable) decodedAnimation).start();
8    }
9}
2.4、Magnifier(放大镜)

Android P引入了Magnifier来提升用户选择文字的体验,它通过放大镜将文字放大从而来帮助用户准确定位想要选择的文字:

 1@RequiresApi(api = 28)
 2        @Override
 3        public boolean onTouch(View v, MotionEvent event) {
 4            Magnifier magnifier = new Magnifier(v);
 5            switch (event.getActionMasked()) {
 6                case MotionEvent.ACTION_DOWN:
 7                    magnifier.show(event.getX(), event.getY());
 8                    break;
 9                case MotionEvent.ACTION_MOVE:
10                    magnifier.show(event.getX(), event.getY());
11                    break;
12                case MotionEvent.ACTION_UP:
13                    magnifier.dismiss();
14                    break;
15                default:
16                    break;
17            }
18            return true;
19        }

原文发布于微信公众号 - IT先森养成记(cyg_24kshign)

原文发表时间:2018-11-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术之路

Qt5 新特性

Qt 5 已经临近发布,其最大的特点就是模块化。将原来庞大的模块更细分为不同的部分,同时,一个大版本的升级,当然少不了添加、删除各个功能类。文本简单介绍 Qt5...

3918
来自专栏熊二哥

Sublime快速入门

在当前的互联网时代,任何程序语言和相关技术都只是实现互联网应用的一种手段,这也就造成了大量的互联网工程师长期与不同的语言、技术、系统环境、IDE等打交道。因此一...

1985
来自专栏施炯的IoT开发专栏

《101 Windows Phone 7 Apps》读书笔记-ALARM CLOCK

课程内容 Ø 隔离存储空间 Ø 设置 Ø 设置页面向导 Ø Toggle Switch控件 Ø 使用自定义字体     Alarm Clock模仿的...

2096
来自专栏何俊林

Android开发中,有哪些让你觉得相见恨晚的方法、类或接口?

前言:Android开发中,不是每一个api,我们都知道,一般情况,面对一个陌生的类,首先new出这个class,得到一到临时变量,然后class.xxx,看对...

1908
来自专栏王磊的博客

一些好用的开源控件

      工作两年,一直都在做些编码方面的表面功夫,实现了很多很炫的功能,在此写下一些体验。有些比较小的dll文件我会发上来,如果是开源组织的代码我会把地址附...

3836
来自专栏落影的专栏

iOS开发笔记(八)---- 键盘、静态库、动画、Crash定位

4129
来自专栏吴老师移动开发

Flutter中ScrollView及其子类(ListView等)的下拉刷新

先丢一个github的demo代码地址 移动开发发展到现在,下拉刷新是个必不可少的功能了。

6213
来自专栏破晓之歌

Python 的 GUI 开发工具 原

Flexx 是一个纯 Python 工具包,用来创建图形化界面应用程序。其使用 Web 技术进行界面的渲染。你可以用 Flexx 来创建桌面应用,同时也可以导出...

7622
来自专栏何俊林

插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑

在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇...

2057
来自专栏進无尽的文章

扒虫篇-Bug日志 Ⅱ

事情是这样的:一个风和日丽的下午,我正在 itunesConnect 中注册一个APP,基本信息都保存了,在编辑版本信息时,都弄的差不多了,可是没有保存,结果不...

761

扫码关注云+社区

领取腾讯云代金券