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被注释掉了:
注释写的是因为AConfiguration_getOrientation的一个NDK bug所以注释掉
将这部分解开注释,发现这里在拉回最大的时候if是进不去的,再把if临时取消掉,发现里面添加的Event是APP_EVENT_STATE_WINDOW_CHANGED
然后顺着去看了一下响应APP_EVENT_STATE_WINDOW_CHANGED的地方,在AndroidEventManager.cpp中
1 |
|
原本看到这个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的具体函数,试图在直接这里修改了一下:
这是一个不稳定的实现,可能会crash,但是帮助找到了真正的问题:
如果忽视掉图中的Sleep函数,在这里通过ANativeWindow_getWidth拿到的宽度值是错误的。比如我把宽度从500拉到1000,这里拿到的是500。加上Sleep之后
成功拿到了正确的值。
由于本人并不是专业的安卓开发,并不知道这是为什么,是否是一个Bug,但是对于UE4的安卓端的表现来讲,视为一个Bug……
解决方案
通过在搜索引擎中各种查找和翻阅安卓开发文档,一共经历了以下几个阶段:
在GameActivity.java.template中
1 |
|
发现上面的这个方式是可以动态的成功拿到当时的屏幕宽度,本来以为是正确的值,结果拉到最大的时候发现width短了一截子,查了一下说是减掉了通知栏……最后确认,不仅是退出分屏的时候,而是所有时候都会剪掉通知栏,其实在分屏模式改变窗口大小的时候是能通过动画表现发现这点的
于是又找到了这个:
1 |
|
这个需要添加依赖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一下就可以了
解决!