HoloLens (1. gen) i Azure 311 — Microsoft Graph

Uwaga

Samouczki dotyczące akademii Mixed Reality zostały zaprojektowane z myślą o HoloLens (1. generacji) i Mixed Reality immersywnych zestawów słuchawkowych. W związku z tym uważamy, że ważne jest pozostawienie tych samouczków w miejscu dla deweloperów, którzy nadal szukają wskazówek dotyczących opracowywania tych urządzeń. Te samouczki nie zostaną zaktualizowane przy użyciu najnowszych zestawów narzędzi ani interakcji używanych do HoloLens 2. Będą one utrzymywane w celu kontynuowania pracy na obsługiwanych urządzeniach. W przyszłości zostanie opublikowana nowa seria samouczków, które pokażą, jak opracowywać HoloLens 2. To powiadomienie zostanie zaktualizowane za pomocą linku do tych samouczków po ich opublikowaniu.

W tym kursie dowiesz się, jak logować się do konta Microsoft za pomocą usługi Microsoft Graph przy użyciu bezpiecznego uwierzytelniania w aplikacji rzeczywistości mieszanej. Następnie pobierzesz i wyświetlisz zaplanowane spotkania w interfejsie aplikacji.

Screenshot that shows the scheduled meetings in the application interface.

Microsoft Graph to zestaw interfejsów API przeznaczonych do umożliwienia dostępu do wielu usług firmy Microsoft. Firma Microsoft opisuje Graph microsoft jako macierz zasobów połączonych relacjami, co oznacza, że umożliwia aplikacji dostęp do wszystkich rodzajów połączonych danych użytkownika. Aby uzyskać więcej informacji, odwiedź stronę microsoft Graph.

Programowanie będzie obejmować tworzenie aplikacji, w której użytkownik zostanie poinstruowany, aby spojrzeć na, a następnie nacisnąć sferę, co spowoduje monit użytkownika o bezpieczne zalogowanie się do konta Microsoft. Po zalogowaniu się na swoje konto użytkownik będzie mógł wyświetlić listę spotkań zaplanowanych na ten dzień.

Po ukończeniu tego kursu będziesz mieć aplikację rzeczywistości mieszanej HoloLens, która będzie mogła wykonać następujące czynności:

  1. Za pomocą gestu Naciśnij naciśnij obiekt, który wyświetli monit użytkownika o zalogowanie się do konta Microsoft (przejście z aplikacji w celu zalogowania się, a następnie powrót do aplikacji ponownie).
  2. Wyświetl listę spotkań zaplanowanych na dzień.

W aplikacji należy do Ciebie, jak zintegrować wyniki z projektem. Ten kurs został zaprojektowany, aby nauczyć cię, jak zintegrować usługę platformy Azure z projektem aparatu Unity. Twoim zadaniem jest wykorzystanie wiedzy uzyskanych z tego kursu w celu ulepszenia aplikacji rzeczywistości mieszanej.

Obsługa urządzeń

Kurs HoloLens Immersyjne zestawy słuchawkowe
MR i Azure 311: Microsoft Graph ✔️

Wymagania wstępne

Uwaga

Ten samouczek jest przeznaczony dla deweloperów, którzy mają podstawowe doświadczenie w językach Unity i C#. Należy również pamiętać, że wymagania wstępne i pisemne instrukcje zawarte w tym dokumencie reprezentują to, co zostało przetestowane i zweryfikowane w momencie pisania dokumentu (lipiec 2018). Możesz bezpłatnie korzystać z najnowszego oprogramowania, jak pokazano w artykule dotyczącym instalacji narzędzi , choć nie należy zakładać, że informacje w tym kursie będą doskonale zgodne z tym, co znajdziesz w nowszym oprogramowaniu niż wymienione poniżej.

Na potrzeby tego kursu zalecamy następujące oprogramowanie i sprzęt:

Przed rozpoczęciem

  1. Aby uniknąć problemów z kompilowaniem tego projektu, zdecydowanie zaleca się utworzenie projektu wymienionego w tym samouczku w folderze głównym lub niemal głównym (długie ścieżki folderów mogą powodować problemy w czasie kompilacji).
  2. Skonfiguruj i przetestuj HoloLens. Jeśli potrzebujesz pomocy technicznej dotyczącej konfigurowania HoloLens, zapoznaj się z artykułem dotyczącym konfiguracji HoloLens.
  3. Dobrym pomysłem jest wykonanie kalibracji i dostrajania czujników podczas tworzenia nowej aplikacji HoloLens (czasami może to pomóc w wykonywaniu tych zadań dla każdego użytkownika).

Aby uzyskać pomoc dotyczącą kalibracji, skorzystaj z tego linku do artykułu HoloLens Kalibracja.

Aby uzyskać pomoc dotyczącą dostrajania czujników, skorzystaj z tego linku do artykułu HoloLens Dostrajanie czujników.

Rozdział 1 . Tworzenie aplikacji w portalu rejestracji aplikacji

Aby rozpocząć pracę, musisz utworzyć i zarejestrować aplikację w portalu rejestracji aplikacji.

W tym rozdziale znajdziesz również klucz usługi, który umożliwi wykonywanie połączeń z firmą Microsoft Graph w celu uzyskania dostępu do zawartości konta.

  1. Przejdź do portalu rejestracji aplikacji firmy Microsoft i zaloguj się przy użyciu konta Microsoft. Po zalogowaniu nastąpi przekierowanie do portalu rejestracji aplikacji.

  2. W sekcji Moje aplikacje kliknij przycisk Dodaj aplikację.

    Screenshot that shows where to select Add an app.

    Ważne

    Portal rejestracji aplikacji może wyglądać inaczej, w zależności od tego, czy wcześniej pracowałeś z firmą Microsoft Graph. Poniższe zrzuty ekranu przedstawiają te różne wersje.

  3. Dodaj nazwę aplikacji i kliknij przycisk Utwórz.

    Screenshot that shows where to add a name for your application.

  4. Po utworzeniu aplikacji nastąpi przekierowanie do strony głównej aplikacji. Skopiuj identyfikator aplikacji i pamiętaj, aby zanotować tę wartość w bezpiecznym miejscu. Użyjesz jej wkrótce w kodzie.

    Screenshot that shows where to view the Application Id.

  5. W sekcji Platformy upewnij się, że jest wyświetlana aplikacja natywna . Jeśli nie kliknij pozycji Dodaj platformę i wybierz pozycję Aplikacja natywna.

    Screenshot that highlights the Native Application section.

  6. Przewiń w dół na tej samej stronie i w sekcji o nazwie Microsoft Graph Uprawnienia musisz dodać dodatkowe uprawnienia dla aplikacji. Kliknij pozycję Dodaj obok pozycji Uprawnienia delegowane.

    Screenshot that shows where to select Add next to Delegated Permissions.

  7. Ponieważ aplikacja ma uzyskać dostęp do kalendarza użytkownika, zaznacz pole wyboru o nazwie Calendars.Read i kliknij przycisk OK.

    Screenshot that shows the Calendars.Read checkbox.

  8. Przewiń w dół i kliknij przycisk Zapisz .

    Screenshot that shows where to select Save.

  9. Zapisanie zostanie potwierdzone i możesz wylogować się z portalu rejestracji aplikacji.

Rozdział 2 . Konfigurowanie projektu aparatu Unity

Poniżej przedstawiono typową konfigurację do opracowywania za pomocą rzeczywistości mieszanej, a w związku z tym jest to dobry szablon dla innych projektów.

  1. Otwórz aparat Unity i kliknij pozycję Nowy.

    Screenshot that shows the Unity interface.

  2. Musisz podać nazwę projektu aparatu Unity. Wstaw msGraphMR. Upewnij się, że szablon projektu ma ustawioną wartość 3D. Ustaw lokalizację na odpowiednią dla Ciebie (pamiętaj, że bliżej katalogów głównych jest lepiej). Następnie kliknij pozycję Utwórz projekt.

    Screenshot that shows where to select Create Project.

  3. Po otwarciu aparatu Unity warto sprawdzić domyślny edytor skryptów ustawiony na Visual Studio. Przejdź do pozycji EdytujPreferences>, a następnie w nowym oknie przejdź do pozycji Narzędzia zewnętrzne. Zmień edytor skryptów zewnętrznych na Visual Studio 2017. Zamknij okno Preferencje .

    Screenshot that shows where to set the External Script Editor to Visual Studio 2017.

  4. Przejdź do Ustawienia FileBuild> i wybierz pozycję platforma uniwersalna systemu Windows, a następnie kliknij przycisk Przełącz platformę, aby zastosować wybór.

    Screenshot that shows where to select Switch Platform.

  5. Mimo że w programie FileBuild>Ustawienia upewnij się, że:

    1. Urządzenie docelowe ma wartość HoloLens

    2. Typ kompilacji jest ustawiony na D3D

    3. Zestaw SDK jest ustawiony na najnowszą zainstalowaną

    4. Visual Studio Wersja jest ustawiona na zainstalowaną najnowszą

    5. Kompilowanie i uruchamianie jest ustawione na komputer lokalny

    6. Zapisz scenę i dodaj ją do kompilacji.

      1. Zrób to, wybierając pozycję Dodaj otwarte sceny. Zostanie wyświetlone okno zapisywania.

        Screenshot that shows where to select Add Open Scenes.

      2. Utwórz nowy folder dla tego i dowolnej przyszłej sceny. Wybierz przycisk Nowy folder , aby utworzyć nowy folder, nadaj mu nazwę Sceny.

        Screenshot that shows where to name the new folder.

      3. Otwórz nowo utworzony folder Sceny , a następnie w polu Nazwa pliku: tekst wpisz MR_ComputerVisionScene, a następnie kliknij przycisk Zapisz.

        Screenshot that shows where to type the file name.

        Ważne

        Pamiętaj, że musisz zapisać sceny aparatu Unity w folderze Assets , ponieważ muszą być skojarzone z projektem aparatu Unity. Tworzenie folderu scen (i innych podobnych folderów) to typowy sposób tworzenia struktury projektu aparatu Unity.

    7. Pozostałe ustawienia w obszarze Kompilacja Ustawienia powinny być pozostawione jako domyślne na razie.

  6. W oknie Kompilacja Ustawienia kliknij przycisk Odtwarzacz Ustawienia, spowoduje to otwarcie powiązanego panelu w przestrzeni, w której znajduje się inspektor.

    Screenshot that shows the Player Settings dialog box.

  7. W tym panelu należy zweryfikować kilka ustawień:

    1. Na karcie Inne Ustawienia:

      1. Wersja ScriptingRuntime powinna być eksperymentalna (odpowiednik platformy.NET 4.6), co spowoduje konieczność ponownego uruchomienia edytora.

      2. Zaplecze skryptów powinno mieć wartość .NET

      3. Poziom zgodności interfejsu API powinien mieć wartość .NET 4.6

        Screenshot that shows where to check the API compatibility level.

    2. Na karcie Ustawienia publikowania w obszarze Możliwości sprawdź:

      • InternetClient

        Screenshot that shows where to select the InternetClient option.

    3. W dalszej części panelu, w Ustawienia XR (znaleziono poniżej publikowanie Ustawienia), sprawdź Obsługiwane rzeczywistość wirtualna, upewnij się, że zestaw SDK Windows Mixed Reality został dodany.

      Screenshot that shows where to add Windows Mixed Reality SDK.

  8. Po powrocie do Ustawienia kompilacjiprojekty języka C# aparatu Unity nie są już wyszarzone. Zaznacz pole wyboru obok tego.

  9. Zamknij okno Build Settings (Ustawienia kompilacji).

  10. Zapisz scenę i projekt (FILESAVE SCENES / FILESAVE>PROJECT).>

Rozdział 3 . Importowanie bibliotek w środowisku Unity

Ważne

Jeśli chcesz pominąć składnik Unity Set up tego kursu i kontynuować bezpośrednio w kodzie, możesz pobrać ten pakiet Azure-MR-311.unitypackage, zaimportować go do projektu jako pakiet niestandardowy, a następnie kontynuować z rozdziału 5.

Aby korzystać z biblioteki Microsoft Graph w środowisku Unity, należy użyć biblioteki DLL Microsoft.Identity.Client. Można jednak użyć zestawu MICROSOFT Graph SDK, jednak po utworzeniu projektu Unity (co oznacza edycję projektu po kompilacji projektu) będzie wymagać dodania pakietu NuGet. Jest to uważane za prostsze importowanie wymaganych bibliotek DLL bezpośrednio do aparatu Unity.

Uwaga

Obecnie istnieje znany problem w środowisku Unity, który wymaga ponownego skonfigurowania wtyczek po zaimportowaniu. Te kroki (4–7 w tej sekcji) nie będą już wymagane po rozwiązaniu usterki.

Aby zaimportować Graph firmy Microsoft do własnego projektu, pobierz plik MSGraph_LabPlugins.zip. Ten pakiet został utworzony przy użyciu wersji bibliotek, które zostały przetestowane.

Jeśli chcesz dowiedzieć się więcej na temat dodawania niestandardowych bibliotek DLL do projektu aparatu Unity, postępuj zgodnie z tym linkiem.

Aby zaimportować pakiet:

  1. Dodaj pakiet Aparatu Unity do aparatu Unity przy użyciu opcji menuAssetsImport PackageCustom Package (Pakiet AssetsImportuj>>pakietdostosowywczaj pakiet). Wybierz właśnie pobrany pakiet.

  2. W oknie Importuj pakiet aparatu Unity wyskakującym upewnij się, że wybrano wszystkie elementy w obszarze (i włącznie) Wtyczki .

    Screenshot that shows the selected configuration parameters under Plugins.

  3. Kliknij przycisk Importuj , aby dodać elementy do projektu.

  4. Przejdź do folderu MSGraph w obszarze Wtyczki w panelu Project i wybierz wtyczkę o nazwie Microsoft.Identity.Client.

    Screenshot that shows the Microsoft.Identity.Client plugin.

  5. Po wybraniu wtyczki upewnij się, że pole wyboru Dowolna platforma jest niezaznaczone, a następnie upewnij się, że program WSAPlayer jest również niezaznaczone, a następnie kliknij przycisk Zastosuj. Wystarczy potwierdzić, że pliki są poprawnie skonfigurowane.

    Screenshot that shows where to confirm that Any Platform and WSAPlayer aren't checked.

    Uwaga

    Oznaczanie tych wtyczek umożliwia skonfigurowanie ich do użycia tylko w edytorze aparatu Unity. Istnieje inny zestaw bibliotek DLL w folderze WSA, który będzie używany po wyeksportowaniu projektu z aparatu Unity jako aplikacji uniwersalnej Windows.

  6. Następnie należy otworzyć folder WSA w folderze MSGraph . Zostanie wyświetlona kopia tego samego pliku, który został właśnie skonfigurowany. Wybierz plik, a następnie w inspektorze:

    • upewnij się, że opcja Dowolna platforma jest niezaznaczone i że zaznaczono tylkopozycjęWSAPlayer.

    • Upewnij się, że zestaw SDK jest ustawiony na platformę UWP, a zaplecze skryptów jest ustawione na Dot Net

    • Upewnij się, że nie zaznaczonoprocesu.

      Screenshot that shows that Don't Process is selected.

  7. Kliknij pozycję Zastosuj.

Rozdział 4 — Konfiguracja aparatu

W tym rozdziale skonfigurujesz główną kamerę sceny:

  1. W panelu hierarchii wybierz aparat główny.

  2. Po wybraniu opcji będzie można zobaczyć wszystkie składniki głównego aparatu w panelu Inspektor .

    1. Obiekt Aparat musi mieć nazwę Main Camera (zanotuj pisownię!)

    2. Główny tag aparatu musi być ustawiony na MainCamera (zanotuj pisownię!)

    3. Upewnij się, że pozycja przekształcania jest ustawiona na 0, 0, 0

    4. Ustaw przezroczyste flagi na kolor stały

    5. Ustaw kolor tła składnika aparatu na czarny, alfa 0(kod szesnastkowy: #00000000)

      Screenshot that highlights where to set the background color.

  3. Ostateczna struktura obiektów w panelu hierarchii powinna przypominać strukturę pokazaną na poniższej ilustracji:

    Screenshot that shows the final object structure in the Hierarchy Panel.

Rozdział 5 . Tworzenie klasy MeetingUI

Pierwszy skrypt, który należy utworzyć, to MeetingUI, który jest odpowiedzialny za hostowanie i wypełnianie interfejsu użytkownika aplikacji (komunikat powitalny, instrukcje i szczegóły spotkań).

Aby utworzyć tę klasę:

  1. Kliknij prawym przyciskiem myszy folder Assets w panelu Project, a następnie wybierz pozycję UtwórzFolder>. Nadaj nazwę skryptom folderu.

    Screenshot that shows where to find the Assets folder.Screenshot that shows where to create the Scripts folder.

  2. Otwórz folder Scripts (Skrypty), a następnie w tym folderze kliknij prawym przyciskiem myszy pozycję CreateC# Script (Utwórz skrypt w językuC>#). Nadaj skryptowi nazwę MeetingUI.

    Screenshot that shows where to create the MeetingsUI folder.

  3. Kliknij dwukrotnie nowy skrypt MeetingUI, aby otworzyć go za pomocą Visual Studio.

  4. Wstaw następujące przestrzenie nazw:

    using System;
    using UnityEngine;
    
  5. Wewnątrz klasy wstaw następujące zmienne:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static MeetingsUI Instance;
    
        /// <summary>
        /// The 3D text of the scene
        /// </summary>
        private TextMesh _meetingDisplayTextMesh;
    
  6. Następnie zastąp metodę Start() i dodaj metodę Awake(). Będą one wywoływane, gdy klasa inicjuje:

        /// <summary>
        /// Called on initialization
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        void Start ()
        {
            // Creating the text mesh within the scene
            _meetingDisplayTextMesh = CreateMeetingsDisplay();
        }
    
  7. Dodaj metody odpowiedzialne za tworzenie interfejsu użytkownika spotkań i wypełnij je bieżącymi spotkaniami po żądaniu:

        /// <summary>
        /// Set the welcome message for the user
        /// </summary>
        internal void WelcomeUser(string userName)
        {
            if(!string.IsNullOrEmpty(userName))
            {
                _meetingDisplayTextMesh.text = $"Welcome {userName}";
            }
            else 
            {
                _meetingDisplayTextMesh.text = "Welcome";
            }
        }
    
        /// <summary>
        /// Set up the parameters for the UI text
        /// </summary>
        /// <returns>Returns the 3D text in the scene</returns>
        private TextMesh CreateMeetingsDisplay()
        {
            GameObject display = new GameObject();
            display.transform.localScale = new Vector3(0.03f, 0.03f, 0.03f);
            display.transform.position = new Vector3(-3.5f, 2f, 9f);
            TextMesh textMesh = display.AddComponent<TextMesh>();
            textMesh.anchor = TextAnchor.MiddleLeft;
            textMesh.alignment = TextAlignment.Left;
            textMesh.fontSize = 80;
            textMesh.text = "Welcome! \nPlease gaze at the button" +
                "\nand use the Tap Gesture to display your meetings";
    
            return textMesh;
        }
    
        /// <summary>
        /// Adds a new Meeting in the UI by chaining the existing UI text
        /// </summary>
        internal void AddMeeting(string subject, DateTime dateTime, string location)
        {
            string newText = $"\n{_meetingDisplayTextMesh.text}\n\n Meeting,\nSubject: {subject},\nToday at {dateTime},\nLocation: {location}";
    
            _meetingDisplayTextMesh.text = newText;
        }
    
  8. Usuń metodę Update() i zapisz zmiany w Visual Studio przed powrotem do aparatu Unity.

Rozdział 6 . Tworzenie klasy Graph

Następnym skryptem do utworzenia jest skrypt Graph. Ten skrypt jest odpowiedzialny za wykonywanie wywołań w celu uwierzytelnienia użytkownika i pobieranie zaplanowanych spotkań dla bieżącego dnia z kalendarza użytkownika.

Aby utworzyć tę klasę:

  1. Kliknij dwukrotnie folder Scripts (Skrypty ), aby go otworzyć.

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty), kliknij pozycję CreateC# Script (Utwórz skrypt w językuC>#). Nadaj skryptowi nazwę Graph.

  3. Kliknij dwukrotnie skrypt, aby otworzyć go za pomocą Visual Studio.

  4. Wstaw następujące przestrzenie nazw:

    using System.Collections.Generic;
    using UnityEngine;
    using Microsoft.Identity.Client;
    using System;
    using System.Threading.Tasks;
    
    #if !UNITY_EDITOR && UNITY_WSA
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Windows.Storage;
    #endif
    

    Ważne

    Zauważysz, że części kodu w tym skrycie są opakowane wokół dyrektyw prekompilacyjnych. Pozwala to uniknąć problemów z bibliotekami podczas kompilowania rozwiązania Visual Studio.

  5. Usuń metody Start() i Update(), ponieważ nie będą używane.

  6. Poza klasą Graph wstaw następujące obiekty, które są niezbędne do deserializacji obiektu JSON reprezentującego codzienne zaplanowane spotkania:

    /// <summary>
    /// The object hosting the scheduled meetings
    /// </summary>
    [Serializable]
    public class Rootobject
    {
        public List<Value> value;
    }
    
    [Serializable]
    public class Value
    {
        public string subject { get; set; }
        public StartTime start { get; set; }
        public Location location { get; set; }
    }
    
    [Serializable]
    public class StartTime
    {
        public string dateTime;
    
        private DateTime? _startDateTime;
        public DateTime StartDateTime
        {
            get
            {
                if (_startDateTime != null)
                    return _startDateTime.Value;
                DateTime dt;
                DateTime.TryParse(dateTime, out dt);
                _startDateTime = dt;
                return _startDateTime.Value;
            }
        }
    }
    
    [Serializable]
    public class Location
    {
        public string displayName { get; set; }
    }
    
  7. W klasie Graph dodaj następujące zmienne:

        /// <summary>
        /// Insert your Application Id here
        /// </summary>
        private string _appId = "-- Insert your Application Id here --";
    
        /// <summary>
        /// Application scopes, determine Microsoft Graph accessibility level to user account
        /// </summary>
        private IEnumerable<string> _scopes = new List<string>() { "User.Read", "Calendars.Read" };
    
        /// <summary>
        /// Microsoft Graph API, user reference
        /// </summary>
        private PublicClientApplication _client;
    
        /// <summary>
        /// Microsoft Graph API, authentication
        /// </summary>
        private AuthenticationResult _authResult;
    
    

    Uwaga

    Zmień wartość appId na identyfikator aplikacji zanotowany w rozdziale 1, krok 4. Ta wartość powinna być taka sama jak wyświetlana w portalu rejestracji aplikacji na stronie rejestracji aplikacji.

  8. W klasie Graph dodaj metody SignInAsync() i AquireTokenAsync() z monitem użytkownika o wstawienie poświadczeń logowania.

        /// <summary>
        /// Begin the Sign In process using Microsoft Graph Library
        /// </summary>
        internal async void SignInAsync()
        {
    #if !UNITY_EDITOR && UNITY_WSA
            // Set up Grap user settings, determine if needs auth
            ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
            string userId = localSettings.Values["UserId"] as string;
            _client = new PublicClientApplication(_appId);
    
            // Attempt authentication
            _authResult = await AcquireTokenAsync(_client, _scopes, userId);
    
            // If authentication is successful, retrieve the meetings
            if (!string.IsNullOrEmpty(_authResult.AccessToken))
            {
                // Once Auth as been completed, find the meetings for the day
                await ListMeetingsAsync(_authResult.AccessToken);
            }
    #endif
        }
    
        /// <summary>
        /// Attempt to retrieve the Access Token by either retrieving
        /// previously stored credentials or by prompting user to Login
        /// </summary>
        private async Task<AuthenticationResult> AcquireTokenAsync(
            IPublicClientApplication app, IEnumerable<string> scopes, string userId)
        {
            IUser user = !string.IsNullOrEmpty(userId) ? app.GetUser(userId) : null;
            string userName = user != null ? user.Name : "null";
    
            // Once the User name is found, display it as a welcome message
            MeetingsUI.Instance.WelcomeUser(userName);
    
            // Attempt to Log In the user with a pre-stored token. Only happens
            // in case the user Logged In with this app on this device previously
            try
            {
                _authResult = await app.AcquireTokenSilentAsync(scopes, user);
            }
            catch (MsalUiRequiredException)
            {
                // Pre-stored token not found, prompt the user to log-in 
                try
                {
                    _authResult = await app.AcquireTokenAsync(scopes);
                }
                catch (MsalException msalex)
                {
                    Debug.Log($"Error Acquiring Token: {msalex.Message}");
                    return _authResult;
                }
            }
    
            MeetingsUI.Instance.WelcomeUser(_authResult.User.Name);
    
    #if !UNITY_EDITOR && UNITY_WSA
            ApplicationData.Current.LocalSettings.Values["UserId"] = 
            _authResult.User.Identifier;
    #endif
            return _authResult;
        }
    
  9. Dodaj następujące dwie metody:

    1. BuildTodayCalendarEndpoint(), który tworzy identyfikator URI określający dzień i przedział czasu, w którym są pobierane zaplanowane spotkania.

    2. ListMeetingsAsync(), który żąda zaplanowanych spotkań od firmy Microsoft Graph.

        /// <summary>
        /// Build the endpoint to retrieve the meetings for the current day.
        /// </summary>
        /// <returns>Returns the Calendar Endpoint</returns>
        public string BuildTodayCalendarEndpoint()
        {
            DateTime startOfTheDay = DateTime.Today.AddDays(0);
            DateTime endOfTheDay = DateTime.Today.AddDays(1);
            DateTime startOfTheDayUTC = startOfTheDay.ToUniversalTime();
            DateTime endOfTheDayUTC = endOfTheDay.ToUniversalTime();
    
            string todayDate = startOfTheDayUTC.ToString("o");
            string tomorrowDate = endOfTheDayUTC.ToString("o");
            string todayCalendarEndpoint = string.Format(
                "https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={0}&enddatetime={1}",
                todayDate,
                tomorrowDate);
    
            return todayCalendarEndpoint;
        }
    
        /// <summary>
        /// Request all the scheduled meetings for the current day.
        /// </summary>
        private async Task ListMeetingsAsync(string accessToken)
        {
    #if !UNITY_EDITOR && UNITY_WSA
            var http = new HttpClient();
    
            http.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Bearer", accessToken);
            var response = await http.GetAsync(BuildTodayCalendarEndpoint());
    
            var jsonResponse = await response.Content.ReadAsStringAsync();
    
            Rootobject rootObject = new Rootobject();
            try
            {
                // Parse the JSON response.
                rootObject = JsonUtility.FromJson<Rootobject>(jsonResponse);
    
                // Sort the meeting list by starting time.
                rootObject.value.Sort((x, y) => DateTime.Compare(x.start.StartDateTime, y.start.StartDateTime));
    
                // Populate the UI with the meetings.
                for (int i = 0; i < rootObject.value.Count; i++)
                {
                    MeetingsUI.Instance.AddMeeting(rootObject.value[i].subject,
                                                rootObject.value[i].start.StartDateTime.ToLocalTime(),
                                                rootObject.value[i].location.displayName);
                }
            }
            catch (Exception ex)
            {
                Debug.Log($"Error = {ex.Message}");
                return;
            }
    #endif
        }
    
  10. Ukończono skrypt Graph. Zapisz zmiany w Visual Studio przed powrotem do aparatu Unity.

Rozdział 7 . Tworzenie skryptu GazeInput

Teraz utworzysz witrynę GazeInput. Ta klasa obsługuje i śledzi spojrzenie użytkownika, używając Raycast pochodzącego z kamery głównej, projektując do przodu.

Aby utworzyć skrypt:

  1. Kliknij dwukrotnie folder Scripts (Skrypty ), aby go otworzyć.

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty), kliknij pozycję CreateC# Script (Utwórz skrypt w językuC>#). Nadaj skryptowi nazwę GazeInput.

  3. Kliknij dwukrotnie skrypt, aby otworzyć go za pomocą Visual Studio.

  4. Zmień kod przestrzeni nazw, aby był zgodny z poniższym, wraz z dodaniem tagu "[System.Serializable]" nad klasą GazeInput , aby można było go serializować:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. W klasie GazeInput dodaj następujące zmienne:

        [Tooltip("Used to compare whether an object is to be interacted with.")]
        internal string InteractibleTag = "SignInButton";
    
        /// <summary>
        /// Length of the gaze
        /// </summary>
        internal float GazeMaxDistance = 300;
    
        /// <summary>
        /// Object currently gazed
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        internal GameObject oldFocusedObject { get; private set; }
    
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// Cursor object visible in the scene
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        internal bool Hit { get; private set; }
    
        internal Vector3 Position { get; private set; }
    
        internal Vector3 Normal { get; private set; }
    
        private Vector3 _gazeOrigin;
    
        private Vector3 _gazeDirection;
    
  6. Dodaj metodę CreateCursor(), aby utworzyć kursor HoloLens w scenie i wywołać metodę z metody Start():

        /// <summary>
        /// Start method used upon initialisation.
        /// </summary>
        internal virtual void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        internal GameObject CreateCursor()
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            newCursor.SetActive(false);
            // Remove the collider, so it doesn't block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
            newCursor.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f);
            Material mat = new Material(Shader.Find("Diffuse"));
            newCursor.GetComponent<MeshRenderer>().material = mat;
            mat.color = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
  7. Poniższe metody umożliwiają spojrzenie Raycast i śledzenie skoncentrowanych obiektów.

    /// <summary>
    /// Called every frame
    /// </summary>
    internal virtual void Update()
    {
        _gazeOrigin = Camera.main.transform.position;
    
        _gazeDirection = Camera.main.transform.forward;
    
        UpdateRaycast();
    }
    /// <summary>
    /// Reset the old focused object, stop the gaze timer, and send data if it
    /// is greater than one.
    /// </summary>
    private void ResetFocusedObject()
    {
        // Ensure the old focused object is not null.
        if (oldFocusedObject != null)
        {
            if (oldFocusedObject.CompareTag(InteractibleTag))
            {
                // Provide the 'Gaze Exited' event.
                oldFocusedObject.SendMessage("OnGazeExited", SendMessageOptions.DontRequireReceiver);
            }
        }
    }
    
        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            oldFocusedObject = FocusedObject;
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance);
                HitInfo = hitInfo;
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                Position = hitInfo.point;
                Normal = hitInfo.normal;
    
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedObject = hitInfo.collider.gameObject;
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedObject = null;
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedObject = null;
    
                // Provide default position for cursor.
                Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance);
    
                // Provide a default normal.
                Normal = _gazeDirection;
            }
    
            // Lerp the cursor to the given position, which helps to stabilize the gaze.
            Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f);
    
            // Check whether the previous focused object is this same. If so, reset the focused object.
            if (FocusedObject != oldFocusedObject)
            {
                ResetFocusedObject();
                if (FocusedObject != null)
                {
                    if (FocusedObject.CompareTag(InteractibleTag))
                    {
                        // Provide the 'Gaze Entered' event.
                        FocusedObject.SendMessage("OnGazeEntered", 
                            SendMessageOptions.DontRequireReceiver);
                    }
                }
            }
        }
    
  8. Zapisz zmiany w Visual Studio przed powrotem do aparatu Unity.

Rozdział 8 . Tworzenie klasy Interakcje

Teraz musisz utworzyć skrypt Interakcje , który jest odpowiedzialny za:

  • Obsługa interakcji Naciśnięcie i Widok kamery, który umożliwia użytkownikowi interakcję z logowaniem "button" w scenie.

  • Utworzenie obiektu "button" w scenie, z którymi użytkownik będzie wchodzić w interakcję.

Aby utworzyć skrypt:

  1. Kliknij dwukrotnie folder Scripts (Skrypty ), aby go otworzyć.

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty), kliknij pozycję CreateC# Script (Utwórz skrypt w językuC>#). Nadaj skryptowi nazwę Interakcje.

  3. Kliknij dwukrotnie skrypt, aby otworzyć go za pomocą Visual Studio.

  4. Wstaw następujące przestrzenie nazw:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Zmień dziedziczenie klasy Interaction z MonoBehaviour na GazeInput.

    interakcje z klasą publiczną: MonoBehaviour

    public class Interactions : GazeInput
    
  6. Wewnątrz klasy Interaction wstaw następującą zmienną:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Zastąp metodę Start ; zwróć uwagę, że jest to metoda zastąpienia, która wywołuje metodę klasy "base" Gaze. Funkcja Start() zostanie wywołana podczas inicjowania klasy, rejestrowania w celu rozpoznawania danych wejściowych i tworzenia przycisku logowania w scenie:

        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        internal override void Start()
        {
            base.Start();
    
            // Register the application to recognize HoloLens user inputs
            _gestureRecognizer = new GestureRecognizer();
            _gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap);
            _gestureRecognizer.Tapped += GestureRecognizer_Tapped;
            _gestureRecognizer.StartCapturingGestures();
    
            // Add the Graph script to this object
            gameObject.AddComponent<MeetingsUI>();
            CreateSignInButton();
        }
    
  8. Dodaj metodę CreateSignInButton(), która utworzy wystąpienie przycisku logowania w scenie i ustawi jej właściwości:

        /// <summary>
        /// Create the sign in button object in the scene
        /// and sets its properties
        /// </summary>
        void CreateSignInButton()
        {
            GameObject signInButton = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            Material mat = new Material(Shader.Find("Diffuse"));
            signInButton.GetComponent<Renderer>().material = mat;
            mat.color = Color.blue;
    
            signInButton.transform.position = new Vector3(3.5f, 2f, 9f);
            signInButton.tag = "SignInButton";
            signInButton.AddComponent<Graph>();
        }
    
  9. Dodaj metodę GestureRecognizer_Tapped(), która odpowiada na zdarzenie Naciśnij użytkownika.

        /// <summary>
        /// Detects the User Tap Input
        /// </summary>
        private void GestureRecognizer_Tapped(TappedEventArgs obj)
        {
            if(base.FocusedObject != null)
            {
                Debug.Log($"TAP on {base.FocusedObject.name}");
                base.FocusedObject.SendMessage("SignInAsync", SendMessageOptions.RequireReceiver);
            }
        }
    
  10. Usuń metodę Update(), a następnie zapisz zmiany w Visual Studio przed powrotem do aparatu Unity.

Rozdział 9 . Konfigurowanie odwołań do skryptu

W tym rozdziale należy umieścić skrypt Interakcje na głównym aparacie. Ten skrypt będzie następnie obsługiwać umieszczanie innych skryptów, w których muszą być.

  • Z folderu Scripts w panelu Project przeciągnij skrypt Interakcje do obiektu Main Camera, jak pokazano poniżej.

    Screenshot that shows where to drag the Interactions script.

Rozdział 10 — konfigurowanie tagu

Kod obsługujący spojrzenie będzie korzystał z tagu SignInButton w celu zidentyfikowania obiektu, z którym użytkownik będzie wchodzić w interakcję w celu logowania się do usługi Microsoft Graph.

Aby utworzyć tag:

  1. W Edytorze aparatu Unity kliknij kartę Main Camera (Główny aparat) w panelu hierarchii.

  2. W Panelu inspektora kliknij pozycję MainCameraTag, aby otworzyć listę rozwijaną. Kliknij pozycję Dodaj tag...

    Screenshot that highlights the Add Tag... option.

  3. + Kliknij przycisk.

    Screenshot that shows the + button.

  4. Napisz nazwę tagu jako SignInButton i kliknij przycisk Zapisz.

    Screenshot that shows where to add the SignInButton tag name.

Rozdział 11 — Tworzenie projektu aparatu Unity na platformie UWP

Wszystko potrzebne dla sekcji Aparatu Unity tego projektu zostało ukończone, więc nadszedł czas, aby skompilować go z aparatu Unity.

  1. Przejdź do Ustawienia kompilacji (FileBuild>Ustawienia).

    Screenshot that shows the Build Settings dialog box.

  2. Jeśli jeszcze tego nie zrobiono, zaznacz pozycję Projekty języka C# aparatu Unity.

  3. Kliknij pozycję Skompiluj. Środowisko Unity uruchomi okno Eksplorator plików, w którym należy utworzyć, a następnie wybierz folder, w którym ma zostać skompilowanie aplikacji. Utwórz teraz ten folder i nadaj mu nazwę Aplikacja. Następnie z wybraną pozycją Folder aplikacji kliknij pozycję Wybierz folder.

  4. Środowisko Unity rozpocznie kompilowanie projektu w folderze App .

  5. Po zakończeniu kompilowania aparatu Unity (może to zająć trochę czasu), zostanie otwarte okno Eksplorator plików w lokalizacji kompilacji (sprawdź pasek zadań, ponieważ może nie zawsze pojawić się nad oknami, ale powiadomi Cię o dodaniu nowego okna).

Rozdział 12 — Wdrażanie w HoloLens

Aby wdrożyć w HoloLens:

  1. Będziesz potrzebować adresu IP HoloLens (w przypadku zdalnego wdrażania) i upewnić się, że HoloLens jest w trybie dewelopera. Aby to zrobić:

    1. Podczas noszenia HoloLens otwórz Ustawienia.

    2. Przejdź do pozycji Sieć &InternetWi-FiAdvanced>>Opcje

    3. Zanotuj adres IPv4 .

    4. Następnie przejdź z powrotem do Ustawienia, a następnie przejdź do pozycji Aktualizacja & zabezpieczeńFor>Developers

    5. Ustaw tryb dewelopera na włączony.

  2. Przejdź do nowej kompilacji aparatu Unity (folderu App) i otwórz plik rozwiązania za pomocą Visual Studio.

  3. W obszarze Konfiguracja rozwiązania wybierz pozycję Debuguj.

  4. W obszarze Platforma rozwiązania wybierz pozycję x86, Maszyna zdalna. Zostanie wyświetlony monit o wstawienie adresu IP urządzenia zdalnego (HoloLens, w tym przypadku, który został zanotowany).

    Screenshot that shows where to select x86 and Remote Machine.

  5. Przejdź do menu Kompilacja i kliknij pozycję Wdróż rozwiązanie, aby załadować aplikację bezpośrednio do HoloLens.

  6. Aplikacja powinna być teraz wyświetlana na liście zainstalowanych aplikacji na HoloLens, gotowych do uruchomienia.

Aplikacja microsoft Graph HoloLens

Gratulacje, utworzono aplikację rzeczywistości mieszanej, która wykorzystuje Graph firmy Microsoft do odczytywania i wyświetlania danych kalendarza użytkownika.

Screenshot that shows the completed mixed reality app.

Ćwiczenia dodatkowe

Ćwiczenie 1

Używanie Graph Firmy Microsoft do wyświetlania innych informacji o użytkowniku

  • Adres e-mail użytkownika/ numer telefonu/ obraz profilu

Ćwiczenie 1

Zaimplementuj sterowanie głosem, aby nawigować po interfejsie użytkownika Graph firmy Microsoft.