ainatipen 发表于 2023-1-22 14:53

【UE4】新买的红米K50和一加Ace Pro安装UE4打包的程序 ...

问题描述:

最近新买了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="com.epicgames.ue4.GameActivity.bUseDisplayCutout" android:value="true" />
<meta-data android:name="android.max_aspect" android:value="2.30" />不出意外的话,你的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("com.epicgames.unreal.GameActivity.bUseDisplayCutout"))
        {
                UseDisplayCutout = bundle.getBoolean("com.epicgames.unreal.GameActivity.bUseDisplayCutout");
                Log.debug( "Display cutout set to " + UseDisplayCutout);
        }
        else
        {
                Log.debug( "Display cutout not found. Leaving as " + UseDisplayCutout);
        }
}
_extrasBundle = getIntent().getExtras();
if (_extrasBundle != null)
{
        ShouldHideUI = _extrasBundle.getString("ShouldHideUI") != null;
        UseDisplayCutout = _extrasBundle.getString("UseDisplayCutout") != null;
}那闪屏界面又是从哪里获取的呢?截取部分闪屏界面代码,可以看到同样是从Manifest获取的。并且还加了一些手机型号的判断,进而最终确认。
try {
        ApplicationInfo ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
        Bundle bundle = ai.metaData;

        if(bundle.containsKey("com.epicgames.unreal.GameActivity.bUseDisplayCutout"))
        {
                UseDisplayCutout = bundle.getBoolean("com.epicgames.unreal.GameActivity.bUseDisplayCutout");
        }
}
catch (NameNotFoundException | NullPointerException e)
{
        Log.error("Error when accessing application metadata", 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("HUAWEI"))
{
        BlockDisplayCutout = false;
}
else if (android.os.Build.MANUFACTURER.equals("HMD Global"))
{
        String model = android.os.Build.MODEL;
        if (model.equals("Nokia 8.1"))
        {
                BlockDisplayCutout = false;
        }
}
else if (android.os.Build.MANUFACTURER.equals("samsung"))
{
        String model = android.os.Build.MODEL;
        if (model.startsWith("SM-G970") || model.startsWith("SM-G973") || model.startsWith("SM-G975") ||
                model.startsWith("SC-03L") || model.startsWith("SCV41") || model.startsWith("SC-04L") ||
                model.startsWith("SCV42") || model.startsWith("SM-N97") || model.startsWith("SM-F700") ||
                model.startsWith("SM-G98") || model.startsWith("SCV47") || model.startsWith("SCG01") ||
                model.startsWith("SCG02") || model.startsWith("SC-51A") || model.startsWith("SC-52A") ||
                android.os.Build.VERSION.SDK_INT >= 28)
        {
                BlockDisplayCutout = false;
        }
}
else if (android.os.Build.MANUFACTURER.equals("Xiaomi"))
{
        String model = android.os.Build.MODEL;
        if (model.startsWith("POCOPHONE F1"))
        {
                BlockDisplayCutout = false;
        }
}
else if (android.os.Build.MANUFACTURER.equals("OnePlus"))
{
        String model = android.os.Build.MODEL;
        if (model.startsWith("KB2000") || model.startsWith("KB2001") || model.startsWith("KB2003") ||
                model.startsWith("KB2005") || model.startsWith("KB2007") || model.startsWith("LE2110") ||
                model.startsWith("LE2111") || model.startsWith("LE2113") || model.startsWith("LE2115") ||
                model.startsWith("LE2117") || model.startsWith("LE2119") || model.startsWith("LE2100") ||
                model.startsWith("LE2101") || model.startsWith("LE2120") || model.startsWith("LE2121") ||
                model.startsWith("LE2123") || model.startsWith("LE2125") || model.startsWith("LE2127") ||
                model.startsWith("IN2020") || model.startsWith("IN2021") || model.startsWith("IN2023") ||
                model.startsWith("IN2025") || model.startsWith("IN2010") || model.startsWith("IN2011") ||
                model.startsWith("IN2013") || model.startsWith("IN2015") || model.startsWith("IN2017") ||
                model.startsWith("IN2019") || model.startsWith("AC2001") || model.startsWith("AC2003") ||
                model.startsWith("BE2025") || model.startsWith("BE2026") || model.startsWith("BE2028") ||
                model.startsWith("BE2029"))
        {
                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。毕竟升级是有代价和风险的。那么可以尝试这两种方法。

[*]通过UPL修改为全屏
[*]通过修改闪屏界面代码
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("com.epicgames.ue4.GameActivity.bUseDisplayCutout"))
        {
                UseDisplayCutout = bundle.getBoolean("com.epicgames.ue4.GameActivity.bUseDisplayCutout");
        }
}
catch (NameNotFoundException | NullPointerException e)
{
        Log.error("Error when accessing application metadata", 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就不好了。

重新打包试试,问题完美解决。
页: [1]
查看完整版本: 【UE4】新买的红米K50和一加Ace Pro安装UE4打包的程序 ...