在最开始针对速贷进行Android9.0版本的适配时,我使用的是真机是vivo X21A,将targetSdkVersion升到28,运行发现网络请求全报400 Bad Request
,查阅了网上针对android9.0网络请求问题的解决方案以及其他的一些迁移到Android9.0需注意的点(下文会讲到)
,做了些适配和调整,发现仍有问题,通过抓包也并没有发现问题的原因所在。随后试了下模拟器以及借来的google pixel(9.0)真机运行了下,能正常使用,并没有发现什么问题,于是猜想是机子本身系统的问题。
在模拟器上的适配我这边做的不多,官网有比较详细的介绍: 将应用迁移到 Android 9
UTF-8
解码器:在 Android 9 中,针对 Java 语言的 UTF-8 解码器比以往更严格,并且遵循 Unicode 标准。FLAG_ACTIVITY_NEW_TASK
:在 Android 9 中,您不能从非 Activity 环境中启动 Activity,除非您传递 Intent 标志 FLAG_ACTIVITY_NEW_TASK
。 如果您尝试在不传递此标志的情况下启动 Activity,则该 Activity 不会启动,系统会在日志中输出一则消息。其中星号*
标注的是我在项目中添加的修改部分。
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 接口包含可以在 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);
在我们项目中,使用OKHttp请求会出现如下异常:
1java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by network security policy
也就是说,当API级别为28及以上时,应用使用的如果是非加密的明文流量的http网络请求,则会导致该应用无法进行网络请求,https则不会受影响,网上提供了三种方案:
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/>
在完成上述的适配修改后,交给测试测了以后发现了如下问题:
针对问题一和二:我测试了下Android9.0的模拟器以及google pixel(9.0)真机,发现并没有这些问题,而在vivo X21A真机上面,当页面崩溃时也没有任何明确的错误日志,只看到如图的信息:
通过打断点调试发现在vivo X21A真机上,无法使用Spinner和RadioButton控件(目前看到的就这两个),一旦使用就会造成崩溃,这个比较头疼,猜测是系统问题。
针对问题三:测试了一下只有targetSdkVersion
设置为 28时才会出现该问题,与设备的系统版本无关,上蚂蚁金服平台查了下最新文档发现,App支付功能近期有了更新和升级,具体来说就是:打包方式更换为 AAR,替代之前的 JAR 打包,SDK 支付接口部分不变(亲测有效)。下载官方demo可以发现附带的更新日志文档中也有记录这些,如图:
针对问题四,由于是偶现,且也没有任何明确的报错日志,需要多个真机进行多次测试。
Android P的真机设备或模拟器上都可以模拟屏幕缺口,提供了三种样式。
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之前,各大手机厂商针对刘海适配方案都不太一样。
可以将PNG, JPEG, WEBP, GIF, or HEIF 格式的图片的转换成Drawable 或者Bitmap 对象的类,可不再使用BitmapFactory
和 BitmapFactory.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);
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}
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 }