UE4:安卓版本分屏模式分辨率异常问题

问题描述

安卓7.0版本中增加了分屏显示的功能,UE4的Android平台的设置中可以设置关闭该项功能的支持,但是在安卓一些较新版本中,如果玩家打开了安卓的开发者选项并且开启了强制将Active设置为可调整大小(不同厂商定制可能名字不同),那么系统依然回允许将应用程序进行分屏显示

但是在这种情况下,分辨率会出现异常:

全屏时,分辨率正常
全屏时,分辨率正常

切换到分屏模式,显示不完全
切换到分屏模式,显示不完全

在这个时候修改分屏的宽度,分辨率异常
修改分屏的宽度,分辨率异常

最后拉到最宽退出分屏模式,分辨率异常
拉到最宽退出分屏模式,分辨率异常

以上是在4.27 release构建的一个空项目。

探寻过程

通过在进行分屏的时候输出的Log,找到了LaunchAndroid.cpp中,添加新的log发现OnAppCommandCB(struct android_app* app, int32_t cmd)里面的cmd只有APP_CMD_CONFIG_CHANGED,但是这个case被注释掉了:

20220922211531

注释写的是因为AConfiguration_getOrientation的一个NDK bug所以注释掉

将这部分解开注释,发现这里在拉回最大的时候if是进不去的,再把if临时取消掉,发现里面添加的Event是APP_EVENT_STATE_WINDOW_CHANGED

然后顺着去看了一下响应APP_EVENT_STATE_WINDOW_CHANGED的地方,在AndroidEventManager.cpp中

1
2
3
4
5
6
case APP_EVENT_STATE_WINDOW_CHANGED:
// React on device orientation/windowSize changes only when application has window
// In case window was created this tick it should already has correct size
// see 'Java_com_epicgames_ue4_GameActivity_nativeOnConfigurationChanged' for event thread/game thread mismatches.
ExecWindowResized();
break;

原本看到这个ExecWindowResized以为找到地方了,进去看了一下这个函数并没有获取或者设置分辨率

发现此处还有一个APP_EVENT_STATE_WINDOW_RESIZED,看名字就很像窗口修改大小需要的,于是又将APP_CMD_CONFIG_CHANGED的函数体里原本的APP_EVENT_STATE_WINDOW_CHANGED改成了APP_EVENT_STATE_WINDOW_RESIZED

但是问题又来了,APP_EVENT_STATE_WINDOW_RESIZED需要一个参数FAppEventData,要么有宽高,要么有app的window,这里都没有

又去看了一下EventManagerUpdateWindowDimensions的具体函数,试图在直接这里修改了一下:
20220922212446

这是一个不稳定的实现,可能会crash,但是帮助找到了真正的问题:

如果忽视掉图中的Sleep函数,在这里通过ANativeWindow_getWidth拿到的宽度值是错误的。比如我把宽度从500拉到1000,这里拿到的是500。加上Sleep之后
成功拿到了正确的值。

由于本人并不是专业的安卓开发,并不知道这是为什么,是否是一个Bug,但是对于UE4的安卓端的表现来讲,视为一个Bug……

解决方案

通过在搜索引擎中各种查找和翻阅安卓开发文档,一共经历了以下几个阶段:

在GameActivity.java.template中

1
2
3
DisplayMetrics displayMetrics = this.getResources().getDisplayMetrics();
Log.debug("onConfigurationChanged, DisplayMetrics widthPixels :" + String.valueOf(displayMetrics.widthPixels));
Log.debug("onConfigurationChanged, DisplayMetrics widthPixels :" + String.valueOf(displayMetrics.heightPixels));

发现上面的这个方式是可以动态的成功拿到当时的屏幕宽度,本来以为是正确的值,结果拉到最大的时候发现width短了一截子,查了一下说是减掉了通知栏……最后确认,不仅是退出分屏的时候,而是所有时候都会剪掉通知栏,其实在分屏模式改变窗口大小的时候是能通过动画表现发现这点的

于是又找到了这个:

1
WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();

这个需要添加依赖android.view.WindowMetrics

上面这个方式倒是可以在退出分屏模式的时候拿到一个正确的width了,但是发现在分屏的状态中他拿到的依然是最宽的宽度

最后终于找到了how-to-get-window-width-in-multiple-window-mode-android-7

于是按照里面的说法,成功的在java层拿到了及时准确的width值,美中不足的是这个会触发多次……但问题不大

最后的做法是,在C++侧添加函数,接收Java侧传递过来的准确的值,构造一个FAppEventData,然后去FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_WINDOW_RESIZED, FAppEventData),最后Trigger一下就可以了

解决!

感谢和参考


UE4:安卓版本分屏模式分辨率异常问题
http://muchenhen.com/posts/64190/
作者
木尘痕
发布于
2022年9月22日
许可协议