UWP Getting Username Asyncronously using Unity

I am building a UWP app to pull the current Windows user DisplayName. When I build the app just using the native Visual Studio 2015 UWP C# API, the app builds fine and the username is populated once the user accepts their credentials to be accessed by the app.

When I run the same function through Unity with an added queue, I get the error:

3164864--240911--Capture.PNG

I have a script that I attached to a button. The function callFunction() is called on the On_Clicked() function from the Unity editor. Can anyone help? I did allow the User Account Information in the package manifest. Here is the script:

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

#if (!UNITY_EDITOR && UNITY_WSA_10_0)
using Windows.System;
using Windows.UI.Core;
#endif

public class login : MonoBehaviour
{

    public InputField login_field;
    public Button login_button;
    public Queue<Action> actions;

    //initialize queue
    void Start()
    {
        actions = new Queue<Action>();
    }

    //dequeue once action received
    void Update()
    {
        while (actions.Count > 0)
        {
            var action = actions.Dequeue();
            if (action != null)
                action();
        }
    }

    //enqueue when button pressed
    public void callFunction()
    {
        actions.Enqueue(() =>
        {
#if (!UNITY_EDITOR && UNITY_WSA_10_0)
                login_button_pressed();
#endif
        });
    }

    //function to pull current username
#if (!UNITY_EDITOR && UNITY_WSA_10_0)
    public async void login_button_pressed()
    {
        //find username
        IReadOnlyList<User> users = await User.FindAllAsync();

        var current = users.Where(p => p.AuthenticationStatus == UserAuthenticationStatus.LocallyAuthenticated &&
        p.Type == UserType.LocalUser).FirstOrDefault();

        //user may have username
        var data = await current.GetPropertyAsync(KnownUserProperties.DisplayName);
        string displayName = (string)data;

        //or may not be available
        if (String.IsNullOrEmpty(displayName))
        {
            displayName = "User";
        }

        login_field.text = displayName;
    }
#else
    void login_button_pressed()
    {
        login_field.text = "User";
    }
#endif
}

When await returns, you end up on another thread. You need to use this to get back on the main thread.

1 Like

This worked perfectly! Thanks for your help!

I replaced the text assignment with:

UnityEngine.WSA.Application.InvokeOnAppThread (() => {login_field.text = displayName;},false);
    }

I know this is a bit old, but I am having trouble with this script. After debugging, I can see that it gets stuck on line:var current = users.Where(p => p.AuthenticationStatus == UserAuthenticationStatus.LocallyAuthenticated && p.Type == UserType.LocalUser).FirstOrDefault();

There is no error, but before and after this line I made it display a text. The text before shows up but not after. Any ideas of what I am may be doing wrong?

^ Can you post your whole script?

Thank you so much for getting back to me so quickly! Here is my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Linq;
using TMPro;

#if (!UNITY_EDITOR)
using Windows.System;
using Windows.UI.Core;
#endif

public class UWPManager : MonoBehaviour
{
    public TextMeshPro username;
    public Queue<Action> actions;

    //initialize queue
    void Start()
    {
        actions = new Queue<Action>();

        actions.Enqueue(() =>
        {
            login_button_pressed();
        });
    }

    //dequeue once action received
    void Update()
    {
        while (actions.Count > 0)
        {
            var action = actions.Dequeue();
            if (action != null)
                action();
        }
    }

    //enqueue when button pressed
    public void callFunction()
    {
        actions.Enqueue(() =>
        {
#if (!UNITY_EDITOR)
            login_button_pressed();
#endif
        });
    }

    //function to pull current username
#if (!UNITY_EDITOR)
    public async void login_button_pressed()
    {
        //find username
        IReadOnlyList<User> users = await User.FindAllAsync();

        var current = users.Where(p => p.AuthenticationStatus == UserAuthenticationStatus.LocallyAuthenticated && p.Type == UserType.LocalUser).FirstOrDefault();

        //user may have username
        var data = await current.GetPropertyAsync(KnownUserProperties.DisplayName);
        string displayName = (string)data;

        //or may not be available
        if (String.IsNullOrEmpty(displayName))
        {
            displayName = "Anonymous";
        }

        UnityEngine.WSA.Application.InvokeOnAppThread(() => { username.text = "Got " + displayName + " " + current.NonRoamableId;  }, false);
    }
#else
    void login_button_pressed()
    {
        username.text = "Anonymous";
    }
#endif
}

I was able to get a bit farther when I changed var current = … to var current = users.ToList()[0];
However, I keep getting “Got Anonymous” for displayName. I do get a NonRoamableId though.

UPDATE: I figured it out!!! I was doing 3 things wrong. First, I didn’t enable “UserAccountInformation” in UWP Build Settings. Second, I had to manually allow my app access to my username from device (Hololens). Third, my Displayname was actually set as blank for some reason! I figured it out when I logged into Microsoft Forum and it asked me to create a displayname. My final code was this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.Linq;
using TMPro;

#if (!UNITY_EDITOR)
using Windows.System;
using Windows.UI.Core;
#endif

public class UWPManager : MonoBehaviour
{
    public TextMeshPro username;

    void Start()
    {
        FetchDisplayName();
    }

    //function to pull current username
#if (!UNITY_EDITOR)
    public async void FetchDisplayName()
    {
        var res = await User.FindAllAsync(UserType.RemoteUser);
        foreach (var r in res)
        {
            var props = await r.GetPropertiesAsync(new string[] { KnownUserProperties.DisplayName });
            foreach (var p in props)
            {
                username.text += (p.Value + "\n");
            }
        }
    }
#else
    void FetchDisplayName()
    {
        username.text = System.Environment.UserName;
    }
#endif
}