HoloLens (1e generatie) en Azure 311 - Microsoft Graph

Notitie

De Mixed Reality Academy-zelfstudies zijn ontworpen met HoloLens (1e generatie) en Mixed Reality Immersive Headsets in gedachten. Daarom vinden we het belangrijk om deze zelfstudies te laten staan voor ontwikkelaars die nog steeds op zoek zijn naar richtlijnen bij het ontwikkelen van deze apparaten. Deze zelfstudies worden niet bijgewerkt met de meest recente toolsets of interacties die worden gebruikt voor HoloLens 2. Ze worden onderhouden om te blijven werken op de ondersteunde apparaten. Er komt een nieuwe reeks zelfstudies die in de toekomst zullen worden gepubliceerd, waarin wordt gedemonstreerd hoe u kunt ontwikkelen voor HoloLens 2. Deze kennisgeving wordt bijgewerkt met een koppeling naar deze zelfstudies wanneer ze worden gepost.

In deze cursus leert u hoe u Microsoft Graph gebruikt om u aan te melden bij uw Microsoft-account met behulp van beveiligde verificatie binnen een mixed reality-toepassing. Vervolgens haalt u uw geplande vergaderingen op en geeft u deze weer in de toepassingsinterface.

Schermopname van de geplande vergaderingen in de toepassingsinterface.

Microsoft Graph is een set API's die is ontworpen om toegang tot veel van de services van Microsoft mogelijk te maken. Microsoft beschrijft Microsoft Graph als een matrix van resources die zijn verbonden door relaties, wat betekent dat een toepassing toegang heeft tot allerlei verbonden gebruikersgegevens. Ga naar de Microsoft Graph-pagina voor meer informatie.

Ontwikkeling omvat het maken van een app waarbij de gebruiker wordt geïnstrueerd om naar een bol te staren en vervolgens op een bol te tikken, waardoor de gebruiker wordt gevraagd zich veilig aan te melden bij een Microsoft-account. Zodra de gebruiker is aangemeld bij het account, kan een lijst met vergaderingen worden weergegeven die voor die dag zijn gepland.

Nadat u deze cursus hebt voltooid, beschikt u over een Mixed Reality HoloLens-toepassing, waarmee u het volgende kunt doen:

  1. Tik met de beweging Tikken op een object, waardoor de gebruiker wordt gevraagd zich aan te melden bij een Microsoft-account (ga uit de app om u aan te melden en vervolgens weer terug bij de app).
  2. Bekijk een lijst met vergaderingen die voor die dag zijn gepland.

In uw toepassing is het aan u om te bepalen hoe u de resultaten integreert met uw ontwerp. In deze cursus leert u hoe u een Azure-service integreert met uw Unity-project. Het is uw taak om de kennis die u opdoen uit deze cursus te gebruiken om uw mixed reality-toepassing te verbeteren.

Ondersteuning voor apparaten

Cursus HoloLens Immersive headsets
MR en Azure 311: Microsoft Graph ✔️

Vereisten

Notitie

Deze zelfstudie is bedoeld voor ontwikkelaars die basiservaring hebben met Unity en C#. Houd er ook rekening mee dat de vereisten en schriftelijke instructies in dit document overeenkomen met wat is getest en geverifieerd op het moment van schrijven (juli 2018). U bent vrij om de nieuwste software te gebruiken, zoals vermeld in het artikel over het installeren van de hulpprogramma's , hoewel niet mag worden aangenomen dat de informatie in deze cursus perfect overeenkomt met wat u in nieuwere software vindt dan wat hieronder wordt vermeld.

Voor deze cursus raden we de volgende hardware en software aan:

Voordat u begint

  1. Om problemen met het bouwen van dit project te voorkomen, wordt u sterk aangeraden het project dat in deze zelfstudie wordt genoemd, te maken in een hoofdmap of een bijna-hoofdmap (lange mappaden kunnen problemen veroorzaken tijdens het bouwen).
  2. Stel uw HoloLens in en test deze. Als u ondersteuning nodig hebt bij het instellen van uw HoloLens, raadpleegt u het artikel Over het instellen van HoloLens.
  3. Het is een goed idee om kalibratie en sensorafstemming uit te voeren wanneer u begint met het ontwikkelen van een nieuwe HoloLens-app (soms kan het helpen om deze taken voor elke gebruiker uit te voeren).

Volg deze koppeling naar het artikel HoloLens-kalibratie voor hulp bij kalibratie.

Volg deze koppeling naar het artikel HoloLens Sensor Tuning voor hulp bij sensorafstemming.

Hoofdstuk 1: Uw app maken in de portal voor toepassingsregistratie

Om te beginnen moet u uw toepassing maken en registreren in de portal voor toepassingsregistratie.

In dit hoofdstuk vindt u ook de servicesleutel waarmee u Microsoft Graph kunt aanroepen om toegang te krijgen tot uw accountinhoud.

  1. Ga naar de Microsoft Application Registration Portal en meld u aan met uw Microsoft-account. Nadat u zich hebt aangemeld, wordt u omgeleid naar de portal voor toepassingsregistratie.

  2. Klik in de sectie Mijn toepassingen op de knop Een app toevoegen.

    Schermopname die laat zien waar u Een app toevoegen kunt selecteren.

    Belangrijk

    De portal voor toepassingsregistratie kan er anders uitzien, afhankelijk van of u eerder met Microsoft Graph hebt gewerkt. In de onderstaande schermafbeeldingen worden deze verschillende versies weergegeven.

  3. Voeg een naam toe voor uw toepassing en klik op Maken.

    Schermopname die laat zien waar u een naam voor uw toepassing kunt toevoegen.

  4. Zodra de toepassing is gemaakt, wordt u omgeleid naar de hoofdpagina van de toepassing. Kopieer de toepassings-id en noteer deze waarde op een veilige plaats. U gebruikt deze binnenkort in uw code.

    Schermopname die laat zien waar de toepassings-id kan worden weergegeven.

  5. Controleer in de sectie Platforms of Systeemeigen toepassing wordt weergegeven. Als u dit niet wilt doen, klikt u op Platform toevoegen en selecteert u Systeemeigen toepassing.

    Schermopname met de sectie Systeemeigen toepassing gemarkeerd.

  6. Schuif omlaag op dezelfde pagina en in de sectie Met de naam Microsoft Graph-machtigingen moet u extra machtigingen voor de toepassing toevoegen. Klik op Toevoegen naast Gedelegeerde machtigingen.

    Schermopname die laat zien waar u Toevoegen selecteert naast Gedelegeerde machtigingen.

  7. Omdat u wilt dat uw toepassing toegang heeft tot de Agenda van de gebruiker, schakelt u het selectievakje Calendars.Read in en klikt u op OK.

    Schermopname van het selectievakje Calendars.Read.

  8. Schuif naar beneden en klik op de knop Opslaan .

    Schermopname die laat zien waar u Opslaan kunt selecteren.

  9. Uw opslag wordt bevestigd en u kunt zich afmelden bij de portal voor toepassingsregistratie.

Hoofdstuk 2 - Het Unity-project instellen

Het volgende is een typische set-up voor het ontwikkelen met mixed reality en is daarom een goede sjabloon voor andere projecten.

  1. Open Unity en klik op Nieuw.

    Schermopname van de Unity-interface.

  2. U moet een Unity-projectnaam opgeven. MSGraphMR invoegen. Zorg ervoor dat de projectsjabloon is ingesteld op 3D. Stel de locatie in op een locatie die geschikt is voor u (houd er rekening mee dat dichter bij hoofdmappen beter is). Klik vervolgens op Project maken.

    Schermopname die laat zien waar u Project maken kunt selecteren.

  3. Als Unity is geopend, is het de moeite waard om te controleren of de standaardscripteditor is ingesteld op Visual Studio. Ga naar Voorkeuren bewerken> en navigeer vervolgens vanuit het nieuwe venster naar Externe hulpprogramma's. Wijzig De externe scripteditor in Visual Studio 2017. Sluit het venster Voorkeuren .

    Schermopname die laat zien waar de externe scripteditor moet worden ingesteld op Visual Studio 2017.

  4. Ga naar File>Build Settings en selecteer Universeel Windows-platform en klik vervolgens op de knop Switch Platform om uw selectie toe te passen.

    Schermopname die laat zien waar u Schakelen tussen platformen kunt selecteren.

  5. Terwijl u zich nog steeds inde instellingen voor het> maken van bestanden hebt, moet u ervoor zorgen dat:

    1. Doelapparaat is ingesteld op HoloLens

    2. Buildtype is ingesteld op D3D

    3. SDK is ingesteld op Laatst geïnstalleerd

    4. Visual Studio-versie is ingesteld op Laatst geïnstalleerd

    5. Bouwen en uitvoeren is ingesteld op Lokale computer

    6. Sla de scène op en voeg deze toe aan de build.

      1. U doet dit door Open scènes toevoegen te selecteren. Er wordt een venster voor opslaan weergegeven.

        Schermopname die laat zien waar u Geopende scènes toevoegen kunt selecteren.

      2. Maak een nieuwe map voor deze scène en een eventuele toekomstige scène. Selecteer de knop Nieuwe map en geef deze de naam Scènes om een nieuwe map te maken.

        Schermopname van de naam van de nieuwe map.

      3. Open de zojuist gemaakte map Scènes en typ in het tekstveld Bestandsnaam: MR_ComputerVisionScene en klik vervolgens op Opslaan.

        Schermopname die laat zien waar de bestandsnaam moet worden getypt.

        Belangrijk

        Houd er rekening mee dat u uw Unity-scènes moet opslaan in de map Assets , omdat deze moeten worden gekoppeld aan het Unity-project. Het maken van de scènemap (en andere vergelijkbare mappen) is een typische manier om een Unity-project te structureren.

    7. De overige instellingen in Build-instellingen moeten voorlopig als standaard worden ingesteld.

  6. Klik in het venster Build-instellingen op de knop Spelerinstellingen . Hiermee opent u het gerelateerde deelvenster in de ruimte waar de Inspector zich bevindt.

    Schermopname van het dialoogvenster Spelerinstellingen.

  7. In dit deelvenster moeten enkele instellingen worden geverifieerd:

    1. Op het tabblad Overige instellingen :

      1. De runtimeversievan script moet experimenteel zijn (equivalent van.NET 4.6), waardoor de editor opnieuw moet worden gestart.

      2. De back-end van scripts moet .NET zijn

      3. API-compatibiliteitsniveau moet .NET 4.6 zijn

        Schermopname die laat zien waar het API-compatibiliteitsniveau moet worden gecontroleerd.

    2. Schakel op het tabblad Publicatie-instellingen onder Mogelijkheden het volgende in:

      • InternetClient

        Schermopname die laat zien waar u de optie InternetClient kunt selecteren.

    3. Verderop in het deelvenster, in XR-instellingen (onder Publicatie-instellingen), selecteert u Virtual Reality Supported en controleert u of de Windows Mixed Reality SDK is toegevoegd.

      Schermopname die laat zien waar u Windows Mixed Reality SDK kunt toevoegen.

  8. In de build-instellingen wordt Unity C#-projecten niet langer grijs weergegeven; schakel het selectievakje naast dit selectievakje in.

  9. Sluit het venster Build Settings.

  10. Sla uw scène en project op (SCÈNES OPSLAAN BESTAND>/PROJECT OPSLAAN VAN BESTAND>).

Hoofdstuk 3 - Bibliotheken importeren in Unity

Belangrijk

Als u het Unity Set up-onderdeel van deze cursus wilt overslaan en direct wilt doorgaan met code, kunt u dit Azure-MR-311.unitypackage downloaden, het in uw project importeren als een aangepast pakket en vervolgens doorgaan vanaf Hoofdstuk 5.

Als u Microsoft Graph in Unity wilt gebruiken, moet u gebruikmaken van de DLL Microsoft.Identity.Client . Het is mogelijk om de Microsoft Graph SDK te gebruiken, maar hiervoor moet een NuGet-pakket worden toegevoegd nadat u het Unity-project hebt gebouwd (dat wil zeggen het bewerken van het project na de build). Het wordt eenvoudiger geacht om de vereiste DLL's rechtstreeks in Unity te importeren.

Notitie

Er is momenteel een bekend probleem in Unity waardoor invoegtoepassingen na het importeren opnieuw moeten worden geconfigureerd. Deze stappen (4 - 7 in deze sectie) zijn niet meer vereist nadat de fout is opgelost.

Als u Microsoft Graph wilt importeren in uw eigen project, downloadt u het MSGraph_LabPlugins.zip-bestand. Dit pakket is gemaakt met versies van de bibliotheken die zijn getest.

Als u meer wilt weten over het toevoegen van aangepaste DLL's aan uw Unity-project, volgt u deze koppeling.

Het pakket importeren:

  1. Voeg het Unity-pakket toe aan Unity met behulp van de menuoptieAangepast pakket voor hetimporteren> van assets>. Selecteer het pakket dat u zojuist hebt gedownload.

  2. Zorg ervoor dat in het venster Unity Package importeren alles onder (en inclusief) Invoegtoepassingen is geselecteerd.

    Schermopname van de geselecteerde configuratieparameters onder Invoegtoepassingen.

  3. Klik op de knop Importeren om de items toe te voegen aan uw project.

  4. Ga naar de map MSGraph onder Invoegtoepassingen in het projectvenster en selecteer de invoegtoepassing met de naam Microsoft.Identity.Client.

    Schermopname van de invoegtoepassing Microsoft.Identity.Client.

  5. Terwijl de invoegtoepassing is geselecteerd, controleert u of Any Platform is uitgeschakeld en zorgt u ervoor dat WSAPlayer ook is uitgeschakeld en klikt u vervolgens op Toepassen. Dit is alleen om te bevestigen dat de bestanden correct zijn geconfigureerd.

    Schermopname die laat zien waar te bevestigen dat Any Platform en WSAPlayer niet zijn ingeschakeld.

    Notitie

    Als u deze invoegtoepassingen markeert, worden ze alleen geconfigureerd voor gebruik in de Unity-editor. Er is een andere set DLL's in de WSA-map die wordt gebruikt nadat het project is geëxporteerd uit Unity als een Universele Windows-toepassing.

  6. Vervolgens moet u de map WSA openen in de map MSGraph . U ziet een kopie van hetzelfde bestand dat u zojuist hebt geconfigureerd. Selecteer het bestand en klik vervolgens in de inspector:

    • zorg ervoor dat Elk platform is uitgeschakeld en dat alleenWSAPlayer is ingeschakeld.

    • Zorg ervoor dat de SDK is ingesteld op UWP en de back-end van scripts is ingesteld op Dot Net

    • Zorg ervoor dat Niet verwerken is ingeschakeld.

      Schermopname die laat zien dat Niet verwerken is geselecteerd.

  7. Klik op Toepassen.

Hoofdstuk 4 - Camera-installatie

Tijdens dit hoofdstuk stelt u de hoofdcamera van uw scène in:

  1. Selecteer in het deelvenster Hiërarchie de hoofdcamera.

  2. Eenmaal geselecteerd, kunt u alle onderdelen van de hoofdcamera in het deelvenster Inspector zien.

    1. Het object Camera moet de naam Hoofdcamera hebben (let op de spelling!)

    2. Het hoofdcameralabel moet zijn ingesteld op MainCamera (let op de spelling!)

    3. Zorg ervoor dat de transformatiepositie is ingesteld op 0, 0, 0

    4. Markeringen wissen instellen op effen kleur

    5. Stel de achtergrondkleur van het cameraonderdeel in op Zwart, Alfa 0(HexCode: #00000000)

      Schermopname waarin wordt gemarkeerd waar de achtergrondkleur moet worden ingesteld.

  3. De uiteindelijke objectstructuur in het deelvenster Hiërarchie moet er uitzien zoals in de onderstaande afbeelding:

    Schermopname van de uiteindelijke objectstructuur in het deelvenster Hiërarchie.

Hoofdstuk 5 - De klasse MeetingsUI maken

Het eerste script dat u moet maken, is MeetingsUI, dat verantwoordelijk is voor het hosten en vullen van de gebruikersinterface van de toepassing (welkomstbericht, instructies en de details van de vergaderingen).

Ga als volgt te werk om deze klasse te maken:

  1. Klik met de rechtermuisknop op de map Assets in het deelvenster Project en selecteer Map maken>. Noem de map Scripts.

    Schermopname die laat zien waar u de map Assets kunt vinden.Schermopname die laat zien waar de map Scripts moet worden gemaakt.

  2. Open de map Scripts en klik in die map met de rechtermuisknop opC#-scriptmaken>. Geef het script de naam MeetingsUI.

    Schermopname die laat zien waar de map MeetingsUI moet worden gemaakt.

  3. Dubbelklik op het nieuwe MeetingsUI-script om het te openen met Visual Studio.

  4. Voeg de volgende naamruimten in:

    using System;
    using UnityEngine;
    
  5. Voeg in de klasse de volgende variabelen in:

        /// <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. Vervang vervolgens de methode Start() en voeg een Awake()- methode toe. Deze worden aangeroepen wanneer de klasse initialiseert:

        /// <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. Voeg de methoden toe die verantwoordelijk zijn voor het maken van de vergaderingsgebruikersinterface en vul deze met de huidige vergaderingen wanneer daarom wordt gevraagd:

        /// <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. Verwijder de methode Update() en sla uw wijzigingen op in Visual Studio voordat u terugkeert naar Unity.

Hoofdstuk 6: De Graph-klasse maken

Het volgende script dat moet worden gemaakt, is het Graph-script . Dit script is verantwoordelijk voor het uitvoeren van de aanroepen om de gebruiker te verifiëren en de geplande vergaderingen voor de huidige dag op te halen uit de agenda van de gebruiker.

Ga als volgt te werk om deze klasse te maken:

  1. Dubbelklik op de map Scripts om deze te openen.

  2. Klik met de rechtermuisknop in de map Scripts en klik opC#-scriptmaken>. Geef het script de naam Graph.

  3. Dubbelklik op het script om het te openen met Visual Studio.

  4. Voeg de volgende naamruimten in:

    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
    

    Belangrijk

    U zult merken dat delen van de code in dit script zijn verpakt rond precompilatie-instructies. Dit is om problemen met de bibliotheken te voorkomen bij het bouwen van de Visual Studio-oplossing.

  5. Verwijder de methoden Start() en Update(), omdat deze niet worden gebruikt.

  6. Voeg buiten de klasse Graph de volgende objecten in, die nodig zijn om het JSON-object dat de dagelijks geplande vergaderingen vertegenwoordigt, te deserialiseren:

    /// <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. Voeg in de klasse Graph de volgende variabelen toe:

        /// <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;
    
    

    Notitie

    Wijzig de waarde van appId in de app-id die u hebt genoteerd in hoofdstuk 1, stap 4. Deze waarde moet hetzelfde zijn als de waarde die wordt weergegeven in de portal voor toepassingsregistratie op de registratiepagina van uw toepassing.

  8. Voeg in de Graph-klasse de methoden SignInAsync() en AquireTokenAsync() toe, waarmee de gebruiker wordt gevraagd de aanmeldingsreferenties in te voegen.

        /// <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. Voeg de volgende twee methoden toe:

    1. BuildTodayCalendarEndpoint(), waarmee de URI wordt samengesteld die de dag en tijdsperiode aangeeft waarin de geplande vergaderingen worden opgehaald.

    2. ListMeetingsAsync(), waarmee de geplande vergaderingen worden aangevraagd bij 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. U hebt nu het Graph-script voltooid. Sla uw wijzigingen op in Visual Studio voordat u terugkeert naar Unity.

Hoofdstuk 7- Het GazeInput-script maken

U maakt nu de GazeInput. Deze klasse verwerkt en houdt de blik van de gebruiker bij met behulp van een Raycast die afkomstig is van de hoofdcamera, die vooruit projecteert.

Het script maken:

  1. Dubbelklik op de map Scripts om deze te openen.

  2. Klik met de rechtermuisknop in de map Scripts en klik opC#-scriptmaken>. Geef het script de naam GazeInput.

  3. Dubbelklik op het script om het te openen met Visual Studio.

  4. Wijzig de naamruimtecode zodat deze overeenkomt met de onderstaande code, samen met het toevoegen van de tag [System.Serializable] boven uw GazeInput-klasse , zodat deze kan worden geserialiseerd:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Voeg in de klasse GazeInput de volgende variabelen toe:

        [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. Voeg de methode CreateCursor() toe om de HoloLens-cursor in de scène te maken en roep de methode aan vanuit de methode 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. Met de volgende methoden kunt u raycast staren en de focusobjecten bijhouden.

    /// <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. Sla uw wijzigingen op in Visual Studio voordat u terugkeert naar Unity.

Hoofdstuk 8: De klasse Interacties maken

U moet nu het interactiesscript maken, dat verantwoordelijk is voor:

  • Het verwerken van de tikinteractie en de Camera Gaze, waarmee de gebruiker kan communiceren met de 'knop' voor aanmelden in de scène.

  • Het object 'knop' voor logboeken maken in de scène waarmee de gebruiker kan communiceren.

Het script maken:

  1. Dubbelklik op de map Scripts om deze te openen.

  2. Klik met de rechtermuisknop in de map Scripts en klik opC#-scriptmaken>. Geef het script de naam Interacties.

  3. Dubbelklik op het script om het te openen met Visual Studio.

  4. Voeg de volgende naamruimten in:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Wijzig de overname van de klasse Interaction van MonoBehaviour in GazeInput.

    interacties van openbare klasse: MonoBehaviour

    public class Interactions : GazeInput
    
  6. Voeg in de klasse Interactie de volgende variabele in:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Vervang de startmethode ; u ziet dat het een onderdrukkingsmethode is, die de 'base' Gaze-klassemethode aanroept. Start() wordt aangeroepen wanneer de klasse wordt geïnitialiseerd, registreert voor invoerherkenning en maakt de aanmeldingsknop in de scène:

        /// <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. Voeg de methode CreateSignInButton() toe, waarmee de aanmeldingsknop in de scène wordt geïnstitueerde en de eigenschappen ervan worden ingesteld:

        /// <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. Voeg de methode GestureRecognizer_Tapped() toe, die moet reageren op de gebeurtenis Tik gebruiker.

        /// <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. Verwijder de methode Update() en sla uw wijzigingen op in Visual Studio voordat u terugkeert naar Unity.

Hoofdstuk 9- Scriptverwijzingen instellen

In dit hoofdstuk moet u het interactiesscript op de hoofdcamera plaatsen. Dat script zorgt er vervolgens voor dat de andere scripts op de gewenste locatie worden geplaatst.

  • Sleep vanuit de map Scripts in het deelvenster Project het script Interacties naar het object Hoofdcamera , zoals hieronder wordt weergegeven.

    Schermopname die laat zien waar het script Interacties moet worden gesleept.

Hoofdstuk 10 - De tag instellen

De code die de blik verwerkt, maakt gebruik van de Tag SignInButton om te bepalen met welk object de gebruiker zal communiceren om zich aan te melden bij Microsoft Graph.

Ga als volgende te werk om de tag te maken:

  1. Klik in de Unity-editor op de hoofdcamera in het deelvenster Hiërarchie.

  2. Klik in het deelvenster Inspector op de tag MainCamera om een vervolgkeuzelijst te openen. Klik op Tag toevoegen...

    Schermopname waarin tag toevoegen wordt gemarkeerd... Optie.

  3. Klik op de + knop.

    Schermopname van de knop +.

  4. Schrijf de tagnaam als SignInButton en klik op Opslaan.

    Schermopname die laat zien waar de tagnaam SignInButton moet worden toegevoegd.

Hoofdstuk 11- Het Unity-project naar UWP bouwen

Alles wat nodig is voor de Unity-sectie van dit project is nu voltooid, dus het is tijd om het te bouwen vanuit Unity.

  1. Navigeer naar Build-instellingen (Instellingen voorbestandsbuilding>).

    Schermopname van het dialoogvenster Build Settings.

  2. Als u dit nog niet hebt, selecteert u Unity C#-projecten.

  3. Klik op Build. Unity start een Bestandenverkenner-venster, waarin u een map moet maken en selecteren om de app in te bouwen. Maak die map nu en geef deze de naam App. Klik vervolgens met de map App geselecteerd op Map selecteren.

  4. Unity begint met het bouwen van uw project in de map App .

  5. Zodra Unity klaar is met het bouwen (dit kan enige tijd duren), wordt er een Bestandenverkenner venster geopend op de locatie van uw build (controleer de taakbalk, omdat deze mogelijk niet altijd boven uw vensters wordt weergegeven, maar u wordt op de hoogte gesteld van de toevoeging van een nieuw venster).

Hoofdstuk 12- Implementeren naar HoloLens

Implementeren op HoloLens:

  1. U hebt het IP-adres van uw HoloLens nodig (voor Externe implementatie) en om ervoor te zorgen dat uw HoloLens zich in de ontwikkelaarsmodus bevindt. Ga als volgt te werk:

    1. Open de Instellingen terwijl u uw HoloLens draagt.

    2. Ga naarGeavanceerde optiesvoor Netwerk & Internet>Wi-Fi>

    3. Noteer het IPv4-adres .

    4. Ga vervolgens terug naar Instellingen en vervolgens naar Update & Security>for Developers

    5. Stel de ontwikkelaarsmodus in op.

  2. Navigeer naar uw nieuwe Unity-build (de map App ) en open het oplossingsbestand met Visual Studio.

  3. Selecteer foutopsporing in de oplossingsconfiguratie.

  4. Selecteer in solution platform de optie x86, Remote Machine. U wordt gevraagd het IP-adres van een extern apparaat in te voegen (in dit geval de HoloLens, die u hebt genoteerd).

    Schermopname die laat zien waar x86 en Externe machine moeten worden geselecteerd.

  5. Ga naar het menu Bouwen en klik op Oplossing implementeren om de toepassing te sideloaden naar uw HoloLens.

  6. Uw app wordt nu weergegeven in de lijst met geïnstalleerde apps op uw HoloLens, klaar om te worden gestart.

Uw Microsoft Graph HoloLens-toepassing

Gefeliciteerd, u hebt een mixed reality-app gemaakt die gebruikmaakt van Microsoft Graph om agendagegevens van gebruikers te lezen en weer te geven.

Schermopname van de voltooide mixed reality-app.

Bonusoefeningen

Oefening 1

Microsoft Graph gebruiken om andere informatie over de gebruiker weer te geven

  • E-mailadres/telefoonnummer van gebruiker/profielafbeelding

Oefening 1

Implementeer spraakbesturing om door de gebruikersinterface van Microsoft Graph te navigeren.