Search Unity

UWP Getting Username Asyncronously using Unity

Discussion in 'Windows' started by ecornwell, Jul 30, 2017.

  1. ecornwell

    ecornwell

    Joined:
    Mar 25, 2017
    Posts:
    2
    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:

    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:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using System;
    6. using System.Linq;
    7.  
    8. #if (!UNITY_EDITOR && UNITY_WSA_10_0)
    9. using Windows.System;
    10. using Windows.UI.Core;
    11. #endif
    12.  
    13. public class login : MonoBehaviour
    14. {
    15.  
    16.     public InputField login_field;
    17.     public Button login_button;
    18.     public Queue<Action> actions;
    19.  
    20.     //initialize queue
    21.     void Start()
    22.     {
    23.         actions = new Queue<Action>();
    24.     }
    25.  
    26.     //dequeue once action received
    27.     void Update()
    28.     {
    29.         while (actions.Count > 0)
    30.         {
    31.             var action = actions.Dequeue();
    32.             if (action != null)
    33.                 action();
    34.         }
    35.     }
    36.  
    37.     //enqueue when button pressed
    38.     public void callFunction()
    39.     {
    40.         actions.Enqueue(() =>
    41.         {
    42. #if (!UNITY_EDITOR && UNITY_WSA_10_0)
    43.                 login_button_pressed();
    44. #endif
    45.         });
    46.     }
    47.  
    48.     //function to pull current username
    49. #if (!UNITY_EDITOR && UNITY_WSA_10_0)
    50.     public async void login_button_pressed()
    51.     {
    52.         //find username
    53.         IReadOnlyList<User> users = await User.FindAllAsync();
    54.  
    55.         var current = users.Where(p => p.AuthenticationStatus == UserAuthenticationStatus.LocallyAuthenticated &&
    56.         p.Type == UserType.LocalUser).FirstOrDefault();
    57.  
    58.         //user may have username
    59.         var data = await current.GetPropertyAsync(KnownUserProperties.DisplayName);
    60.         string displayName = (string)data;
    61.  
    62.         //or may not be available
    63.         if (String.IsNullOrEmpty(displayName))
    64.         {
    65.             displayName = "User";
    66.         }
    67.  
    68.         login_field.text = displayName;
    69.     }
    70. #else
    71.     void login_button_pressed()
    72.     {
    73.         login_field.text = "User";
    74.     }
    75. #endif
    76. }
    77.  
     
  2. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    When await returns, you end up on another thread. You need to use this to get back on the main thread.
     
    ecornwell likes this.
  3. ecornwell

    ecornwell

    Joined:
    Mar 25, 2017
    Posts:
    2
    This worked perfectly! Thanks for your help!

    I replaced the text assignment with:
    Code (CSharp):
    1. UnityEngine.WSA.Application.InvokeOnAppThread (() => {login_field.text = displayName;},false);
    2.     }
     
  4. oliran

    oliran

    Joined:
    Sep 29, 2015
    Posts:
    49
    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?
     
  5. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,680
    ^ Can you post your whole script?
     
  6. oliran

    oliran

    Joined:
    Sep 29, 2015
    Posts:
    49
    Thank you so much for getting back to me so quickly! Here is my code:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using System;
    7. using System.Linq;
    8. using TMPro;
    9.  
    10. #if (!UNITY_EDITOR)
    11. using Windows.System;
    12. using Windows.UI.Core;
    13. #endif
    14.  
    15. public class UWPManager : MonoBehaviour
    16. {
    17.     public TextMeshPro username;
    18.     public Queue<Action> actions;
    19.  
    20.     //initialize queue
    21.     void Start()
    22.     {
    23.         actions = new Queue<Action>();
    24.  
    25.         actions.Enqueue(() =>
    26.         {
    27.             login_button_pressed();
    28.         });
    29.     }
    30.  
    31.     //dequeue once action received
    32.     void Update()
    33.     {
    34.         while (actions.Count > 0)
    35.         {
    36.             var action = actions.Dequeue();
    37.             if (action != null)
    38.                 action();
    39.         }
    40.     }
    41.  
    42.     //enqueue when button pressed
    43.     public void callFunction()
    44.     {
    45.         actions.Enqueue(() =>
    46.         {
    47. #if (!UNITY_EDITOR)
    48.             login_button_pressed();
    49. #endif
    50.         });
    51.     }
    52.  
    53.     //function to pull current username
    54. #if (!UNITY_EDITOR)
    55.     public async void login_button_pressed()
    56.     {
    57.         //find username
    58.         IReadOnlyList<User> users = await User.FindAllAsync();
    59.  
    60.         var current = users.Where(p => p.AuthenticationStatus == UserAuthenticationStatus.LocallyAuthenticated && p.Type == UserType.LocalUser).FirstOrDefault();
    61.  
    62.         //user may have username
    63.         var data = await current.GetPropertyAsync(KnownUserProperties.DisplayName);
    64.         string displayName = (string)data;
    65.  
    66.         //or may not be available
    67.         if (String.IsNullOrEmpty(displayName))
    68.         {
    69.             displayName = "Anonymous";
    70.         }
    71.  
    72.         UnityEngine.WSA.Application.InvokeOnAppThread(() => { username.text = "Got " + displayName + " " + current.NonRoamableId;  }, false);
    73.     }
    74. #else
    75.     void login_button_pressed()
    76.     {
    77.         username.text = "Anonymous";
    78.     }
    79. #endif
    80. }
    81.  
    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:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using System;
    7. using System.Linq;
    8. using TMPro;
    9.  
    10. #if (!UNITY_EDITOR)
    11. using Windows.System;
    12. using Windows.UI.Core;
    13. #endif
    14.  
    15. public class UWPManager : MonoBehaviour
    16. {
    17.     public TextMeshPro username;
    18.  
    19.     void Start()
    20.     {
    21.         FetchDisplayName();
    22.     }
    23.  
    24.     //function to pull current username
    25. #if (!UNITY_EDITOR)
    26.     public async void FetchDisplayName()
    27.     {
    28.         var res = await User.FindAllAsync(UserType.RemoteUser);
    29.         foreach (var r in res)
    30.         {
    31.             var props = await r.GetPropertiesAsync(new string[] { KnownUserProperties.DisplayName });
    32.             foreach (var p in props)
    33.             {
    34.                 username.text += (p.Value + "\n");
    35.             }
    36.         }
    37.     }
    38. #else
    39.     void FetchDisplayName()
    40.     {
    41.         username.text = System.Environment.UserName;
    42.     }
    43. #endif
    44. }
    45.  
     
    Last edited: Mar 7, 2018