华为官方适配平行视界的文档:文档中心 最近在做华为平板的平行视界下的适配工作,从一开始的小白到网上查资料踩坑,到现在逐步实现了想要的功能。提一个比较坑的一点,就是网上不少人写的判断是否是平行世界模式,用的是
String config = this.getResources().getConfiguration().toString();
return config.contains("hwMultiwindow-magic") || config.contains("miui-magic-windows");或是config.contains("hwMultiwindow-magic")。然而,这是错的!!!一直是false
真正对的写法是config.contains("hw-magic-windows");这个也是官网上说明了。文档中心
说下我遇到的功能需求。由于开发的App安装到华为平板上后,会默认开启平行视界模式,也就是在平板的设置-平行视界中能看到App的开关是开着的。所以,不得已进行适配平行视界。 而App的启动流程原先是启动页--->主界面,但是启动页中需要做各种操作,为整个App功能和主界面的功能做一些初始化。这里其实有个先后关联关系,这就要求,启动页的处理不能随随便便。 关于分屏适配的心路历程:因为适配前,App的启动逻辑就是启动页SplashActivity-->主界面MainActivity。且启动页是要关闭的。然后就想着,适配的话,就需要一个辅助页MainPageActivity。App一启动的时候是启动的辅助页,辅助页设置为全屏,然后1秒后跳转到启动页,跳转后两个界面就分屏了(我预想应该可以这样的)。因为官方文档上说的可以设置某个界面默认的启动方式为全屏,我就有了这个想法。但是实际测试发现,如果启动页是全屏,即使设置了
"activityPairs": [ { "from": "com.cnki.android.cnkimoble.activity.MainPageActivity", "to": "com.cnki.android.cnkimoble.activity.SplashActivity" } ],
和
"Activities": [
{
"name": "com.cnki.android.cnkimoble.activity.MainPageActivity",
"defaultFullScreen": "true"
},
{
"name": "com.cnki.android.cnkimoble.activity.SplashActivity",
"defaultFullScreen": "false"
}
]
跳转到启动页后,并不会分屏,启动页依然是全屏。但是如果翻转为竖屏再翻转回来,就变成了分屏了。但是,这不是我想要的效果。 后来发现实在不行,就只好改为启动时双屏显示的方案。也就是 "defaultDualActivities": { "mainPages": "com.cnki.android.cnkimoble.activity.MainPageActivity", "relatedPage": "com.cnki.android.cnkimoble.activity.SplashActivity" }, 。启动时的显示问题解决了,也就是启动双屏,然后SplashActivity跳转到MainActivity,且SplashActivity关闭(注意,这里埋了一个坑,后面说),MainActivity打开二级界面,这一系列的显示都是ok的,如自己想要的一样。 然而,从主界面的二级界面返回后,本来想着应该是辅助页和主界面分屏显示啊,结果,只剩一个主界面了,当然,它是半屏的,中间的那种。那,辅助页怎么显示不出来了呢。我郁闷了。由于这个App本身功能复杂,配置也是各种配置,有可能不知道哪个地方影响到了呢,或者本来就是这个样?于是,我新建了一个干净的Demo,仿照这个启动逻辑重新搞了一遍。结果发现,当主界面的二级界面关闭后,Demo里的辅助页和主界面是正常显示的,并不会像自己开发的App显示的只剩主界面半屏中间的那样。 于是,我猜测应该就是App配置影响到了。仔细检查了清单文件,发现了猫腻。主界面的配置是这样的:
<activity
android:name="com.cnki.android.cnkimoble.activity.MainActivity"
android:clearTaskOnLaunch="true"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize
|screenLayout"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="unspecified"
android:windowSoftInputMode="adjustPan">
</activity>
不寻常的配置有两项,android:clearTaskOnLaunch="true"和android:launchMode="singleTask"
而,android:clearTaskOnLaunch="true"这个就是启动的时候会把任务栈清空,也就是其他界面都移出去了,那么辅助页当然也被移出去了,所以,当二级界面回退到主界面时,只剩下主界面了,辅助页没有了。但是又有个问题,就是明明启动主界面时会把任务栈清空,那为啥那个时候辅助页还是存在的?界面显示正常啊。这应该是任务栈清空不会立即影响到界面,当需要重新显示辅助页时才会影响到,这里只是我的猜测。但这里不做深入讨论,毕竟现在我要把这个属性改一下。
android:clearTaskOnLaunch="false" 再重新运行,发现这个问题解决了。但后来发现,不是这个原因,貌似平板关机后重启,就没问题了。其实平行世界的这个系统功能还是不够稳定,不只我说,我看很多人也是吐槽,说功能还不稳定就放出来让用户用,而且还让开发者适配,这就坑到开发者了。 分屏显示时主界面退出后启动页重新创建的问题,用下面的代码解决: Intent home = new Intent(Intent.ACTION_MAIN); home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); home.addCategory(Intent.CATEGORY_HOME); startActivity(home); 适配过程中主要有几个点。 一、声明兼容平行视界模式 <meta-data android:name="EasyGoClient" android:value="true" /> 下面这个不加貌似也没问题 <meta-data android:name="android.allow_multiple_resumed_activities" android:value="true"/>
二、easyGo.json的配置
{
"easyGoVersion": "1.0",
"client": "com.cnki.android.cnkimobile",
"logicEntities": [
{
"head": {
"function": "magicwindow",
"required": "true"
},
"body": {
"mode": "0",
"defaultDualActivities": {
"mainPages": "com.cnki.android.cnkimoble.activity.MainPageActivity",
"relatedPage": "com.cnki.android.cnkimoble.activity.SplashActivity"
},
"activityPairs": [
{
"from": "com.cnki.android.cnkimoble.activity.MainActivity",
"to": "*"
}
],
"UX": {
"supportRotationUxCompat": "true",
"isDraggable": "true",
"supportDraggingToFullScreen": "PAD"
}
}
}
]
}
"mode": "0",表示是购物模式,官网中也说明了。我的功能是在购物模式下才能很好的实现。
三、启动的双屏配置
配置文件中
"defaultDualActivities": { "mainPages": "com.cnki.android.cnkimoble.activity.MainPageActivity", "relatedPage": "com.cnki.android.cnkimoble.activity.SplashActivity" }
决定着,启动界面应该是MainPageActivity
所以就有了以下配置
<activity
android:name="com.cnki.android.cnkimoble.activity.MainPageActivity"
android:label="@string/app_name"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.cnki.android.cnkimoble.activity.SplashActivity"
android:label="@string/app_name"
android:screenOrientation="unspecified"
android:windowSoftInputMode="adjustPan">
</activity>
而主界面
<activity
android:name="com.cnki.android.cnkimoble.activity.MainActivity"
android:clearTaskOnLaunch="true"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize
|screenLayout"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="unspecified"
android:windowSoftInputMode="adjustPan">
</activity>
注意,在适配平行视界之前,就是这个写法。有两点比较特殊,android:clearTaskOnLaunch="true"和android:launchMode="singleTask"
四、主界面退出时,App中调用了这个方法,来关闭。
/**
* 退出程序关闭所有的Activity
*/
public static void finishActivitys() {
LogSuperUtil.i(Constant.LogTag.advertise,"MyMainPage finish all activity",1);
if(true) {
Intent home = new Intent(Intent.ACTION_MAIN);
home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
home.addCategory(Intent.CATEGORY_HOME);
getInstance().startActivity(home);
//return;
}
for (int i = 0; i < mActivityList.size(); i++) {
if (null != mActivityList.get(i).get()) {
String activityName=mActivityList.get(i).get().getLocalClassName();
if(activityName!=null&&activityName.equals(MainPageActivity.class.getName())) {
}else {
}
LogSuperUtil.i(Constant.LogTag.advertise,i+" MyMainPage finish activity="+activityName);
mActivityList.get(i).get().finish();
}
}
mActivityList.clear();//这个必须有,因为有的地方判断MainActivity是否在运行要遍历mActivityList
}
五、对于解决我需求中的Bug的比较重要的知识点
/**
* 判断是否处于平行视界
* @return true/false
*/
protected boolean isInMagicWindow(){
//String config = this.getResources().getConfiguration().toString();
//return config.contains("hwMultiwindow-magic") || config.contains("miui-magic-windows");
String config = this.getResources().getConfiguration().toString();
boolean isInMagicWindow = config.contains("hw-magic-windows");//这个才是官网上说的判定标准
return isInMagicWindow;
}
Intent home = new Intent(Intent.ACTION_MAIN);
home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
home.addCategory(Intent.CATEGORY_HOME);
startActivity(home);