How to not cover up the Android/iOS top status bar (eg. with time, icons) in mobile app?

I am making an Android/iOS mobile app. Currently, when I build it and install it (for example from APK to Android) it loads completely full screen covering up the top phone status bar which usually shows the time, network signal, wifi icons, etc.

I see an option in Project Settings > Player for “Hide Navigation Bar” - unchecking this I believe lets you see the bottom on screen navigation buttons like home, back, etc. However I see no option to show/hide the top status bar.

Is there some way to do this?

Thanks.

1 Like

iOS has an option called “Status Bar Hidden” which should do what you want if you turn it off. I cannot see a similar option for Android.

1 Like

You can do it through script (for API 30+). This is what I’ve gathered:
using (var unityPlayer = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”)) {
using (var activity = unityPlayer.GetStatic(“currentActivity”)) {
using (var window = activity.Call(“getWindow”)) {
using (var Decor= window.Call(“getDecorView”)) {
using (var controller = Decor.Call(“getWindowInsetsController”)) {
using (var type = new AndroidJavaClass(“android.view.WindowInsets$Type”)) {
controller.Call(“show”, type.CallStatic(“statusBars”));
}}}
window.Call(“setStatusBarColor”, unchecked((int)0x00005700)); //for transparent status bar
}}}}

your game will however overlap with the statusbars so I calculate the pixelheight of the bar with:

static int getStatusHeight(){
AndroidJavaClass up = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”);
AndroidJavaObject ca = up.GetStatic(“currentActivity”);
var windowManager=ca.Call(“getWindowManager”);
var wMetrics=windowManager.Call(“getCurrentWindowMetrics”);
var insets= wMetrics.Call(“getWindowInsets”);

return insets.Call(“getStableInsetTop”);
}
int result = getStatusHeight();

If anyone got anything smpler, I’m all ears though.

Hey lagpie. Thanks for providing your solution.

I posted the question over at StackExchange also and two solutions were posted there which both seem to work handling it a different way. The problem with both those solutions is they also show the navigation bar (bottom buttons) which I don’t want:

https://gamedev.stackexchange.com/questions/198126/how-to-not-cover-up-the-android-ios-top-status-bar-eg-with-time-network-wifi

Your solution works better as in one way as it at least initially doesn’t force the navigation bar (bottom buttons) to display as well like those solutions. However, I notice if I run your script more than once in a project (eg. on a scene, then reload the scene), the bottom navigation bar comes back as well with it. I don’t know why that happens.

Yours is also interesting as on my Galaxy it rearranges things automatically around the status bar. So I would not have to measure status bar height. Yet in android studio emulator with your solution the status bar overlaps the screen. So it seems to be inconsistent what it does.

Their solutions allow the screen to auto-resize to fit the space under the status bar on both my Galaxy and Android studio emulator. That is obviously better as it is consistent behavior with no need for measuring or adjusting around the status bar.

You obviously understand this far better than I do. I wonder if looking at those scripts might give you any ideas that could help us always get the automatic screen fitting and status bar from those solutions but without the navigation bar being forced active as well.

That would be the most ideal conclusion probably for both of us. I hope it is possible. Thanks again for your help.

I did a bit more testing and I figured out the reason the methods at StackExchange don’t work is they require you to leave full screen mode which automatically shows the nav bar. This doesn’t work then of course.

I also figured out the reason I was not seeing the status bar only overlap using lagpie’s method on my Galaxy is the “render safe zone only” setting was keeping my app out of the status bar region on Galaxy. But on a notchless phone this won’t work.

I think the correct solution is to do what you did Lagpie. My elements are all on UI canvas, so my solution was then to add an empty object to my canvas as parent to everything else with a stretched rect transform and modify the top margin according to your status bar height detection script.

This seems to work. Thanks.

Glad it’s working. I don’t think it’s a good idea to use the you linked to since it won’t work on newer versions of android (check out: View  |  Android Developers and search on the page for "
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN"). I also think it’s weird that it would show the navigation bar aswell with my script (I haven’t had any problem with it since I want the navigation bar showing). one thing you could try is simply adding:
controller.Call(“hide”, type.CallStatic(“navigationBars”));
just after the other controller.call and see if that works.

The only thing I can think of why it’s inconsistent with the overlap is that maybe your devices use different android versions.
What you should idealy do is check for the API-version of the android device before executing the cod

static int getSDKInt() {
   using (var version = new AndroidJavaClass("android.os.Build$VERSION")) {
     return version.GetStatic<int>("SDK_INT");
   }
}

int SDK_INT = getSDKInt();

and use my script only when API >= 30.

if you want the navigation bars gone in the other script you could try adding:

window.Call("setFlags", 512, 512);

just after this code in the other script.

 public static void ShowStatusBar(Color color)
        {
            int androidColor = ConvertColorToAndroidColor(color);
            RunOnUiThread(() =>
                {
                    using (var window = Window)
                    {
                        window.Call("clearFlags", SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

Haven’t tested this though but it should work.

Hey Lagpie.

Hey Lagpie. Thanks for the reply. At least certainly I can say if I only run it once with your script it works, and that is good enough as i can easily force it to only run once. I will test further what happens if it runs twice and your extra code later for this.

I tried adding

window.Call("setFlags", 512, 512);

To the other script by this then prevents it from showing either the status bar or the navigation bar which is no good. So yours remains the only working script I have seen.

I have noticed one small quirk to your script though which is causing me problems. If I try to run commands after it they seem to fail, indicating there may be something breaking from it invisibly. I described the phenomenon and some code that shows it here:

https://gamedev.stackexchange.com/questions/198200/why-does-the-order-of-these-two-functions-matter-if-one-goes-first-they-both-ru?noredirect=1#comment359954_198200

I’m struggling to get my APK running properly in Android Studio to see if I can find the issue. I would appreciate if you could guess where the issue might be coming from. I’m testing on a brand new Samsung S21+ which is the new flagship so it should be up to date.

Thanks again.

Hello, @mikemohan & @lagpie
Im triying to use your code, but I dont sure where to put in my script (if go on a static class/ static void o something else), sorry im novice.

public class DisableFullScreenV4 : MonoBehaviour
{
    public static int SDK_INT; //get value 0 if I call from another script
    public static int result; //get value 0 if I call from another script

    void Start()
    {
        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 Decor = window.Call<AndroidJavaObject>("getDecorView"))
                    {
                        using (var controller = Decor.Call<AndroidJavaObject>("getWindowInsetsController"))
                        {
                            using (var type = new AndroidJavaClass("android.view.WindowInsets$Type"))
                            {
                                controller.Call("show", type.CallStatic<int>("statusBars"));
                            }
                        }
                    }
                    window.Call("setStatusBarColor", unchecked((int)0x00005700)); //for transparent status bar
                }
            }
        }

        static int getStatusHeight()
        {
            AndroidJavaClass up = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject ca = up.GetStatic<AndroidJavaObject>("currentActivity");
            var windowManager = ca.Call<AndroidJavaObject>("getWindowManager");
            var wMetrics = windowManager.Call<AndroidJavaObject>("getCurrentWindowMetrics");
            var insets = wMetrics.Call<AndroidJavaObject>("getWindowInsets");

            return insets.Call<int>("getStableInsetTop");
        }
        result = getStatusHeight();

        static int getSDKInt()
        {
            using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
            {
                return version.GetStatic<int>("SDK_INT");
            }
        }
        SDK_INT = getSDKInt();

        Debug.Log("Android Version:" + SDK_INT); //not showing up
        Debug.Log("Bar Height:" + result); //not showing up
    }
}

this is my code so far, but is not working, im getting value 0 in my two static int. and debug log not working too.
Can you give me some guidance?, thanks

Try putting an extra Debug.Log(“Run Script”) line at the top of the script just to be sure. ie. Just under the line for Start. If that doesn’t debug anything out then obviously the script is not running at all.

You will have to attach this script to a game object in your scene for it to run. Or alternatively, you must run the script’s function from another script that’s on a game object in your scene.

Lastly, you defined the two functions within Start. You want to define them outside of start, then either run them in Start or Awake. Lastly, you are best running this on Awake rather than Start.

So you could redo it like this:

public class DisableFullScreenV4 : MonoBehaviour
{
    public static int SDK_INT; //get value 0 if I call from another script
    public static int result; //get value 0 if I call from another script
    void Awake(){
           Debug.Log("SCRIPT RUN");
           disableFullScreen();
           result = getStatusHeight();   
           SDK_INT = getSDKInt();
        Debug.Log("Android Version:" + SDK_INT);
        Debug.Log("Bar Height:" + result);
}
    static void disableFullScreen()
    {
        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 Decor = window.Call<AndroidJavaObject>("getDecorView"))
                    {
                        using (var controller = Decor.Call<AndroidJavaObject>("getWindowInsetsController"))
                        {
                            using (var type = new AndroidJavaClass("android.view.WindowInsets$Type"))
                            {
                                controller.Call("show", type.CallStatic<int>("statusBars"));
                            }
                        }
                    }
                    window.Call("setStatusBarColor", unchecked((int)0x00005700)); //for transparent status bar
                }
            }
        }

        static int getStatusHeight()
        {
            AndroidJavaClass up = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            AndroidJavaObject ca = up.GetStatic<AndroidJavaObject>("currentActivity");
            var windowManager = ca.Call<AndroidJavaObject>("getWindowManager");
            var wMetrics = windowManager.Call<AndroidJavaObject>("getCurrentWindowMetrics");
            var insets = wMetrics.Call<AndroidJavaObject>("getWindowInsets");

            return insets.Call<int>("getStableInsetTop");
        }

        static int getSDKInt()
        {
            using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
            {
                return version.GetStatic<int>("SDK_INT");
            }
        }
      

    }
}

I don’t know if i got all the brackets there but hopefully that makes sense. The point is you have to run your functions under Awake or Start or Update in most cases or they won’t run on their own. And you need the script attached to a game object for Start or Awake to function.

I’m using this code, but it appears very strange. It’s like is going to cover my UI.

And as you can see from the image the color is not transparent. I attached the script to the camera. Here is it:

public class DisableFullScreen : MonoBehaviour
{
    public static int SDK_INT; //get value 0 if I call from another script
    public static int result; //get value 0 if I call from another script
    void Start()
    {
        disableFullScreen();
        result = getStatusHeight();
        SDK_INT = getSDKInt();
    }

    static void disableFullScreen()
    {
        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 Decor = window.Call<AndroidJavaObject>("getDecorView"))
                    {
                        using (var controller = Decor.Call<AndroidJavaObject>("getWindowInsetsController"))
                        {
                            using (var type = new AndroidJavaClass("android.view.WindowInsets$Type"))
                            {
                                controller.Call("show", type.CallStatic<int>("statusBars"));
                            }
                        }
                    }
                    window.Call("setStatusBarColor", unchecked((int)0x00005700)); //for transparent status bar
                    window.Call("setFlags", 512, 512); //hide navigation bar
                }
            }
        }
    }

    static int getStatusHeight()
    {
        AndroidJavaClass up = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject ca = up.GetStatic<AndroidJavaObject>("currentActivity");
        var windowManager = ca.Call<AndroidJavaObject>("getWindowManager");
        var wMetrics = windowManager.Call<AndroidJavaObject>("getCurrentWindowMetrics");
        var insets = wMetrics.Call<AndroidJavaObject>("getWindowInsets");

        return insets.Call<int>("getStableInsetTop");
    }

    static int getSDKInt()
    {
        using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
        {
            return version.GetStatic<int>("SDK_INT");
        }
    }
}

8442638--1119149--1663267600871.jpg

thank you afurioso!!! I slightly edited your code and the status bar after welding works! use for health

using UnityEngine;

public class DisableFullScreen : MonoBehaviour
{
public static int SDK_INT;
public static int result;

void Start()
{
disableFullScreen();
result = getStatusHeight();
SDK_INT = getSDKInt();
}

void OnApplicationPause(bool pauseStatus)
{
if (pauseStatus)
{
// Приложение находится на паузе
// Добавьте здесь необходимый код для обработки события паузы
}
else
{
// Приложение возобновляет работу
// Добавьте здесь необходимый код для обработки события возобновления работы
disableFullScreen();
result = getStatusHeight();
SDK_INT = getSDKInt();
}
}

static void disableFullScreen()
{
using (var unityPlayer = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”))
{
using (var activity = unityPlayer.GetStatic(“currentActivity”))
{
using (var window = activity.Call(“getWindow”))
{
using (var Decor = window.Call(“getDecorView”))
{
using (var controller = Decor.Call(“getWindowInsetsController”))
{
using (var type = new AndroidJavaClass(“android.view.WindowInsets$Type”))
{
controller.Call(“show”, type.CallStatic(“statusBars”));
}
}
}
window.Call(“setStatusBarColor”, unchecked((int)0x00005700)); //for transparent status bar
window.Call(“setFlags”, 512, 512); //hide navigation bar
}
}
}
}

static int getStatusHeight()
{
AndroidJavaClass up = new AndroidJavaClass(“com.unity3d.player.UnityPlayer”);
AndroidJavaObject ca = up.GetStatic(“currentActivity”);
var windowManager = ca.Call(“getWindowManager”);
var wMetrics = windowManager.Call(“getCurrentWindowMetrics”);
var insets = wMetrics.Call(“getWindowInsets”);

return insets.Call(“getStableInsetTop”);
}

static int getSDKInt()
{
using (var version = new AndroidJavaClass(“android.os.Build$VERSION”))
{
return version.GetStatic(“SDK_INT”);
}
}
}