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

Uwaga

Samouczki Mixed Reality Academy zostały zaprojektowane z myślą o HoloLens (1. generacji) i Mixed Reality immersyjne zestawy nagłowne. 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 tworzenia aplikacji dla tych urządzeń. Te samouczki nie zostaną zaktualizowane o najnowsze zestawy narzędzi ani interakcje używane na 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 zademonstrują sposób tworzenia aplikacji dla HoloLens 2. Ta informacja zostanie zaktualizowana przy użyciu linku do tych samouczków, gdy zostaną opublikowane.

W ramach tego kursu dowiesz się, jak używać usługi Microsoft Graph do logowania się do aplikacji konto Microsoft przy użyciu bezpiecznego uwierzytelniania w aplikacji rzeczywistości mieszanej. Następnie pobierzemy i wyświetlimy zaplanowane spotkania w interfejsie aplikacji.

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

Opracowywanie będzie obejmować tworzenie aplikacji, w której użytkownik zostanie poinstruowany, aby spojrzył na, a następnie naciśnij sferę, która wyświetli monit o bezpieczne zalogowanie się do aplikacji konto Microsoft. Po zalogowaniu się na koncie 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, co spowoduje 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 ten dzień.

W aplikacji to Ty musisz dowiedzieć się, jak zintegrować wyniki z projektem. Ten kurs ma na celu nauczenie Cię, jak zintegrować usługę platformy Azure z projektem aparatu Unity. Twoim zadaniem jest wykorzystanie wiedzy zdobytej podczas tego kursu w celu ulepszania 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 pracy z aparatu Unity i języka C#. Należy również pamiętać, że wymagania wstępne i pisemne instrukcje w tym dokumencie reprezentują to, co zostało przetestowane i zweryfikowane w momencie pisania (lipiec 2018 r.). Możesz korzystać z najnowszego oprogramowania, jak podano w artykule instalowanie narzędzi, chociaż nie należy zakładać, że informacje zawarte w tym kursie będą idealnie zgodne z informacjami dostępnymi w nowszej wersji oprogramowania niż wymienione poniżej.

Na ten kurs zalecamy użycie następującego sprzętu i oprogramowania:

Przed rozpoczęciem

  1. Aby uniknąć problemów podczas kompilowania tego projektu, zdecydowanie zaleca się utworzenie projektu wspomnianego 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 podczas konfigurowania HoloLens, przejdź do artykułu HoloLens konfiguracji.
  3. Dobrym pomysłem jest przeprowadzenie dostrajania i dostosowywania czujnika podczas tworzenia nowej aplikacji HoloLens (czasami może to ułatwić wykonanie tych zadań dla każdego użytkownika).

Aby uzyskać pomoc na temat śledzenia, skorzystaj z tego linku do HoloLens Tematu.

Aby uzyskać pomoc na temat dostrajania czujników, skorzystaj z tego linku do artykułu HoloLens Sensor Tuning (Dostrajanie czujnika).

Rozdział 1 — Tworzenie aplikacji w portalu rejestracji aplikacji

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

W tym rozdziale znajdziesz również klucz usługi, który umożliwi Ci połączenia z usługą Microsoft Graph w celu uzyskania dostępu do zawartości Twojego 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ę.

    Ważne

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

  3. Dodaj nazwę aplikacji, a następnie kliknij pozycję Utwórz.

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

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

  6. Przewiń w dół na tej samej stronie i w sekcji o nazwie Microsoft Graph Permissions (Uprawnienia usługi Microsoft Graph), musisz dodać dodatkowe uprawnienia do aplikacji. Kliknij pozycję Dodaj obok ustawienia Uprawnienia delegowane.

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

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

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

Rozdział 2 — Konfigurowanie projektu aparatu Unity

Poniżej przedstawiono typową infrastrukturę do tworzenia aplikacji z rzeczywistością mieszaną i w związku z tym jest to dobry szablon dla innych projektów.

  1. Otwórz platformę Unity i kliknij pozycję New (Nowy).

  2. Musisz podać nazwę projektu aparatu Unity. Wstaw polecenie MSGraphMR. Upewnij się, że szablon projektu został ustawiony na 3D. Ustaw lokalizację na wartość w odpowiednim miejscu (pamiętaj, że lepiej jest bliżej katalogów głównych). Następnie kliknij pozycję Create project (Utwórz projekt).

  3. Po otwarciu aparatu Unity warto sprawdzić, czy domyślny Edytor skryptów jest ustawiony na wartość Visual Studio. Przejdź do menu Edytuj > preferencje, a następnie w nowym oknie przejdź do narzędzia zewnętrzne. Zmień zewnętrzny edytor skryptów na Visual Studio 2017. Zamknij okno Preferencje.

  4. Przejdź do opcji Kompilacja Ustawienia i wybierz pozycję > Windows platformę uniwersalną, a następnie kliknij przycisk Switch Platform (Przełącz platformę), aby zastosować wybór.

  5. Podczas pracy z programem File > Build Ustawienia upewnij się, że:

    1. Ustawienie Urządzenie docelowe ma wartość HoloLens

    2. Typ kompilacji jest ustawiony na D3D

    3. Zestaw SDK jest ustawiony na najnowszą zainstalowaną wersję

    4. Visual Studio jest ustawiona na najnowszą zainstalowaną wersję

    5. Kompilowanie i uruchamianie jest ustawione na wartość Komputer lokalny

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

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

      2. Utwórz nowy folder dla tej i każdej przyszłej sceny. Wybierz przycisk Nowy folder, aby utworzyć nowy folder, nadaj temu folderowi nazwę Scenes ( Sceny).

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

        Ważne

        Należy pamiętać, że należy zapisać sceny aparatu Unity w folderze Assets, ponieważ muszą one być skojarzone z projektem aparatu Unity. Tworzenie folderu scenes (i innych podobnych folderów) jest typowym sposobem tworzenia struktury projektu aparatu Unity.

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

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

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

    1. Na karcie Inne Ustawienia danych:

      1. Wersja środowiska uruchomieniowego skryptów powinna być eksperymentalna (odpowiednik dla programu .NET 4.6), co wyzwoli konieczność ponownego uruchomienia edytora.

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

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

    2. Na karcie Publishing Ustawienia (Funkcje) sprawdź:

      • InternetClient

    3. Poniżej panelu, w artykule XR Ustawienia (Publikowanie Ustawienia) zaznacz pole Virtual Reality Supported(Rzeczywistość wirtualna obsługiwana) i upewnij się, że Windows Mixed Reality SDK.

  8. Po powrocie do Ustawienia kompilacji projekty C# aparatu Unity nie są już wyszzarowane; zaznacz pole wyboru obok tej.

  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 Konfigurowanie aparatu Unity w tym kursie i przejść bezpośrednio do kodu, możesz pobrać ten plik Azure-MR-311.unitypackage,zaimportować go do projektu jako pakiet niestandardowy,a następnie kontynuować z rozdziału 5.

Aby używać biblioteki Microsoft Graph w a aparatu Unity, należy użyć biblioteki DLL Microsoft.Identity.Client. Istnieje możliwość użycia zestawu Microsoft Graph SDK, jednak będzie on wymagał dodatku pakietu NuGet po skompilowaniu projektu aparatu Unity (co oznacza edytowanie projektu po kompilacji). Importowanie wymaganych bibliotek DLL bezpośrednio do aparatu Unity jest uznawane za prostsze.

Uwaga

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

Aby zaimportować Graph Microsoft do własnego projektu, pobierz MSGraph_LabPlugins.zip plik . Ten pakiet został utworzony z wersjami przetestowanych bibliotek.

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

Aby zaimportować pakiet:

  1. Dodaj pakiet aparatu Unity do aparatu Unity przy użyciu opcji menu Pakiet niestandardowy importu > > zasobów. Wybierz właśnie pobrany pakiet.

  2. W wyskakującym oknie Import Unity Package (Importowanie pakietu aparatu Unity) upewnij się, że wybrano wszystko w obszarze (i w tym) Plugins (Wtyczki).

  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.

  5. Po wybraniu wtyczki upewnij się, że pole Any Platform (Dowolna platforma) nie jest zaznaczone, a następnie upewnij się, że pole WSAPlayer nie jest zaznaczone, a następnie kliknij przycisk Apply (Zastosuj). Ma to na celu jedynie potwierdzenie, że pliki są poprawnie skonfigurowane.

    Uwaga

    Oznaczanie tych wtyczek konfiguruje je tak, aby były używane tylko w edytorze aparatu Unity. W folderze WSA istnieje inny zestaw bibliotek DLL, które będą używane po wyeksportowaniu projektu z aparatu Unity jako universal Windows Application.

  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 pole Dowolna platforma jest niezaznaczone i że zaznaczono tylko opcję WSAPlayer.

    • Upewnij się, że dla zestawu SDK ustawiono wartość UWP, a dla zaplecza skryptów ustawiono wartość Dot Net

    • Upewnij się, że pole Nie przetwarzaj jest zaznaczone.

  7. Kliknij pozycję Zastosuj.

Rozdział 4 — Konfiguracja aparatu

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

  1. W Panelu hierarchii wybierz pozycję Main Camera (Kamera główna).

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

    1. Obiekt Camera musi mieć nazwę Main Camera (Kamera główna) (zwróć uwagę na pisownię!)

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

    3. Upewnij się, że pozycja Przekształcenia jest ustawiona na wartość 0, 0, 0

    4. Ustaw flagi Clear na solid color (Pełny kolor)

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

  3. Końcowa struktura obiektu w Panelu hierarchii powinna przypominać strukturę pokazaną na poniższej ilustracji:

Rozdział 5 — Tworzenie klas MeetingsUI

Pierwszy skrypt, który należy utworzyć, to MeetingsUI, 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órz > folder. Nadaj folderowi nazwę Skrypty.

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

  3. Kliknij dwukrotnie nowy skrypt MeetingsUI, 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 na żądanie wypełnij go bieżącymi spotkaniami:

        /// <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 Graph danych

Następnym skryptem do utworzenia jest Graph skryptu. Ten skrypt jest odpowiedzialny za wykonywanie wywołań w celu uwierzytelnienia użytkownika i pobrania 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) i kliknij polecenie Create > C# Script (Utwórz skrypt języka C#). 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 skrypcie są opakowane wokół dyrektyw kompilacji wstępnej,aby uniknąć problemów z bibliotekami podczas kompilowania Visual Studio kompilacji.

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

  6. Poza Graph wstaw następujące obiekty, które są niezbędne do deserializować obiekt JSON reprezentujący zaplanowane codzienne 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. Wewnątrz 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 zanotowywiony 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(), 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 adres URI określający dzień i zakres 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. Skrypt skryptu Graph został ukończony. Zapisz zmiany w programie Visual Studio przed powrotem do aparatu Unity.

Rozdział 7 . Tworzenie skryptu GazeInput

Teraz utworzysz projekt GazeInput. Ta klasa obsługuje i śledzi spojrzenie użytkownika przy użyciu rzutu z głównej kamery, który jest rzutem do przodu.

Aby utworzyć skrypt:

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

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

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

  4. Zmień kod przestrzeni nazw tak, aby był taki, jak podano poniżej, wraz z dodawaniem 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. 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ć HoloLens kursora w scenie, i wywołaj 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 skupionych 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 odpowiada za:

  • Obsługa interakcji naciśnięcia i spojrzenia aparatu, które umożliwia użytkownikowi interakcję z logowaniem "przycisku" w scenie.

  • Utworzenie obiektu "button" dziennika w scenie, z pomocą której użytkownik może wchodzić w interakcje.

Aby utworzyć skrypt:

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

  2. Kliknij prawym przyciskiem myszy wewnątrz folderu Scripts (Skrypty) i kliknij polecenie Create > C# Script (Utwórz skrypt języka C#). 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 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 przesłonięcia, która wywołuje metodę klasy "base" Gaze. Metody Start() zostaną wywołane podczas inicjowania klasy, rejestracji 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 spowoduje utworzenie wystąpienia przycisku logowania w scenie i ustawienie 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 będzie odpowiadać na zdarzenie użytkownika Naciśnij.

        /// <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 w aparacie głównym. Ten skrypt będzie obsługiwać umieszczanie innych skryptów w miejscu, w którym muszą być.

  • Z folderu Skrypty na panelu Project przeciągnij skrypt Interakcje do obiektu Main Camera (Kamera główna), jak po ilustracji poniżej.

Rozdział 10 — Konfigurowanie tagu

Kod obsługi spojrzenia będzie używać tagu SignInButton do identyfikowania obiektu, z którym użytkownik będzie wchodzić w interakcję w celu zalogowania się do usługi Microsoft Graph.

Aby utworzyć tag:

  1. W edytorze aparatu Unity kliknij pozycję Main Camera (Główny aparat) w panelu hierarchy (Hierarchia).

  2. W panelu Inspector (Inspektor) kliknij tag MainCamera, aby otworzyć listę rozwijaną. Kliknij pozycję Dodaj tag...

  3. Kliknij + przycisk .

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

Rozdział 11 — Kompilowanie projektu aparatu Unity na platformie uniwersalnej systemu Windows

Wszystkie potrzebne informacje w sekcji dotyczącej aparatu Unity w tym projekcie zostały ukończone, więc czas na skompilowanie go z aparatu Unity.

  1. Przejdź do Ustawienia kompilacji (Plik > Kompilacja Ustawienia).

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

  3. Kliknij pozycję Build (Kompilacja). Unity uruchomi okno Eksplorator plików, w którym musisz utworzyć, a następnie wybrać folder, w którym chcesz skompilować aplikację. Utwórz teraz ten folder i nadaj aplikacji nazwę. Następnie po wybraniu folderu Aplikacja kliknij pozycję Wybierz folder.

  4. Unity rozpocznie budowania projektu w folderze App.

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

Rozdział 12 — Wdrażanie w HoloLens

Aby wdrożyć na HoloLens:

  1. Będziesz potrzebować adresu IP swojej usługi HoloLens (w przypadku wdrażania zdalnego) i upewnić się, że HoloLens jest w trybie dewelopera. W tym celu:

    1. Podczas noszenia własnego HoloLens otwórz Ustawienia.

    2. Przejdź do opcji Sieć & Zaawansowane opcje sieci > Wi-Fi >

    3. Zanotuj adres IPv4.

    4. Następnie przejdź z powrotem do Ustawienia, a następnie do & Update & Security for > Developers

    5. Ustaw tryb dewelopera na.

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

  3. W konfiguracji rozwiązania wybierz pozycję Debuguj.

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

  5. Przejdź do menu Kompilacja i kliknij pozycję Deploy Solution (Wd wdrażaj rozwiązanie), aby załadować aplikację do aplikacji HoloLens.

  6. Twoja aplikacja powinna teraz zostać wyświetlona na liście zainstalowanych aplikacji HoloLens gotowych do uruchomień!

Twoja aplikacja Graph HoloLens Microsoft

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

Ćwiczenia dodatkowe

Ćwiczenie 1

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

  • Adres e-mail/numer telefonu/zdjęcie profilowe użytkownika

Ćwiczenie 1

Zaim implementuj sterowanie głosowe, aby nawigować po interfejsie Graph Microsoft.