安卓9.0发布,献上Android 9.0新特性适配处理

时间:2024-04-09 22:26:19

安卓9.0即Android 9.0已经面向全球发布,它的代号是Pie,仍然基于Linux内核构建。为了避免Android 9.0 Pie新特性更新引发的适配问题,本文将介绍Android 9.0将带来哪些和开发者息息相关的影响,对Android 9.0新特性适配进行处理的方案。

 

新特性可以先阅读:https://ywnz.com/linuxxw/2556.html

 

Android 9.0模拟器搭建

目前Android 9.0只在少数的几款手机上能够升级,如果暂时还不想购买手机,模拟器就会是最佳选择,首先在AndroidStudio的Tools目录下找到Android,点开目录下的AVD Manager。

安卓9.0发布,献上Android 9.0新特性适配处理

在弹出的窗口中选择Craet Virtual Device按钮。根据提示下载API 28的SDK资源与Image资源等,下载速度较慢,最好准备处理网站访问问题。

安卓9.0发布,献上Android 9.0新特性适配处理

下载完之后别忘了更新gradle配置:

androidTargetSdkVersion = 28

androidCompileSdkVersion = 28

 

限制非Activity场景启动Activity

从Android 9.0开始,只有当Intent flag中指定了FLAG_ACTIVITY_NEW_TASK,才允许在非Activity场景启动Activity。如果不在Intent添加FLAG_ACTIVITY_NEW_TASK,将无法通过非Activity的Context启动一个Activity,并且会抛异常。

例如:

@Override

public void onCreate() {

super.onCreate();

Intent intent = new Intent(this, HomeActivity.class);

//不加 FLAG_ACTIVITY_NEW_TASK 将抛出异常

//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

}

因为没有添加FLAG_ACTIVITY_NEW_TASK,当Service的onCreat方法执行的时候会抛出异常。

安卓9.0发布,献上Android 9.0新特性适配处理

 

前台服务需要添加权限

在安卓9.0版本之后,必须要授予FOREGROUND_SERVICE权限,才能够使用前台服务,否则会抛出异常。

例如:

@Override

public void onCreate() {

super.onCreate();

String channelID = "1";

String channelName = "channel_name";

NotificationChannel channel = new NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_HIGH);

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

manager.createNotificationChannel(channel);

Intent intent = new Intent(this, ForegroundActivity.class);

PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);

Notification notification = new NotificationCompat.Builder(this)

.setContentTitle("前台服务测试")

.setContentText("前台服务需要增加 FOREGROUND_SERVICE 权限")

.setChannelId(channelID)

.setWhen(System.currentTimeMillis())

.setSmallIcon(R.mipmap.ic_launcher)

.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))

.setContentIntent(pi)

.build();

startForeground(1, notification);

}

这是一个带Notification的简单前台服务, 如果我们没有在AndroidManifest中注册FOREGROUND_SERVICE权限,在Service启动的时候会抛出SecurityException异常。

安卓9.0发布,献上Android 9.0新特性适配处理

对此,我们只需要在AndroidManifest添加对应的权限即可,这个权限是普通权限,不需要动态申请。

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

安卓9.0发布,献上Android 9.0新特性适配处理

 

限制静态广播的接收

升级安卓9.0之后,隐式广播将会被全面禁止,在AndroidManifest中注册的Receiver将不能够生效,如果你的清单文件中有如下的监听器:

<receiver android:name="com.yanghaoyi.receiver.UpdateReceiver">

<intent-filter>

<action android:name="com.yanghaoyi.action.ACTION_UPDATE" />

</intent-filter>

</receiver>

你需要移除上面的代码,并在应用中进行动态注册,例如:

private void registerReceiver(){

myReceiver = new MyReceiver();

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(TOAST_ACTION);

registerReceiver(myReceiver, intentFilter);

}

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(myReceiver);

}

 

非全屏透明Activity禁用设置orientation

非全屏透明页面不允许设置方向,否则会抛Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation异常,解决方案:android:windowIsTranslucent设置为false。

 

非 SDK 接口访问限制

在 Android 9.0 版本中,谷歌加入了非 SDK 接口使用限制,无论是通过调用、反射还是JNI等方式,开发者都无法对非 SDK 接口进行访问,此接口的滥用将会带来严重的系统兼容性问题。 在开发过程中,开发者如果调用了非 SDK 接口,会导致应用出现crash,无法启动;或在运行过程中出现崩溃、闪退等现象;也可能导致应用功能不可用等严重兼容性问题,其影响范围波及所有调用此接口的应用。

那么什么是非SDK接口呢,所谓非SDK接口就是所有不能够在谷歌官网上查询到的接口,谷歌提供了查询接口的网站。

非SDK接口的类型,分为三类

(1)Light grey list: targetSDK>=P时,警告;

(2)Dark grey list: targetSDK<P时,警告;>=p时,不允许调用;

(3)Black list:三方应用不允许调用。

安卓9.0发布,献上Android 9.0新特性适配处理

例如我们通过反射修改Dialog窗体的颜色:

try {

//通过反射的方式来更改dialog中文字大小、颜色

Field mAlert = AlertDialog.class.getDeclaredField("mAlert");

mAlert.setAccessible(true);

Object mAlertController = mAlert.get(normalDialog);

Field mMessage = mAlertController.getClass().getDeclaredField("mMessageView");

mMessage.setAccessible(true);

TextView mMessageView = (TextView) mMessage.get(mAlertController);

mMessageView.setTextSize(23);

mMessageView.setTextColor(Color.RED);

Field mTitle = mAlertController.getClass().getDeclaredField("mTitleView");

mTitle.setAccessible(true);

TextView mTitleView = (TextView) mTitle.get(mAlertController);

mTitleView.setTextSize(20);

mTitleView.setTextColor(Color.RED);

}catch (Exception e){

Toast.makeText(NotSDKInterfaceActivity. this,e.getLocalizedMessage(),Toast.LENGTH_LONG).show();

}

此方法在安卓9.0版本将不能够正常运行,会抛出NoSuchFieldException,对于诸如此类的调用官方private方法或者@hide方法,都将不能使用。

安卓9.0发布,献上Android 9.0新特性适配处理

 

刘海屏适配

谷歌安卓9.0版本提供了统一的挖孔屏方案和三方适配挖孔屏方案:对于有状态栏的页面,不会受到挖孔屏特性的影响;全屏显示的页面,系统挖孔屏方案会对应用界面做下移避开挖孔区显示;已经适配的P的应用的全屏页面可以通过谷歌提供的适配方案使用挖孔区,真正做到全屏显示。

安卓9.0发布,献上Android 9.0新特性适配处理

安卓9.0版本三方适配挖孔屏方案:

1.新增挖孔屏挖孔尺寸和位置接口:

class WindowInsets {

DisplayCutout getDisplayCutout();

}

class DisplayCutout {

int getSafeInsetLeft();

int getSafeInsetTop();

int getSafeInsetRight();

int getSafeInsetBottom();

Region getBounds();

}

2.新窗口布局模式,允许应用程序请求是否在挖孔区域布局:

class WindowManager.LayoutParams {

int layoutInDisplayCutoutMode;

final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;

final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;

final int LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;

}

3.layoutInDisplayCutoutMode值说明:

(1)LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT:默认情况下,全屏窗口不会使用到挖孔区域,非全屏窗口可正常使用挖孔区域。

(2)LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS:窗口声明使用挖孔区域

(3)LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER:窗口声明不使用挖孔区域

 

sensor和麦克风后台管控

限制sensor event向后台应用或服务的传输,对前台应用无影响;主要是考虑隐私原因,功耗不是主要动机;对应用来说是很大的变化。影响范围:应用处于idle和gone的状态就会被管控,切换到后台一分钟应用就会进入idle状态,但是有前台服务的不会进入idle状态。

问题定位,确认是不是该特性管控导致的:

(1)查看应用状态:adb shell dumpsys activity p com.sina.weibo ,然后搜索UID states查看UID的状态。

(2)查看应用有没有注册监听sensor情况:adb shell dumpsys sensorservice

适配方案:需要后台访问麦克风、sensor和camera的时候增加前台服务。如果满足以下任意条件,应用将被视为处于前台:

(1)具有可见 Activity(不管该 Activity 已启动还是已暂停)。

(2)具有前台服务。

(3)另一个前台应用已关联到该应用(不管是通过绑定到其中一个服务,还是通过使用其中一个内容提供程序)。例如,如果另一个应用绑定到该应用的服务,那么该应用处于前台。

 

设备识别码

通过Build.SERIAL不再能够获取到真实数据,Build.serial:unknown,需要通过Build.getSerial()获取。同时需要用户授权READ_PHONE_STATE权限。

 

示例代码

GitHub完整示例代码

 

附:能升级Android 9的手机和开始使用Android 9的方法