|
问题描述:
最近新买了RedMi K50和一加Ace Pro两台机器,一台是Android13,一台是Android12。以前UE4.26打包的程序,不论是刘海屏还是挖孔屏,都是可以全屏的。但安装到这两台机器上竟然不能全屏。正好是刘海和挖孔的位置被留了出来。
UE中如何全屏Android应用
在UE4/UE5中,Android应用的全屏需要设置两个位置,如下图中红框部分。
第一, 最大宽高比默认是2.1,随着市场上屏幕越来越多,该值可能要放大,例如我就设置为了2.3.
第二,勾选是否使用cutout。通俗点讲,就是你的APP是否要使用刘海或者挖孔的部分。
设置完成之后在Android的Manifest文件中会生成下面两项:
<meta-data android:name=&#34;com.epicgames.ue4.GameActivity.bUseDisplayCutout&#34; android:value=&#34;true&#34; />
<meta-data android:name=&#34;android.max_aspect&#34; android:value=&#34;2.30&#34; />不出意外的话,你的App可以全屏了。
出现问题的原因
通过测试发现,相同的手机,用UE4.26和UE5打包结果完全不同。UE5不会有任何问题。但UE4.26在文中提到的两部手机就不会全屏显示了。
既然通过ProjectSetting修改的是上面提到的两项Manifest配置。那我们就打开Android Studio工程看看。差异是什么。
这里有一个教程,里面详细讲解了在UE4/UE5中如何进行Android开发Unreal Engine 5语音SDK接入案例
通过查看Android Studio工程代码,可以看到,是否使用刘海就在于下面这几行代码
if (UseDisplayCutout)
{
// will not be true if not Android Pie or later
WindowManager.LayoutParams params = getWindow().getAttributes();
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(params);
}所以,只要UseDisplayCutout为true,应该不会出问题吧?那就去找找该值在哪里设置的。
通过翻查代码,该值有两个地方设置
- 如果有闪屏界面,是通过闪屏界面传递给GameActivity
- 如果没有闪屏界面,该值是直接从Manifest获取的
if (SplashScreenLaunch == false && android.os.Build.VERSION.SDK_INT >= 28)
{
if(bundle.containsKey(&#34;com.epicgames.unreal.GameActivity.bUseDisplayCutout&#34;))
{
UseDisplayCutout = bundle.getBoolean(&#34;com.epicgames.unreal.GameActivity.bUseDisplayCutout&#34;);
Log.debug( &#34;Display cutout set to &#34; + UseDisplayCutout);
}
else
{
Log.debug( &#34;Display cutout not found. Leaving as &#34; + UseDisplayCutout);
}
}
_extrasBundle = getIntent().getExtras();
if (_extrasBundle != null)
{
ShouldHideUI = _extrasBundle.getString(&#34;ShouldHideUI&#34;) != null;
UseDisplayCutout = _extrasBundle.getString(&#34;UseDisplayCutout&#34;) != null;
}那闪屏界面又是从哪里获取的呢?截取部分闪屏界面代码,可以看到同样是从Manifest获取的。并且还加了一些手机型号的判断,进而最终确认。
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
if(bundle.containsKey(&#34;com.epicgames.unreal.GameActivity.bUseDisplayCutout&#34;))
{
UseDisplayCutout = bundle.getBoolean(&#34;com.epicgames.unreal.GameActivity.bUseDisplayCutout&#34;);
}
}
catch (NameNotFoundException | NullPointerException e)
{
Log.error(&#34;Error when accessing application metadata&#34;, e);
}
// allow certain models for now to use full area around cutout
boolean BlockDisplayCutout = android.os.Build.VERSION.SDK_INT < 30;
if (android.os.Build.MANUFACTURER.equals(&#34;HUAWEI&#34;))
{
BlockDisplayCutout = false;
}
else if (android.os.Build.MANUFACTURER.equals(&#34;HMD Global&#34;))
{
String model = android.os.Build.MODEL;
if (model.equals(&#34;Nokia 8.1&#34;))
{
BlockDisplayCutout = false;
}
}
else if (android.os.Build.MANUFACTURER.equals(&#34;samsung&#34;))
{
String model = android.os.Build.MODEL;
if (model.startsWith(&#34;SM-G970&#34;) || model.startsWith(&#34;SM-G973&#34;) || model.startsWith(&#34;SM-G975&#34;) ||
model.startsWith(&#34;SC-03L&#34;) || model.startsWith(&#34;SCV41&#34;) || model.startsWith(&#34;SC-04L&#34;) ||
model.startsWith(&#34;SCV42&#34;) || model.startsWith(&#34;SM-N97&#34;) || model.startsWith(&#34;SM-F700&#34;) ||
model.startsWith(&#34;SM-G98&#34;) || model.startsWith(&#34;SCV47&#34;) || model.startsWith(&#34;SCG01&#34;) ||
model.startsWith(&#34;SCG02&#34;) || model.startsWith(&#34;SC-51A&#34;) || model.startsWith(&#34;SC-52A&#34;) ||
android.os.Build.VERSION.SDK_INT >= 28)
{
BlockDisplayCutout = false;
}
}
else if (android.os.Build.MANUFACTURER.equals(&#34;Xiaomi&#34;))
{
String model = android.os.Build.MODEL;
if (model.startsWith(&#34;POCOPHONE F1&#34;))
{
BlockDisplayCutout = false;
}
}
else if (android.os.Build.MANUFACTURER.equals(&#34;OnePlus&#34;))
{
String model = android.os.Build.MODEL;
if (model.startsWith(&#34;KB2000&#34;) || model.startsWith(&#34;KB2001&#34;) || model.startsWith(&#34;KB2003&#34;) ||
model.startsWith(&#34;KB2005&#34;) || model.startsWith(&#34;KB2007&#34;) || model.startsWith(&#34;LE2110&#34;) ||
model.startsWith(&#34;LE2111&#34;) || model.startsWith(&#34;LE2113&#34;) || model.startsWith(&#34;LE2115&#34;) ||
model.startsWith(&#34;LE2117&#34;) || model.startsWith(&#34;LE2119&#34;) || model.startsWith(&#34;LE2100&#34;) ||
model.startsWith(&#34;LE2101&#34;) || model.startsWith(&#34;LE2120&#34;) || model.startsWith(&#34;LE2121&#34;) ||
model.startsWith(&#34;LE2123&#34;) || model.startsWith(&#34;LE2125&#34;) || model.startsWith(&#34;LE2127&#34;) ||
model.startsWith(&#34;IN2020&#34;) || model.startsWith(&#34;IN2021&#34;) || model.startsWith(&#34;IN2023&#34;) ||
model.startsWith(&#34;IN2025&#34;) || model.startsWith(&#34;IN2010&#34;) || model.startsWith(&#34;IN2011&#34;) ||
model.startsWith(&#34;IN2013&#34;) || model.startsWith(&#34;IN2015&#34;) || model.startsWith(&#34;IN2017&#34;) ||
model.startsWith(&#34;IN2019&#34;) || model.startsWith(&#34;AC2001&#34;) || model.startsWith(&#34;AC2003&#34;) ||
model.startsWith(&#34;BE2025&#34;) || model.startsWith(&#34;BE2026&#34;) || model.startsWith(&#34;BE2028&#34;) ||
model.startsWith(&#34;BE2029&#34;))
{
BlockDisplayCutout = false;
}
}
if (BlockDisplayCutout)
{
UseDisplayCutout = false;
}
if (UseDisplayCutout)
{
// only do this on Android Pie and above
if (android.os.Build.VERSION.SDK_INT >= 28)
{
WindowManager.LayoutParams params = getWindow().getAttributes();
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(params);
}
else
{
UseDisplayCutout = false;
}
}这段代码UE4和UE5是有区别的。UE5默认值是通过boolean BlockDisplayCutout = android.os.Build.VERSION.SDK_INT < 30;判断,但UE4是默认为true,后面再通过手机型号判断是否需要忽略Cutout的配置。
从代码中可以看到,闪屏同样会设置是否使用刘海后者挖孔。
两种解决方法
如果你的项目就是UE4开发的,并且不想升级到UE5。毕竟升级是有代价和风险的。那么可以尝试这两种方法。
1. 通过UPL修改
这种方式需要你对UPL了解,前面提到一个教程会告诉你如何在UE4、UE5中进行Android开发。Unreal Engine 5语音SDK接入案例
前面提到了全屏关键的几行代码,我们只需要在UPL里将那几行代码插入即可。但只能修改GameActivity,闪屏界面还是不能全屏,所以在项目设置里取消显示闪屏界面。自己开发一个闪屏界面。
然后在UPL文件中插入以下代码,将java代码插入到GameActivity的OnCreate中。这样游戏界面就可以全屏了。
<!--添加代码到OnCreate函数的Super后面-->
<gameActivityOnCreateAdditions>
<insert>
try {
String packageName = getPackageName();
PackageManager pm = getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
if(bundle.containsKey(&#34;com.epicgames.ue4.GameActivity.bUseDisplayCutout&#34;))
{
UseDisplayCutout = bundle.getBoolean(&#34;com.epicgames.ue4.GameActivity.bUseDisplayCutout&#34;);
}
}
catch (NameNotFoundException | NullPointerException e)
{
Log.error(&#34;Error when accessing application metadata&#34;, e);
}
if (UseDisplayCutout)
{
// will not be true if not Android Pie or later
WindowManager.LayoutParams paramsA = getWindow().getAttributes();
paramsA.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(paramsA);
}
</insert>
</gameActivityOnCreateAdditions>这种方法有个缺陷,就是前面提到的闪屏界面需要特殊处理。(如果你会接入SDK,那这也不是个事)
2. 通过修改闪屏代码
这种方法比较直接和粗暴,但效果甚好。UE4、UE5打包Android生成了这么多代码,总有地方去修改这些代码吧。找到他们不就好了。
生成的Android工程代码
不论是GameApplication也好,GameActivity也好。还是SplashActivity。他们都是在UBT的时候生成。在UBT里有一份Android打包的代码UEBuildAndroid.cs、UEDeployAndroid.cs有兴趣可以去翻翻。
这里直接说结果,Engine\Build\Android\Java\src\com\epicgames\ue4到这里取找SplashActivity可以看到,就是完整的代码,并不是模板。那我们将该代码中关于是否忽略UseDisplayCutout的代码修改成与UE5一样就可以了。boolean BlockDisplayCutout = android.os.Build.VERSION.SDK_INT < 30;
这种方法修改了引擎原本的内容,一定要记好。不然更新或升级的时候出Bug就不好了。
重新打包试试,问题完美解决。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|