Udostępnij za pośrednictwem


Urządzenia HoloLens (1. generacji) i Azure 311 — Microsoft Graph

Uwaga

Samouczki akademii rzeczywistości mieszanej zostały zaprojektowane z myślą o urządzeniach HoloLens (1. generacji) i zestawach słuchawkowych immersyjnych rzeczywistości mieszanej. W związku z tym uważamy, że ważne jest pozostawienie tych samouczków na 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 dla urządzenia 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ć urządzenia HoloLens 2. To powiadomienie zostanie zaktualizowane za pomocą linku do tych samouczków po ich opublikowaniu.

W tym kursie dowiesz się, jak zalogować się do konta Microsoft przy użyciu programu Microsoft Graph przy użyciu bezpiecznego uwierzytelniania w aplikacji rzeczywistości mieszanej. Następnie pobierzesz i wyświetlisz zaplanowane spotkania w interfejsie aplikacji.

Zrzut ekranu przedstawiający zaplanowane spotkania w interfejsie aplikacji.

Microsoft Graph to zestaw interfejsów API przeznaczonych do umożliwienia dostępu do wielu usług firmy Microsoft. Firma Microsoft opisuje program Microsoft Graph jako macierz zasobów połączonych przez relacje, co oznacza, że umożliwia aplikacji dostęp do wszystkich rodzajów połączonych danych użytkownika. Aby uzyskać więcej informacji, odwiedź stronę programu 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 wyświetlenie monitu użytkownika o bezpieczne zalogowanie się do konta Microsoft. Po zalogowaniu się na swoje konto użytkownik będzie mógł zobaczyć listę spotkań zaplanowanych na ten dzień.

Po ukończeniu tego kursu będziesz mieć aplikację HoloLens rzeczywistości mieszanej, 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).
  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 nagłowne
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 r.). Możesz bezpłatnie korzystać z najnowszego oprogramowania, jak wymieniono w artykule dotyczącym instalacji narzędzi , choć nie należy zakładać, że informacje zawarte w tym kursie doskonale pasują do tego, co znajdziesz w nowszym oprogramowaniu niż to, co zostało wymienione poniżej.

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

Przed rozpoczęciem

  1. Aby uniknąć problemów podczas tworzenia 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 urządzenie HoloLens. Jeśli potrzebujesz pomocy technicznej dotyczącej konfigurowania urządzenia HoloLens, zapoznaj się z artykułem dotyczącym konfiguracji urządzenia HoloLens.
  3. Dobrym pomysłem jest przeprowadzenie 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 Kalibracja urządzenia HoloLens.

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

Rozdział 1 . Tworzenie aplikacji w portalu rejestracji aplikacji

Na początek należy utworzyć i zarejestrować aplikację w portalu rejestracji aplikacji.

W tym rozdziale znajdziesz również klucz usługi, który umożliwi wykonywanie wywołań do programu 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ę.

    Zrzut ekranu pokazujący, gdzie wybrać pozycję Dodaj aplikację.

    Ważne

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

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

    Zrzut ekranu pokazujący, gdzie dodać nazwę aplikacji.

  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.

    Zrzut ekranu przedstawiający miejsce wyświetlania identyfikatora aplikacji.

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

    Zrzut ekranu przedstawiający sekcję Aplikacja natywna.

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

    Zrzut ekranu pokazujący, gdzie wybrać pozycję Dodaj obok pozycji Uprawnienia delegowane.

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

    Zrzut ekranu przedstawiający pole wyboru Calendars.Read.

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

    Zrzut ekranu pokazujący, gdzie wybrać pozycję Zapisz.

  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.

    Zrzut ekranu przedstawiający interfejs aparatu Unity.

  2. Musisz podać nazwę projektu aparatu Unity. Wstaw narzędzie MSGraphMR. Upewnij się, że szablon projektu jest ustawiony na 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.

    Zrzut ekranu pokazujący, gdzie wybrać pozycję Utwórz projekt.

  3. Po otwarciu aparatu Unity warto sprawdzić, czy domyślny edytor skryptów jest ustawiony na program Visual Studio. Przejdź do pozycji Edytuj>preferencje, 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.

    Zrzut ekranu pokazujący, gdzie ustawić edytor skryptów zewnętrznych na program Visual Studio 2017.

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

    Zrzut ekranu pokazujący, gdzie wybrać pozycję Przełącz platformę.

  5. Nadal w obszarze Ustawienia kompilacji pliku>upewnij się, że:

    1. Urządzenie docelowe jest ustawione na urządzenie HoloLens

    2. Typ kompilacji jest ustawiony na D3D

    3. Zestaw SDK jest ustawiony na najnowszą zainstalowaną

    4. Dla wersji programu Visual Studio jest ustawiona wartość Najnowsza zainstalowana

    5. Kompilowanie i uruchamianie jest ustawione na komputer lokalny

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

      1. W tym celu wybierz pozycję Dodaj otwarte sceny. Zostanie wyświetlone okno zapisywania.

        Zrzut ekranu pokazujący, gdzie wybrać pozycję Dodaj otwarte sceny.

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

        Zrzut ekranu pokazujący, gdzie nazwać nowy 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.

        Zrzut ekranu przedstawiający miejsce wpisywania nazwy pliku.

        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 Ustawienia kompilacji powinny być pozostawione jako domyślne na razie.

  6. W oknie Ustawienia kompilacji kliknij przycisk Ustawienia odtwarzacza, spowoduje to otwarcie powiązanego panelu w obszarze, w którym znajduje się inspektor.

    Zrzut ekranu przedstawiający okno dialogowe Ustawienia odtwarzacza.

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

    1. Na karcie Inne ustawienia:

      1. Wersja środowiska uruchomieniowego skryptów 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

        Zrzut ekranu pokazujący, gdzie sprawdzić poziom zgodności interfejsu API.

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

      • InternetClient

        Zrzut ekranu pokazujący, gdzie wybrać opcję InternetClient.

    3. W dalszej części panelu w obszarze Ustawienia XR (znajdujące się poniżej ustawienia publikowania) zaznacz pole Virtual Reality Supported (Obsługiwana rzeczywistość wirtualna), upewnij się, że dodano zestaw WINDOWS Mixed Reality SDK.

      Zrzut ekranu przedstawiający miejsce dodawania zestawu Windows Mixed Reality SDK.

  8. Po powrocie do ustawień kompilacji projekty 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 (PLIK>ZAPISZ SCENY / PLIK>ZAPISZ PROJEKT).

Rozdział 3 . Importowanie bibliotek w a unity

Ważne

Jeśli chcesz pominąć składnik Konfiguracji aparatu Unity 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 programu Microsoft Graph w środowisku Unity, należy użyć biblioteki DLL Microsoft.Identity.Client . Można jednak użyć zestawu SDK programu Microsoft Graph, jednak po utworzeniu projektu Aparatu Unity będzie wymagane dodanie pakietu NuGet (co oznacza edytowanie projektu po kompilacji). Jest on uważany za prostszy do importowania wymaganych bibliotek DLL bezpośrednio do aparatu Unity.

Uwaga

Obecnie w środowisku Unity występuje znany problem, 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ć program Microsoft Graph do własnego projektu, pobierz plik MSGraph_LabPlugins.zip. Ten pakiet został utworzony z wersjami bibliotek, które zostały przetestowane.

Jeśli chcesz dowiedzieć się więcej na temat dodawania niestandardowych bibliotek DLL do projektu aparatu Unity, użyj tego linku.

Aby zaimportować pakiet:

  1. Dodaj pakiet aparatu Unity do aparatu Unity przy użyciu opcji menu Importuj pakiet>niestandardowy pakietu Assets.> Wybierz właśnie pobrany pakiet.

  2. W wyświetlonym oknie Importuj pakiet aparatu Unity upewnij się, że wybrano wszystkie elementy w obszarze (i w tym) Wtyczki .

    Zrzut ekranu przedstawiający wybrane parametry konfiguracji w obszarze Wtyczki.

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

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

    Zrzut ekranu przedstawiający wtyczkę Microsoft.Identity.Client.

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

    Zrzut ekranu pokazujący, gdzie potwierdzić, że nie zaznaczono opcji Dowolna platforma i WSAPlayer.

    Uwaga

    Oznaczanie tych wtyczek konfiguruje je tak, aby były używane 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 systemu Windows.

  6. Następnie należy otworzyć folder WSA w folderze MSGraph . Zobaczysz kopię 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 tylko WSAPlayer.

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

    • Upewnij się, że nie zaznaczono wyboru Nie przetwarzaj.

      Zrzut ekranu przedstawiający wybranie opcji Nie przetwarzaj.

  7. Kliknij Zastosuj.

Rozdział 4 — Konfiguracja aparatu

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

  1. W panelu hierarchii wybierz kamerę główną.

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

    1. Obiekt Aparatu 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 , Alfa 0 (kod szesnastkowy: #00000000)

      Zrzut ekranu pokazujący, gdzie ustawić kolor tła.

  3. Ostateczna struktura obiektów w panelu hierarchii powinna być podobna do tej przedstawionej na poniższej ilustracji:

    Zrzut ekranu przedstawiający ostateczną strukturę obiektu w panelu hierarchii.

Rozdział 5 . Tworzenie klasy MeetingsUI

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 projektu, a następnie wybierz polecenie Utwórz>folder. Nadaj folderowi nazwę Scripts( Skrypty).

    Zrzut ekranu przedstawiający miejsce znalezienia folderu Assets.Zrzut ekranu pokazujący, gdzie utworzyć folder Scripts.

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

    Zrzut ekranu pokazujący, gdzie utworzyć folder MeetingsUI.

  3. Kliknij dwukrotnie nowy skrypt MeetingsUI , aby otworzyć go za pomocą programu 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 utworzenie interfejsu użytkownika spotkań i wypełnij je bieżącymi spotkaniami po zażą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 programie Visual Studio przed powrotem do aparatu Unity.

Rozdział 6 . Tworzenie klasy Graph

Następnym skryptem do utworzenia jest skrypt programu 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 Skrypty, aby go otworzyć.

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty), kliknij polecenie Create C# Script (Utwórz>skrypt języka C#). Nadaj skryptowi nazwę Graph.

  3. Kliknij dwukrotnie skrypt, aby otworzyć go za pomocą programu 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 prekompilowania. Pozwala to uniknąć problemów z bibliotekami podczas kompilowania rozwiązania programu 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 ta wyświetlana w portalu rejestracji aplikacji na stronie rejestracji aplikacji.

  8. W klasie Graph dodaj metody SignInAsync() i AquireTokenAsync(), które będą monitować 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 pobierane są zaplanowane spotkania.

    2. ListMeetingsAsync(), który żąda zaplanowanych spotkań z programu 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. Skrypt programu Graph został ukończony. Zapisz zmiany w programie Visual Studio przed powrotem do aparatu Unity.

Rozdział 7 . Tworzenie skryptu GazeInput

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

Aby utworzyć skrypt:

  1. Kliknij dwukrotnie folder Skrypty, aby go otworzyć.

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty), kliknij polecenie Create C# Script (Utwórz>skrypt języka C#). Nadaj skryptowi nazwę GazeInput.

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

  4. Zmień kod przestrzeni nazw, aby był zgodny z poniższym, wraz z dodaniem tagu "[System.Serializable]" powyżej klasy 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. Wewnątrz klasy 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 programie 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 Spojrzenie kamery, która umożliwia użytkownikowi interakcję z dziennikiem "button" w scenie.

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

Aby utworzyć skrypt:

  1. Kliknij dwukrotnie folder Skrypty, aby go otworzyć.

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty), kliknij polecenie Create C# Script (Utwórz>skrypt języka C#). Nadaj skryptowi nazwę Interakcje.

  3. Kliknij dwukrotnie skrypt, aby otworzyć go za pomocą programu 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 klasy publicznej: 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() będzie wywoływana, gdy klasa inicjuje, rejestrując się w celu rozpoznawania danych wejściowych i tworząc przycisk 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 jego 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 programie Visual Studio przed powrotem do aparatu Unity.

Rozdział 9 — Konfigurowanie odwołań do skryptów

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

  • W folderze Scripts (Skrypty) w panelu projektu przeciągnij skrypt Interactions (Interakcje skryptu) do obiektu Main Camera (Aparat główny), jak pokazano poniżej.

    Zrzut ekranu przedstawiający miejsce przeciągania skryptu Interakcje.

Rozdział 10 — konfigurowanie tagu

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

Aby utworzyć tag:

  1. W Edytorze aparatu Unity kliknij aparat główny w panelu hierarchii.

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

    Zrzut ekranu z wyróżnionym tagiem Dodaj... opcja.

  3. + Kliknij przycisk .

    Zrzut ekranu przedstawiający przycisk +

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

    Zrzut ekranu przedstawiający miejsce dodawania nazwy tagu SignInButton.

Rozdział 11 — Kompilowanie projektu aparatu Unity w usłudze UWP

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

  1. Przejdź do obszaru Ustawienia kompilacji (ustawienia kompilacji pliku>).

    Zrzut ekranu przedstawiający okno dialogowe Ustawienia kompilacji.

  2. Jeśli jeszcze tego nie zrobiono, zaznacz pole Unity C# Projects (Projekty języka C# aparatu Unity).

  3. Kliknij pozycję Kompiluj. Aparat Unity uruchomi okno Eksplorator plików, w którym należy utworzyć, a następnie wybierz folder do skompilowania aplikacji. Utwórz teraz ten folder i nadaj mu nazwę Aplikacja. Następnie po wybraniu folderu Aplikacja kliknij pozycję Wybierz folder.

  4. Aparat Unity rozpocznie kompilowanie projektu w folderze App .

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

Rozdział 12 — Wdrażanie na urządzeniu HoloLens

Aby wdrożyć na urządzeniu HoloLens:

  1. Będziesz potrzebować adresu IP urządzenia HoloLens (na potrzeby zdalnego wdrażania) i upewnij się, że urządzenie HoloLens jest w trybie dewelopera. W tym celu:

    1. Podczas noszenia urządzenia HoloLens otwórz ustawienia.

    2. Przejdź do pozycji Sieć i Internetowe>opcje zaawansowane sieci Wi-Fi>

    3. Zanotuj adres IPv4 .

    4. Następnie przejdź z powrotem do pozycji Ustawienia, a następnie przejdź do pozycji Aktualizuj i zabezpieczenia>dla deweloperów

    5. Ustaw tryb dewelopera wł.

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

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

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

    Zrzut ekranu pokazujący, gdzie wybrać x86 i maszynę zdalną.

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

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

Aplikacja Microsoft Graph HoloLens

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

Zrzut ekranu przedstawiający ukończoną aplikację rzeczywistości mieszanej.

Ćwiczenia dodatkowe

Ćwiczenie 1

Użyj programu Microsoft Graph, aby wyświetlić inne informacje o użytkowniku

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

Ćwiczenie 1

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