Android P正式版(以下称为Pie)已经正式上线了,各大厂商已经开始了系统升级工作,咱做上层开发的也得跟上节奏。当然了,新版本所有的行为更改内容都可以在官网上找到,对于其中如何绕开非SDK接口限制的问题,也有各路大神给出了解决方案。所以,我只能当搬运工了(偷笑ing)。下面我会结合现有的开发经验,聊聊Pie中对我们开发影响较大的一些更新,重头戏还是适配齐刘海和非SDK接口限制。
这里只会列出部分行为变更(仅代表个人见解),感兴趣的同学直接去官网查看。
Pie官方文档
更新内容:
影响:APP的推送功能可能需要适配,Pie中可以知道渠道组的状态了。
更新内容:
影响:对APP级别的影响应该较小,毕竟大部分都是使用第三方库来实现图片资源的加载。可能对SDK影响较大,SDK里基本都是自己写Image压缩解码逻辑,所以可以考虑使用。
更新内容:
在 Android 9 中,系统代表您的应用提供生物识别身份验证对话框。 该功能可创建标准化的对话框外观、风格和位置,让用户更加确信,他们在使用可信的生物识别凭据检查程序进行身份验证。
影响:接入了生物识别功能的(如:指纹)APP就有统一的提示对话框了,挺好的。就是不知道标准的风格是否适合各种应用。
更新内容:
影响:用户可以在关闭自动旋转的情况下,手动旋转屏幕;能否旋转取决于顶层可见Activity所支持的旋转设置。
更新内容:
影响:这个无疑强化了TextView的能力,应该比现在设置TextVie的样式方便。
更新内容:
应用待机群组
的概念,系统将根据用户的使用模式限制应用对 CPU 或电池等设备资源的访问。 影响:无疑,Google在帮Android机省电、省资源,算是一个比较好的更新。但是,我相信厂商会对分组策略稍作修改(或者白名单啥的),以方便自身应用可以随时唤起。总的来说,应该对应用的Push类功能影响较大。
更新内容:
影响:权限变更对收集手机应用信息和监听应用WiFi状态(主要是位置信息)都有很大影响,特别是对这些信息有依赖的业务。
更新内容:
从 Android 9 开始,默认情况下Apache网络库已从 bootclasspath 中移除且不可用于应用。
影响:终于要彻底抛弃Apache库了,但业务硬要用的话,还是可以自己导入jar包或者在AndroidManifest.xml中使用uses-library标签。
有Pixel的同学可以把系统升级到Pie查看效果,也可以下载相应镜像用模拟器测试(最好使用AS3.1以上)。Pie提供了三种刘海样式:
在Pie中,官方提供了DisplayCutout
类来获取刘海块相关数据;通过getDisplayCutout()
函数可以知道刘海是否存在;通过窗口布局属性layoutInDisplayCutoutMode
可以让应用为设备屏幕缺口周围的内容进行布局。直接上代码吧:
@TargetApi(28)
public void showDisplayCutout(View view) {
// 注意:getRootWindowInsets()只有在视图加载完成后,才会返回,否则返回null
DisplayCutout cutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
if (cutout == null) { // 没有刘海的时候拿到的DisplayCutout为null
Log.d(TAG, "showDisplayCutout: 普通屏,没有刘海");
return;
}
List<Rect> rects = cutout.getBoundingRects(); // 获取可能的凹凸块
if (rects.size() == 1) {
Log.d(TAG, "showDisplayCutout: 有刘海");
Rect rect = rects.get(0);
Log.d(TAG, "showDisplayCutout: 刘海区域:" + rect);
} else {
Log.d(TAG, "showDisplayCutout: 有刘海和下巴");
for (Rect rect : rects) {
Log.d(TAG, "showDisplayCutout: 区域:" + rect);
}
}
// 获取安全区域的数据,单位px
int safeInsetLeft = cutout.getSafeInsetLeft();
int safeInsetTop = cutout.getSafeInsetTop();
int safeInsetRight = cutout.getSafeInsetRight();
int safeInsetBottom = cutout.getSafeInsetBottom();
Log.d(TAG, "showDisplayCutout: 安全区域距离屏幕左边:" + safeInsetLeft);
Log.d(TAG, "showDisplayCutout: 安全区域距离屏幕顶部:" + safeInsetTop);
Log.d(TAG, "showDisplayCutout: 安全区域距离屏幕右边:" + safeInsetRight);
Log.d(TAG, "showDisplayCutout: 安全区域距离屏幕底部:" + safeInsetBottom);
int statusBarHeight = getStatusBarHeight();
Log.d(TAG, "showDisplayCutout: 状态栏高度:" + statusBarHeight);
}
private int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
注意:
设置窗口属性:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// 设置全屏
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
//沉浸式状态栏
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
WindowManager.LayoutParams lp = getWindow().getAttributes();
// 只有当DisplayCutout完全包含在系统栏中时,才允许窗口延伸到DisplayCutout区域。 否则,窗口布局不与DisplayCutout区域重叠。
lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
// 该窗口决不允许与DisplayCutout区域重叠。
// lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
// 该窗口始终允许延伸到屏幕短边上的DisplayCutout区域。
// lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(lp);
}
部分效果图:
适配方案:
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
,则会强制使用刘海区域,这时页面要规避刘海块的那一点区域。Android 9(API 级别 28)引入了针对非 SDK 接口的使用限制,无论是直接使用还是通过反射或 JNI 间接使用。无论应用是引用非 SDK 接口还是尝试使用反射或 JNI 获取其句柄,均适用这些限制。
如果我们使用非SDK接口,会出现几种情况:
非SDK接口都记录在了不同的名单下:
所有的名单文件都在:https://android.googlesource.com/platform/prebuilts/runtime/+/master/appcompat ,其中还有一个veridex
检测工具(目前只支持linux和mac)。
直接借用大佬们的文章:
360奇卓社-Android P 调用隐藏API限制原理
大致过程:
还是大佬们的文章:
其中替换classloader
的方式目前是最可靠的。