How to detect if a mobile is running the WebGL scene

Hi all,

Is there a way to detect if a mobile is using WebGL at run-time?

I’ve tried Application.isMobilePlatform, but it seems to return false, as I guess the run-time platform isn’t actually mobile, but WebGL instead. Maybe I need to use System.Info or something similar? However, I was wondering if Unity had something built in for this?

In the Unity installation folder, PlaybackEngines/WebGLSupport/BuildTools/UnityConfig/UnityConfig.js contains code to do that. You could do the same in a simple jslib and create the corresponding C# binding.

Does that make sense ?

3 Likes

Hi Marco, yes that makes sense, got it all implemented. Thanks!

I’m pretty new to developing and can wrap my head around how to use C# for scripting for a webgl project I’m working but need it to detect whether it’s running on mobile and don’t understand what I need to do here. Could you point me in the right direction for how to create this jslib and C# binding? I’m also unable to find the UnityConfig.js on my system. Thanks for any help!

You can get that information in Javascript from UnityLoader.SystemInfo.mobile:
For example, in your html:

    <script src="Build/UnityLoader.js"></script>
    </script>
      console.log("mobile: " + UnityLoader.SystemInfo.mobile);
    </script>

will print true/false depending on whether it’s running on a mobile browser.
So, the idea is that you make your own jslib (see manual) to get that information from JS to C#.
does that make sense?

5 Likes

Thanks for the tip Marco-Trivellato.

I think the guy (rdurland) was stating that he is really new to dev and he uses C# + VS + Unity. Any other platform or language can be a problem for him (or - was) so writing about html is propably not that good idea.

There is simple explanation what to do, step by step:

4 Likes

Please don’t necro old threads

The WebGL Template has been changed in 2020.1 which includes detecting Mobile clients.
You could use the same logic.

if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent))
{
  container.className = "unity-mobile";
  config.devicePixelRatio = 1;
}
else
{
  canvas.style.width = "100%";
  canvas.style.height = "100%";
}
2 Likes

I do this from a jslib (same as @MaskedMouse suggested done within Unity),

mergeInto(LibraryManager.library, {
  IsMobileBrowser: function () {
    return (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent));
  }, [...]
1 Like

Hey,
Could you explain more?
I’m new to WebGL Unity and I’m facing a problem with the Retina display on MacBooks
On windows it is all great and the FPS is 45-60 and the resolution is 1920 * 1xxx. On Macs the performance drops to 13-17 because of Retina and the resolution is 3300 * 2100 (double the laptop’s resolution).It is because the Macs DPI is 2.
Do you think your solution could solve this ? Like could I detect the Macs and change the DPI ? and where should I add this part of code ?
Thanks in advance

@MaskedMouse ’ s code example shows how rendering to low/standard DPI is done. In the main .html file, set “config.devicePixelRatio = 1;” to override the DPI rendering scale. This works in Unity 2020.1 and newer iirc.

Hi. I’m new to Unity WebGL and I’m still not very sure how to detect if a mobile is running in the WebGL Scene. The attached image is the error that I got after building and running it. I’ve also took reference from Detect mobile client in webgl - Questions & Answers - Unity Discussions, and the previous messages, but it still does not work.

This is the script in my jslib file:

var CheckMobile = {
    IsMobile : function()
    {
        return UnityLoader.SystemInfo.mobile;
    }
};
mergeInto(LibraryManager.library, CheckMobile);

This is my Unity script file:

using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;
public class StartSceneController : MonoBehaviour
{
    private bool playOnce = false;
    public Text text;
    [DllImport("__Internal")]
    private static extern bool IsMobile();
    void Start()
    {
        text.text = "";
    }
    public bool isMobile()
    {
#if !UNITY_EDITOR && UNITY_WEBGL
            return IsMobile();
#endif
        return false;
    }
    void Update()
    {
        if (playOnce == false)
        {
            text.text = "Mobile: " + isMobile();
            playOnce = true;
        }
    }
}

Could anyone help?

6467314--725665--Screenshot_3.png

1 Like

The variable UnityLoader is not available in that JavaScript function scope. Try replacing the content of that function with

var CheckMobile = {
    IsMobile : function()
    {
        return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
    }
};
mergeInto(LibraryManager.library, CheckMobile);

or use the Application.isMobilePlatform API (Unity - Scripting API: Application.isMobilePlatform)

This might also work:

var CheckMobile = {
    IsMobile : function()
    {
        return Module.SystemInfo.mobile;
    }
};
mergeInto(LibraryManager.library, CheckMobile);

(although not 100% sure on that form)

Hi @Siba_M_M . We have an asset for your problem. The asset is modifying the DPI dynamically depending on current FPS. If FPS is too low, the asset will reduce DPI automatically. And it is effortless totally. You should just add the prefab to your scene, That’s all.

You can check here;
WebGL FPS Accelerator

Hi @jukka_j . Thank you so much for your assistance. It can now detect if I am running it on Mobile devices. Thanks a lot! :slight_smile:

thank you for this but might i ask a question!? like how do we actually use it? i mean i have made a cross platform input system for a webgl game im making. inside unity it works fine ( when tested on device emulator it creates buttons on screen and when not you can move it the player with the keyboard and some other things ) but once i uploaded it to a testing server to try it , it didnt work, it detected it as webgl so i found this thread and used this code ( havent tested it yet ) but assuming in my case i want to use the code i have made already how would i do it??

this is the system check script
and ive added the code from above!

using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SystemDetect : MonoBehaviour
{
    public GameObject mobileControls;
    public GameObject portraitWarning;

    private bool playOnce = false;
    public Text text;
    [DllImport("__Internal")]
    private static extern bool IsMobile();
    void Start()
    {
        text.text = "";
    }
    public bool isMobile()
    {
#if !UNITY_EDITOR && UNITY_WEBGL
            return IsMobile();
#endif
        return false;
    }
    // Start is called before the first frame update

    // Update is called once per frame
    void Update()
    {
        if (Application.platform == RuntimePlatform.WindowsEditor)
        {
            Debug.Log("webgl/windows");
            Input.GetAxis("Horizontal");

        }
        else if (Application.platform == RuntimePlatform.Android)
        {
            if (Screen.orientation == ScreenOrientation.Portrait)
            {
                portraitWarning.SetActive(true);
            }
            else if (Screen.orientation == ScreenOrientation.Landscape)
            {
                portraitWarning.SetActive(false);
            }

            Debug.Log("Mobile");
            mobileControls.SetActive(true);
        }

    }
    public void Play()
    {
        if (Application.platform == RuntimePlatform.Android)
        {
            if (Screen.orientation == ScreenOrientation.Landscape)
            {
                SceneManager.LoadScene("Menu");
            }
        }else if (Application.platform == RuntimePlatform.WindowsEditor)
        {
            SceneManager.LoadScene("Menu");
        }

    }
    public void ToggleFullScreen()
    {
        // Toggle fullscreen
        Screen.fullScreen = !Screen.fullScreen;
    }
}

and this my my controls. as you can see its nothing just a testing game to get things right

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControl : MonoBehaviour
{
    public float moveSpeed;
    private float movement;
    private bool moveRight;
    private bool moveLeft;
    private Rigidbody2D rb2d;

    // Start is called before the first frame update
    void Start()
    {
       
        rb2d = GetComponent<Rigidbody2D>();
        moveLeft = false;
        moveRight = false;
    }

    // Update is called once per frame
    void Update()
    {
       if (Application.platform == RuntimePlatform.WindowsEditor)
        {
           desktopMovement();
       }
        else if (Application.platform == RuntimePlatform.Android)
        {
            mobileMovement();
            rb2d.velocity = new Vector2(movement, rb2d.velocity.y);
        }
    }

    void desktopMovement()
    {
        movement = Input.GetAxis("Horizontal");
        rb2d.velocity = new Vector2(movement * moveSpeed, rb2d.velocity.y);
    }
    void mobileMovement()
    {
        if (moveLeft)
        {
            movement = -moveSpeed;
        }
        else if (moveRight)
        {
            movement = moveSpeed;
        }
        else
        {
            movement = 0;
        }
       
    }

    //settting up ui buttons movement
    public void PointerDownLeft()
    {
        moveLeft = true;
    }
    public void PointerUpLeft()
    {
        moveLeft = false;
    }
    public void PointerDownRight()
    {
        moveRight = true;
    }
    public void PointerUpRight()
    {
        moveRight = false;
    }

}

Create a file called like “Assets/Plugins/webgl.jslib” - this adds the Javascript to your project:

mergeInto(LibraryManager.library, {
  IsMobileBrowser: function () {
    return (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent));
  }
});

Then create a file like “Assets/Scripts/WebGLHandler.cs” to expose the functions from the .jslib that you want access to from C#:

using UnityEngine;
using System.Runtime.InteropServices;
public class WebGLHandler : MonoBehaviour
{
  [DllImport("__Internal")]
  public static extern bool IsMobileBrowser();
}

Then make something like “Assets/Scripts/Platform.cs” to wrap conditional compilation:

public class Platform
{
  public static bool IsMobileBrowser()
  {
#if UNITY_EDITOR
    return false; // value to return in Play Mode (in the editor)
#elif UNITY_WEBGL
    return WebGLHandler.IsMobileBrowser(); // value based on the current browser
#else
    return false; // value for builds other than WebGL
#endif
  }
}

Then anywhere you want, you can do this:

if (Platform.IsMobileBrowser())
{
  // whatever for mobile browser
} else {
  // whatever for desktop browser
}

Edit: I don’t think you need the “WebGLHandler” to extend from MonoBehaviour, I just stripped the above example down from stuff I do. You could probably remove : MonoBehaviour and remove the using UnityEngine; from the top of that.

Edit: You could probably also combine WebGLHandler and Platform into the same class, just based the snippets on how I have things structured without much attention to simplifying.

7 Likes

thank you for your help , its a great start for me, but i cant get it work on Unity 2020. i changed all my code to this , but still it doesnt show the warning screen that forces the user to rotate the phone or the virtual buttons!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerControl : MonoBehaviour
{
    public float moveSpeed;
    private float movement;
    private bool moveRight;
    private bool moveLeft;
    private Rigidbody2D rb2d;

    // Start is called before the first frame update
    void Start()
    {
      
        rb2d = GetComponent<Rigidbody2D>();
        moveLeft = false;
        moveRight = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (PlatformOS.IsMobileBrowser())
        {
            mobileMovement();
            rb2d.velocity = new Vector2(movement, rb2d.velocity.y);
        }
        else
        {
           desktopMovement();
       }
 
    }

    void desktopMovement()
    {
        movement = Input.GetAxis("Horizontal");
        rb2d.velocity = new Vector2(movement * moveSpeed, rb2d.velocity.y);
    }
    void mobileMovement()
    {
        if (moveLeft)
        {
            movement = -moveSpeed;
        }
        else if (moveRight)
        {
            movement = moveSpeed;
        }
        else
        {
            movement = 0;
        }
      
    }

    //settting up ui buttons movement
    public void PointerDownLeft()
    {
        moveLeft = true;
    }
    public void PointerUpLeft()
    {
        moveLeft = false;
    }
    public void PointerDownRight()
    {
        moveRight = true;
    }
    public void PointerUpRight()
    {
        moveRight = false;
    }

}

and the gameManager Object that handles the controlls

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SystemDetect : MonoBehaviour
{
    public GameObject mobileControls;
    public GameObject portraitWarning;

    // Start is called before the first frame update
    void Start()
    {

    }
    // Update is called once per frame
    void Update()
    {
        if (PlatformOS.IsMobileBrowser())
        {
            if (Screen.orientation == ScreenOrientation.Portrait)
            {
                portraitWarning.SetActive(true);
            }
            else if (Screen.orientation == ScreenOrientation.Landscape)
            {
                portraitWarning.SetActive(false);
            }

            Debug.Log("Mobile");
            mobileControls.SetActive(true);
        }
        else
        {
            Debug.Log("webgl/windows");

        }


    }
    public void Play()
    {
        if (PlatformOS.IsMobileBrowser())
        {
            if (Screen.orientation == ScreenOrientation.Landscape)
            {
                SceneManager.LoadScene("Menu");
            }
        }
        else
        {
            SceneManager.LoadScene("Menu");
        }

    }
    public void ToggleFullScreen()
    {
        // Toggle fullscreen
        Screen.fullScreen = !Screen.fullScreen;
    }
}

It might be a problem with orientation, not sure if that works on WebGL like it does for mobile platforms - you could try replacing this:

if (Screen.orientation == ScreenOrientation.Portrait)
            {
                portraitWarning.SetActive(true);
            }
            else if (Screen.orientation == ScreenOrientation.Landscape)
            {
                portraitWarning.SetActive(false);
            }

With this:

portraitWarning.SetActive(Screen.width < Screen.height);

Also, you could throw Debug.Log statements around and check the javascript console to see what’s going wrong.