Unity6でandroidのsafeAreaの判定が変わったようで、端末によっては下のナビゲーションバーの部分にアプリのUIが食い込むようになってしまった
なので色々と試して調整していった結果、下記のようなコードだとひとまずナビゲーションにめりこまなくなった
using UnityEngine;
[RequireComponent(typeof(RectTransform))]
public class SafeAreaAdjuster : MonoBehaviour
{
private RectTransform panel;
private Rect lastAppliedSafeArea = Rect.zero;
private ScreenOrientation lastOrientation = ScreenOrientation.Unknown;
void Awake()
{
panel = GetComponent<RectTransform>();
}
void OnEnable()
{
ApplySafeArea();
}
void Update()
{
if (Screen.orientation != lastOrientation || Screen.safeArea != lastAppliedSafeArea)
{
ApplySafeArea();
}
}
void ApplySafeArea()
{
Rect safeArea = Screen.safeArea;
#if UNITY_ANDROID && !UNITY_EDITOR
int nativeNavBarHeight = GetNavigationBarHeight();
// 下部のみ、UnityのAPIとネイティブAPIの大きい方を採用する
float bottomInset = Mathf.Max(safeArea.y, nativeNavBarHeight);
float heightDifference = bottomInset - safeArea.y;
if(heightDifference > 0)
{
safeArea.y = bottomInset;
safeArea.height -= heightDifference;
}
#endif
ApplyRect(safeArea);
lastAppliedSafeArea = safeArea;
lastOrientation = Screen.orientation;
}
void ApplyRect(Rect area)
{
if (Screen.width == 0 || Screen.height == 0) return;
panel.anchorMin = new Vector2(area.x / Screen.width, area.y / Screen.height);
panel.anchorMax = new Vector2((area.x + area.width) / Screen.width, (area.y + area.height) / Screen.height);
}
}
public static int GetNavigationBarHeight()
{
#if UNITY_ANDROID && !UNITY_EDITOR
try
{
using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
using (var activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
using (var window = activity.Call<AndroidJavaObject>("getWindow"))
using (var windowManager = window.Call<AndroidJavaObject>("getWindowManager"))
using (var metrics = windowManager.Call<AndroidJavaObject>("getCurrentWindowMetrics"))
using (var insets = metrics.Call<AndroidJavaObject>("getWindowInsets"))
{
var systemBarInsets = insets.Call<AndroidJavaObject>("getInsets", new AndroidJavaClass("android.view.WindowInsets$Type").CallStatic<int>("systemBars"));
return systemBarInsets.Get<int>("bottom");
}
}
catch (System.Exception) { /* Fallback can be added here if needed */ }
#endif
return 0;
}
下部のところをどのくらいあけるか、という判定にsafeAreaだけでなくandroidのネイティブAPIも使って高さを取得する
そしてより大きい方の数値を採用する、という仕組みになっている
これだとどの端末(エミュレーター)でもとりあえずナビゲーションにUIが埋まらなくなった
でもそのかわりというべきか、ナビゲーションバーの上に空白ができるようにもなった
これは端末によってできたりできなかったりする
ナビゲーションの上にぴったりつくものもある
Pixel5 api32のエミュレーターだと下側に隙間ができる
Pixel9 api36のエミュレーターだとぴったり合う
GetNavigationBarHeightでネイティブAPIから値を取っているのだけど、これを入れないとナビゲーションの中に埋まってしまうこともあるので使っている
どうもこのあたりの数値の取れ方がUnity6ではまちまちになっているようだ
Unity2022を使っていた時はこういったことはなかったんだけどね
ちなみにこのネイティブAPIはandroid api 30以降でないと動作しないはず
もしも使う場合はそのあたり気をつけてください
けっこう入念に検証はしましたが(api30〜36でチェック)、あらゆる端末で動作するという保証もありません
他によい解決法があるのかもしれないけど、とりあえずUIが埋まらないことが重要なのでこのコードを使うことした