Unity6でandroidのsafeAreaの判定が変わったようなので、ネイティブAPIも交えて調整をした

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が埋まらないことが重要なのでこのコードを使うことした

タイトルとURLをコピーしました