HoloLens (1. generace) a Azure 311 – Microsoft Graph

Poznámka

Kurzy Mixed Reality Academy byly navrženy s ohledem na HoloLens (1. generace) a Mixed Reality Asistivní náhlavní soupravy. Proto se domníváme, že je důležité ponechat tyto kurzy pro vývojáře, kteří stále hledají pokyny k vývoji pro tato zařízení. Tyto kurzy nebudou aktualizovány nejnovějšími sadami nástrojů nebo interakcemi používanými pro HoloLens 2. Budou zachovány, aby mohly pokračovat v práci na podporovaných zařízeních. V budoucnu bude k dispozici nová série kurzů, které předvedou, jak vyvíjet pro HoloLens 2. Toto oznámení bude aktualizováno odkazem na tyto kurzy, jakmile budou publikovány.

V tomto kurzu se dozvíte, jak se pomocí Microsoft Graphu přihlásit k účtu Microsoft pomocí zabezpečeného ověřování v aplikaci hybridní reality. Potom načtete a zobrazíte naplánované schůzky v rozhraní aplikace.

Snímek obrazovky znázorňující naplánované schůzky v rozhraní aplikace

Microsoft Graph je sada rozhraní API navržená tak, aby umožňovala přístup k mnoha službám Microsoftu. Microsoft popisuje Microsoft Graph jako matici prostředků propojených relacemi, což znamená, že umožňuje aplikaci přistupovat k nejrůznějším připojeným uživatelským datům. Další informace najdete na stránce Microsoft Graphu.

Vývoj bude zahrnovat vytvoření aplikace, ve které bude uživatel vyzván, aby se podíval na kouli a potom na kouli, což uživatele vyzve k bezpečnému přihlášení k účtu Microsoft. Jakmile se uživatel přihlásí ke svému účtu, uvidí seznam schůzek naplánovaných na tento den.

Po dokončení tohoto kurzu budete mít aplikaci HoloLens pro hybridní realitu, která bude umět následující:

  1. Pomocí gesta klepnutí klepněte na objekt, který uživatele vyzve k přihlášení k účtu Microsoft (přesun z aplikace, aby se přihlásil, a pak se do aplikace znovu vrátil).
  2. Zobrazí seznam schůzek naplánovaných na tento den.

Ve vaší aplikaci je na vás, jak do návrhu integrujete výsledky. Tento kurz je navržený tak, aby vás naučil integrovat službu Azure s projektem Unity. Vaším úkolem je využít znalosti, které z tohoto kurzu získáte, k vylepšení aplikace hybridní reality.

Podpora zařízení

Kurz HoloLens Imerzivní náhlavní soupravy
MR a Azure 311: Microsoft Graph ✔️

Požadavky

Poznámka

Tento kurz je určený pro vývojáře, kteří mají základní zkušenosti s Unity a C#. Mějte také na paměti, že požadavky a písemné pokyny v tomto dokumentu představují to, co bylo testováno a ověřeno v době psaní tohoto dokumentu (červenec 2018). Můžete používat nejnovější software, jak je uvedeno v článku instalace nástrojů , i když by se nemělo předpokládat, že informace v tomto kurzu budou dokonale odpovídat tomu, co najdete v novějším softwaru, než je uvedeno níže.

Pro tento kurz doporučujeme následující hardware a software:

Než začnete

  1. Aby nedocházelo k problémům při sestavování tohoto projektu, důrazně doporučujeme vytvořit projekt uvedený v tomto kurzu v kořenové nebo téměř kořenové složce (dlouhé cesty ke složkám můžou způsobovat problémy v době sestavení).
  2. Nastavte a otestujte HoloLens. Pokud potřebujete podporu při nastavování HoloLensu, navštivte článek o nastavení HoloLensu.
  3. Při zahájení vývoje nové aplikace HoloLens je vhodné provést kalibraci a ladění senzorů (někdy může pomoct provádět tyto úlohy pro každého uživatele).

Nápovědu k kalibraci najdete na tomto odkazu v článku Kalibrace HoloLens.

Pokud potřebujete pomoc s laděním senzorů, postupujte podle tohoto odkazu na článek o ladění snímačů HoloLens.

Kapitola 1 – Vytvoření aplikace na portálu pro registraci aplikací

Nejprve budete muset vytvořit a zaregistrovat aplikaci na portálu pro registraci aplikací.

V této kapitole najdete také klíč služby, který vám umožní volat Microsoft Graph pro přístup k obsahu vašeho účtu.

  1. Přejděte na portál Microsoft Application Registration Portal a přihlaste se pomocí svého účtu Microsoft. Po přihlášení budete přesměrováni na portál pro registraci aplikací.

  2. V části Moje aplikace klikněte na tlačítko Přidat aplikaci.

    Snímek obrazovky, který ukazuje, kde vybrat Přidat aplikaci

    Důležité

    Portál pro registraci aplikací může vypadat jinak v závislosti na tom, jestli jste dříve pracovali s Microsoft Graphem. Následující snímky obrazovky zobrazují tyto různé verze.

  3. Přidejte název aplikace a klikněte na Vytvořit.

    Snímek obrazovky, který ukazuje, kam přidat název aplikace

  4. Po vytvoření aplikace budete přesměrováni na hlavní stránku aplikace. Zkopírujte ID aplikace a nezapomeňte si tuto hodnotu někde bezpečně poznamenat. Brzy ho použijete ve svém kódu.

    Snímek obrazovky, který ukazuje, kde zobrazit ID aplikace

  5. V části Platformy se ujistěte, že je zobrazená nativní aplikace . Pokud ne , klikněte na Přidat platformu a vyberte Nativní aplikace.

    Snímek obrazovky se zvýrazněnou částí Nativní aplikace

  6. Posuňte se dolů na stejné stránce a v části s názvem Oprávnění Microsoft Graphu budete muset pro aplikaci přidat další oprávnění. Klikněte na Přidat vedle delegovaných oprávnění.

    Snímek obrazovky, který ukazuje, kde vybrat Přidat vedle položky Delegovaná oprávnění

  7. Vzhledem k tomu, že chcete, aby vaše aplikace přistupovala ke kalendáři uživatele, zaškrtněte políčko s názvem Calendars.Read a klikněte na OK.

    Snímek obrazovky, který zobrazuje zaškrtávací políčko Calendars.Read

  8. Posuňte se dolů a klikněte na tlačítko Uložit .

    Snímek obrazovky, který ukazuje, kam vybrat Uložit

  9. Uložení se potvrdí a můžete se odhlásit z portálu pro registraci aplikací.

Kapitola 2 – Nastavení projektu Unity

Následující příklad je typickým nastavením pro vývoj s hybridní realitou a jako takový je dobrou šablonou pro další projekty.

  1. Otevřete Unity a klikněte na Nový.

    Snímek obrazovky s rozhraním Unity

  2. Musíte zadat název projektu Unity. Vložte MSGraphMR. Ujistěte se, že je šablona projektu nastavená na 3D. Nastavte umístění na místo, které je pro vás vhodné (nezapomeňte, že lepší je blíž ke kořenovým adresářům). Pak klikněte na Vytvořit projekt.

    Snímek obrazovky, který ukazuje, kde vybrat Vytvořit projekt

  3. Když je Unity otevřená, stojí za to zkontrolovat, jestli je výchozí Editor skriptů nastavený na Visual Studio. Přejděte na Upravit>předvolby a pak v novém okně přejděte na Externí nástroje. Změňte Editor externích skriptů na Visual Studio 2017. Zavřete okno Předvolby .

    Snímek obrazovky, který ukazuje, kde nastavit Editor externích skriptů na Visual Studio 2017

  4. Přejděte naNastavení sestavenísouboru>, vyberte Univerzální platforma Windows a pak klikněte na tlačítko Přepnout platformu, aby se váš výběr použil.

    Snímek obrazovky, který ukazuje, kde vybrat Přepnout platformu

  5. Vnastavení sestavenísouboru> se ujistěte, že:

    1. Cílové zařízení je nastavené na HoloLens.

    2. Typ sestavení je nastavený na D3D.

    3. Sada SDK je nastavená na nejnovější nainstalovanou verzi.

    4. Verze sady Visual Studio je nastavená na nejnovější nainstalovanou verzi

    5. Sestavení a spuštění je nastavené na místní počítač.

    6. Uložte scénu a přidejte ji do sestavení.

      1. Uděláte to tak, že vyberete Přidat otevřené scény. Zobrazí se okno pro uložení.

        Snímek obrazovky, který ukazuje, kde vybrat Přidat otevřené scény

      2. Vytvořte novou složku pro tuto a jakoukoli budoucí scénu. Vyberte tlačítko Nová složka a vytvořte novou složku a pojmenujte ji Scény.

        Snímek obrazovky, který ukazuje, kde se má nová složka pojmenovat

      3. Otevřete nově vytvořenou složku Scény , do textového pole Název souboru: zadejte MR_ComputerVisionScene a klikněte na Uložit.

        Snímek obrazovky, který ukazuje, kam zadat název souboru

        Důležité

        Mějte na paměti, že scény Unity musíte uložit do složky Assets , protože musí být přidružené k projektu Unity. Typickým způsobem strukturování projektu Unity je vytvoření složky scenes (a dalších podobných složek).

    7. Zbývající nastavení v nastavení sestavení by prozatím měla zůstat ve výchozím nastavení.

  6. V okně Build Settings (Nastavení sestavení ) klikněte na tlačítko Player Settings (Nastavení přehrávače ). Tím se otevře související panel v prostoru, kde se inspektor nachází.

    Snímek obrazovky s dialogovým oknem Nastavení přehrávače

  7. Na tomto panelu je potřeba ověřit několik nastavení:

    1. Na kartě Další nastavení :

      1. Skriptovacímodul runtime verze by měla být experimentální (ekvivalent .NET 4.6), což aktivuje potřebu restartování editoru.

      2. Skriptovací back-end by měl být .NET.

      3. Úroveň kompatibility rozhraní API by měla být .NET 4.6.

        Snímek obrazovky, který ukazuje, kde zkontrolovat úroveň kompatibility rozhraní API

    2. Na kartě Nastavení publikování v části Schopnosti zaškrtněte:

      • InternetClient

        Snímek obrazovky, který ukazuje, kde vybrat možnost InternetClient

    3. Dále na panelu v nastavení XR (najdete pod nastavením publikování) zkontrolujte, že virtuální realita je podporovaná a ujistěte se, že je přidaná sada SDK Windows Mixed Reality.

      Snímek obrazovky, který ukazuje, kam přidat Windows Mixed Reality SDK

  8. Zpátky v nastavení sestavení se projekty Unity C# už nezobrazují šedě. zaškrtněte políčko vedle této položky.

  9. Zavřete okno Nastavení sestavení .

  10. Uložte scénu a projekt (FILE>SAVE SCENE / FILE>SAVE PROJECT).

Kapitola 3 – Import knihoven v Unity

Důležité

Pokud chcete komponentu Unity Set up v tomto kurzu přeskočit a pokračovat přímo do kódu, můžete si stáhnout tento balíček Azure-MR-311.unitypackage, naimportovat ho do projektu jako vlastní balíček a pak pokračovat z Kapitoly 5.

Pokud chcete v Unity používat Microsoft Graph , musíte použít knihovnu DLL Microsoft.Identity.Client . Je možné použít sadu Microsoft Graph SDK, ale po sestavení projektu Unity (tj. úprava projektu po sestavení) bude vyžadovat přidání balíčku NuGet. Import požadovaných knihoven DLL přímo do Unity se považuje za jednodušší.

Poznámka

V Unity je v současné době známý problém, který vyžaduje, aby se moduly plug-in po importu překonfigurovaly. Tyto kroky (4 až 7 v této části) už se po vyřešení chyby nebudou vyžadovat.

Pokud chcete naimportovat Microsoft Graph do vlastního projektu, stáhněte si soubor MSGraph_LabPlugins.zip. Tento balíček byl vytvořen s verzemi knihoven, které byly testovány.

Pokud se chcete dozvědět více o tom, jak do projektu Unity přidat vlastní knihovny DLL, použijte tento odkaz.

Import balíčku:

  1. Přidejte balíček Unity do Unity pomocí možnosti nabídkyVlastní balíček importu balíčků>prostředků>. Vyberte balíček, který jste právě stáhli.

  2. V okně Import Unity Package (Importovat balíček Unity ), které se zobrazí, zkontrolujte, že je vybrané všechno v části Plugins (a včetně).

    Snímek obrazovky znázorňující vybrané parametry konfigurace v části Moduly plug-in

  3. Kliknutím na tlačítko Importovat přidejte položky do projektu.

  4. Přejděte do složky MSGraph v části Moduly plug-in na panelu projektu a vyberte modul plug-in s názvem Microsoft.Identity.Client.

    Snímek obrazovky znázorňující modul plug-in Microsoft.Identity.Client

  5. S vybraným modulem plug-in se ujistěte, že možnost Any Platform (Libovolná platforma) není zaškrtnutá, pak se ujistěte, že není zaškrtnutá také možnost WSAPlayer, a pak klikněte na Apply (Použít). Stačí jenom ověřit, jestli jsou soubory správně nakonfigurované.

    Snímek obrazovky, který ukazuje, kde potvrdit, že není zaškrtnutá možnost Any Platform a WSAPlayer

    Poznámka

    Označení těchto modulů plug-in se nakonfiguruje tak, aby se používaly jenom v Unity Editoru. Složka WSA obsahuje jinou sadu knihoven DLL, které se po exportu projektu z Unity jako univerzální aplikace pro Windows použijí.

  6. Dále musíte otevřít složku WSA ve složce MSGraph . Zobrazí se kopie stejného souboru, který jste právě nakonfigurovali. Vyberte soubor a pak v inspektoru:

    • Ujistěte se, že možnost Any Platform je nezaškrtnutá a že je zaškrtnutápouzeWSAPlayer.

    • Ujistěte se, že je sada SDK nastavená na UPW a skriptovací back-end je nastavená na Dot Net.

    • Ujistěte se, že je zaškrtnuté políčko Nezpracovát.

      Snímek obrazovky, který ukazuje, že je vybraná možnost Nezpracovát

  7. Klikněte na Použít.

Kapitola 4 – Nastavení kamery

Během této kapitoly nastavíte hlavní kameru scény:

  1. Na panelu hierarchie vyberte hlavní kameru.

  2. Po výběru uvidíte na panelu inspektoru všechny součásti hlavní kamery.

    1. Objekt Kamera musí mít název Hlavní kamera (všimněte si pravopisu).)

    2. Značka hlavní kamery musí být nastavená na MainCamera (nezapomeňte na pravopis).)

    3. Ujistěte se, že je pozice transformace nastavená na 0, 0, 0.

    4. Nastavit vymazat příznaky na plnou barvu

    5. Nastavte barvu pozadí komponenty Kamera na černou, alfa 0(šestnáctkový kód: #00000000).

      Snímek obrazovky, který zvýrazňuje, kde se má nastavit barva pozadí

  3. Konečná struktura objektu na panelu hierarchie by měla vypadat jako na následujícím obrázku:

    Snímek obrazovky znázorňující konečnou strukturu objektu na panelu hierarchie

Kapitola 5 – Vytvoření třídy MeetingsUI

První skript, který musíte vytvořit, je MeetingsUI, který je zodpovědný za hostování a naplnění uživatelského rozhraní aplikace (uvítací zpráva, pokyny a podrobnosti o schůzkách).

Vytvoření této třídy:

  1. Klikněte pravým tlačítkem na složku Prostředky na panelu projektu a pak vyberte Vytvořit>složku. Složku pojmenujte Scripts.

    Snímek obrazovky, který ukazuje, kde najít složku AssetsSnímek obrazovky, který ukazuje, kde vytvořit složku Scripts

  2. Otevřete složku Scripts a pak v této složce klikněte pravým tlačítkem na Create C# Script ( Vytvořit>skript jazyka C#). Pojmenujte skript MeetingsUI.

    Snímek obrazovky, který ukazuje, kde vytvořit složku MeetingsUI

  3. Poklikáním na nový skript MeetingsUI ho otevřete v sadě Visual Studio.

  4. Vložte následující obory názvů:

    using System;
    using UnityEngine;
    
  5. Do třídy vložte následující proměnné:

        /// <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. Pak nahraďte metodu Start() a přidejte metodu Awake(). Budou volána při inicializaci třídy:

        /// <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. Přidejte metody zodpovědné za vytvoření uživatelského rozhraní schůzek a na vyžádání ho naplňte aktuálními schůzkami:

        /// <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. Odstraňte metodu Update() a před návratem do Unity uložte změny v sadě Visual Studio.

Kapitola 6 – Vytvoření třídy Graphu

Dalším skriptem, který se má vytvořit, je skript graphu . Tento skript zodpovídá za volání za účelem ověření uživatele a načtení naplánovaných schůzek pro aktuální den z jeho kalendáře.

Vytvoření této třídy:

  1. Poklikáním na složku Scripts ji otevřete.

  2. Klikněte pravým tlačítkem do složky Scripts (Skripty) a klikněte na CreateC# Script (Vytvořit > skript jazyka C#). Skript pojmenujte Graph.

  3. Poklikáním na skript ho otevřete v sadě Visual Studio.

  4. Vložte následující obory názvů:

    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
    

    Důležité

    Všimněte si, že části kódu v tomto skriptu jsou zabalené kolem předkompilních direktiv, aby se zabránilo problémům s knihovnami při sestavování řešení sady Visual Studio.

  5. Odstraňte metody Start() a Update(), protože se nebudou používat.

  6. Mimo třídu Graph vložte následující objekty, které jsou nezbytné k deserializaci objektu JSON představujícího denní naplánované schůzky:

    /// <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. Do třídy Graph přidejte následující proměnné:

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

    Poznámka

    Změňte hodnotu appId na ID aplikace , které jste si poznamenali v kapitole 1, kroku 4. Tato hodnota by měla být stejná jako hodnota zobrazená na portálu pro registraci aplikací na stránce registrace aplikace.

  8. Do třídy Graph přidejte metody SignInAsync() a AquireTokenAsync(), které uživatele vyzve k vložení přihlašovacích údajů.

        /// <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. Přidejte následující dvě metody:

    1. BuildTodayCalendarEndpoint(), který sestaví identifikátor URI určující den a časový rozsah, ve kterém se načítají naplánované schůzky.

    2. ListMeetingsAsync() – žádost o naplánované schůzky z Microsoft Graphu

        /// <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. Teď jste dokončili skript Graphu . Před návratem do Unity uložte změny v sadě Visual Studio.

Kapitola 7 – Vytvoření skriptu GazeInput

Teď vytvoříte GazeInput. Tato třída zpracovává a sleduje pohled uživatele pomocí raycastu pocházejícího z hlavní kamery a promítání dopředu.

Vytvoření skriptu:

  1. Poklikáním na složku Scripts ji otevřete.

  2. Klikněte pravým tlačítkem do složky Scripts (Skripty) a klikněte na CreateC# Script (Vytvořit > skript jazyka C#). Pojmenujte skript GazeInput.

  3. Poklikáním na skript ho otevřete v sadě Visual Studio.

  4. Změňte kód oborů názvů tak, aby odpovídal následujícímu kódu, spolu s přidáním značky [System.Serializable] nad třídu GazeInput , aby ji bylo možné serializovat:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Do třídy GazeInput přidejte následující proměnné:

        [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. Přidejte metodu CreateCursor() pro vytvoření kurzoru HoloLens ve scéně a zavolejte metodu 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. Následující metody umožňují pohled Raycast a sledují objekty s fokusem.

    /// <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. Před návratem do Unity uložte změny v sadě Visual Studio.

Kapitola 8 – Vytvoření třídy Interactions

Teď budete muset vytvořit skript Interakce , který zodpovídá za:

  • Zpracování interakce klepnutí a pohledu z fotoaparátu, který uživateli umožňuje pracovat s tlačítkem přihlášení ve scéně.

  • Vytvoření objektu pro přihlášení "button" ve scéně pro interakci uživatele.

Vytvoření skriptu:

  1. Poklikáním na složku Scripts ji otevřete.

  2. Klikněte pravým tlačítkem do složky Scripts (Skripty) a klikněte na CreateC# Script (Vytvořit > skript jazyka C#). Pojmenujte skript Interakce.

  3. Poklikáním na skript ho otevřete v sadě Visual Studio.

  4. Vložte následující obory názvů:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Změňte dědičnost třídy Interaction z MonoBehaviour na GazeInput.

    public class Interactions : MonoBehaviour

    public class Interactions : GazeInput
    
  6. Do třídy Interaction vložte následující proměnnou:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Nahraďte metodu Start ; všimněte si, že se jedná o metodu přepsání, která volá metodu třídy "base" Gaze. Start() se zavolá, když se třída inicializuje, zaregistruje se pro rozpoznávání vstupu a vytvoří se tlačítko pro přihlášení ve scéně:

        /// <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. Přidejte metodu CreateSignInButton(), která vytvoří instanci přihlašovacího tlačítka ve scéně a nastaví jeho vlastnosti:

        /// <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. Přidejte metodu GestureRecognizer_Tapped(), která bude odpovídat na událost Uživatele Tap .

        /// <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. Odstraňte metodu Update() a před návratem do Unity uložte změny v sadě Visual Studio.

Kapitola 9 – Nastavení odkazů na skripty

V této kapitole musíte umístit skript Interakce na hlavní kameru. Tento skript pak zpracuje umístění ostatních skriptů tam, kde je potřeba.

  • Ze složky Skripty na panelu projektu přetáhněte skript Interakce do objektu Hlavní kamera , jak je znázorněno níže.

    Snímek obrazovky, který ukazuje, kam přetáhnout skript Interakce

Kapitola 10 – Nastavení značky

Kód, který zpracovává pohled, použije tag SignInButton k identifikaci objektu, se kterým bude uživatel pracovat, aby se přihlásil k Microsoft Graphu.

Vytvoření značky:

  1. V Editoru Unity klikněte na hlavní kameru na panelu hierarchie.

  2. Na panelu inspektoru kliknutím na značkuMainCamera otevřete rozevírací seznam. Klikněte na Přidat značku...

    Snímek obrazovky se zvýrazněnou značkou Přidat značku... Možnost.

  3. Klikněte na + tlačítko.

    Snímek obrazovky s tlačítkem +

  4. Název značky napište jako SignInButton a klikněte na Uložit.

    Snímek obrazovky, který ukazuje, kam přidat název značky SignInButton

Kapitola 11 – Sestavení projektu Unity pro UPW

Všechno, co je potřeba pro oddíl Unity tohoto projektu, bylo dokončeno, takže je čas ho sestavit z Unity.

  1. Přejděte na Nastavení sestavení (Nastavení sestavenísouboru>).

    Snímek obrazovky s dialogovým oknem Nastavení sestavení

  2. Pokud tomu tak není, zaškrtněte políčko Projekty Unity C#.

  3. Klikněte na Sestavit. Unity spustí Průzkumník souborů okno, ve kterém musíte vytvořit a pak vybrat složku, do které chcete aplikaci sestavit. Vytvořte teď složku a pojmenujte ji App. Potom vyberte složku Aplikace a klikněte na Vybrat složku.

  4. Unity začne vytvářet projekt do složky Aplikace .

  5. Jakmile Unity dokončí sestavování (může to nějakou dobu trvat), otevře se okno Průzkumník souborů v umístění vašeho buildu (zkontrolujte hlavní panel, protože se nemusí vždy zobrazovat nad vašimi okny, ale upozorní vás na přidání nového okna).

Kapitola 12 – Nasazení do HoloLensu

Nasazení na HoloLens:

  1. Budete potřebovat IP adresu vašeho HoloLensu (pro vzdálené nasazení) a zajistit, aby byl Váš HoloLens ve vývojářském režimu. Postup:

    1. Při nošení HoloLensu otevřete Nastavení.

    2. Přejděte do částiRozšířené možnostiwi-fi>sítě & internetu>.

    3. Poznamenejte si IPv4 adresu.

    4. Pak přejděte zpět na Nastavení a pak na Aktualizovat zabezpečení &>pro vývojáře.

    5. Nastavte vývojářský režim na zapnuto.

  2. Přejděte do nového sestavení Unity (složka Aplikace ) a otevřete soubor řešení v sadě Visual Studio.

  3. V části Konfigurace řešení vyberte Ladit.

  4. Na platformě řešení vyberte x86, Vzdálený počítač. Zobrazí se výzva k vložení IP adresy vzdáleného zařízení (v tomto případě HoloLens, který jste si poznamenali).

    Snímek obrazovky, který ukazuje, kde vybrat x86 a Vzdálený počítač

  5. Přejděte do nabídky Build (Sestavení ) a klikněte na Deploy Solution (Nasadit řešení ) a načtěte aplikaci do HoloLensu bokem.

  6. Vaše aplikace by se teď měla zobrazit v seznamu nainstalovaných aplikací na holoLensu a měla by být připravená ke spuštění.

Vaše aplikace Microsoft Graph HoloLens

Blahopřejeme, vytvořili jste aplikaci hybridní reality, která využívá Microsoft Graph ke čtení a zobrazení dat kalendáře uživatelů.

Snímek obrazovky s dokončenou aplikací hybridní reality

Bonusová cvičení

Cvičení 1

Použití Microsoft Graphu k zobrazení dalších informací o uživateli

  • E-mail uživatele / telefonní číslo / profilový obrázek

Cvičení 1

Implementace hlasového ovládání pro navigaci v uživatelském rozhraní Microsoft Graphu