Sdílet prostřednictvím


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

Poznámka:

Kurzy Mixed Reality Academy byly navrženy s HoloLensem (1. generace) a imerzivními náhlavními soupravami hybridní reality. Proto máme pocit, že je důležité nechat tyto kurzy zavedené pro vývojáře, kteří stále hledají pokyny při vývoji těchto zařízení. Tyto kurzy nebudou aktualizovány nejnovějšími sadami nástrojů ani interakcemi používanými pro HoloLens 2. Budou zachovány, aby pokračovaly v práci na podporovaných zařízeních. Bude k dispozici nová série kurzů, které budou publikovány v budoucnu, které předvádějí, jak vyvíjet pro HoloLens 2. Toto oznámení se při publikování aktualizuje odkazem na tyto kurzy.

V tomto kurzu se dozvíte, jak se pomocí Microsoft Graphu přihlásit ke svému účtu Microsoft pomocí zabezpečeného ověřování v rámci aplikace hybridní reality. Pak 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 aplikace umožňuje přístup 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, na které bude uživatel vyzván, aby se podíval a potom klepněte na kouli, která uživatele vyzve, aby se bezpečně přihlásil k účtu Microsoft. Po přihlášení ke svému účtu uvidí uživatel seznam schůzek naplánovaných pro tento den.

Po dokončení tohoto kurzu budete mít aplikaci HoloLens pro hybridní realitu, která bude moct provést následující akce:

  1. Pomocí gesta klepnutím klepněte na objekt, který vyzve uživatele, aby se přihlásil k účtu Microsoft (přesunem z aplikace, aby se přihlásil a pak se znovu k aplikaci vrátil).
  2. Umožňuje zobrazit seznam schůzek naplánovaných pro tento den.

V aplikaci je na vás, jak integrovat výsledky s návrhem. Tento kurz je navržený tak, aby vás naučil, jak integrovat službu Azure s projektem Unity. Vaším úkolem je využít znalosti získané z tohoto kurzu 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 otestováno a ověřeno v době psaní (červenec 2018). Můžete používat nejnovější software, jak je uvedeno v článku o instalaci 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. Abyste se vyhnuli 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 k nastavení HoloLens, nezapomeňte navštívit článek o nastavení HoloLens.
  3. Při vývoji nové aplikace HoloLens je vhodné provést kalibraci a ladění senzorů (někdy může pomoct tyto úlohy provádět pro každého uživatele).

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

Nápovědu k ladění senzorů najdete v tomto odkazu na článek o ladění snímačů HoloLens.

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

Abyste mohli začít, 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 Do Microsoft Graphu pro přístup k obsahu vašeho účtu.

  1. Přejděte na portál pro registraci aplikací Microsoftu 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 znázorňující, 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 poznamenat někam bezpečně, brzy ji použijete ve svém kódu.

    Snímek obrazovky znázorňující, kde se má zobrazit ID aplikace

  5. V části Platformy se ujistěte, že je zobrazena 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 přidat další oprávnění pro aplikaci. Klikněte na Přidat vedle delegovaných oprávnění.

    Snímek obrazovky znázorňující, kde vybrat Přidat vedle delegovaných oprávnění

  7. Vzhledem k tomu, že chcete, aby 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 do dolní části a klikněte na tlačítko Uložit .

    Snímek obrazovky, který ukazuje, kam se má 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ásleduje typická sada pro vývoj s hybridní realitou a jako taková je vhodná šablona pro jiné projekty.

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

    Snímek obrazovky znázorňující rozhraní Unity

  2. Potřebujete 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 blíže ke kořenovým adresářům je lepší). Potom klikněte na Vytvořit projekt.

    Snímek obrazovky znázorňující, kde vybrat Vytvořit projekt

  3. Při otevření Unity 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 znázorňující, kde nastavit editor externích skriptů na Visual Studio 2017

  4. Přejděte do Nastavení sestavení souboru>a vyberte Univerzální platforma Windows a kliknutím na tlačítko Přepnout platformu použijte svůj výběr.

    Snímek obrazovky znázorňující, kde vybrat Přepnout platformu

  5. Zůstaňte v nastavení sestavení souborů>a ujistěte se, ž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 znázorňující, kde vybrat Přidat otevřené scény

      2. Vytvořte pro tuto a libovolnou budoucí scénu novou složku. 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 a potom v názvu souboru: textové pole, 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. Vytvoření složky scén (a dalších podobných složek) je typický způsob strukturování projektu Unity.

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

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

    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í verze modulu runtime by měla být experimentální (ekvivalent .NET 4.6), která aktivuje nutnost restartování editoru.

      2. Back-end skriptování 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 Možnosti zaškrtněte:

      • InternetClient

        Snímek obrazovky znázorňující, kde vybrat možnost InternetClient

    3. Dále na panelu v nastavení XR (najdete níže v části Nastavení publikování), zkontrolujte podporu virtuální reality a ujistěte se, že je přidaná sada WINDOWS Mixed Reality SDK.

      Snímek obrazovky znázorňující, kam přidat sadu Windows Mixed Reality SDK

  8. Zpět v nastavení sestavení už projekty Unity C# nejsou zobrazené šedě. Zaškrtněte políčko vedle tohoto nastavení.

  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 přeskočit komponentu Nastavení Unity v tomto kurzu a pokračovat přímo do kódu, můžete si stáhnout tento balíček Azure-MR-311.unitypackage, importovat ho do projektu jako vlastní balíček a pokračovat z kapitoly 5.

Pokud chcete používat Microsoft Graph v Unity, musíte použít knihovnu DLL Microsoft.Identity.Client. Sadu Microsoft Graph SDK je možné použít, ale po sestavení projektu Unity bude vyžadovat přidání balíčku NuGet (což znamená úpravu projektu po sestavení). Je považováno za jednodušší importovat požadované knihovny DLL přímo do Unity.

Poznámka:

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

Pokud chcete importovat 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, postupujte podle tohoto odkazu.

Import balíčku:

  1. Přidejte balíček Unity do Unity pomocí možnosti nabídky Vlastní balíček importu >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še v části (a včetně) modulů plug-in.

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

  3. Kliknutím na tlačítko Importovat přidáte 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. Pokud je vybraný modul plug-in , ujistěte se, že je nezaškrtnutá možnost Libovolná platforma , a ujistěte se, že je také nezaškrtnutá možnost WSAPlayer , a klikněte na tlačítko Použít. Stačí jenom ověřit, že jsou soubory správně nakonfigurované.

    Snímek obrazovky, který ukazuje, kde potvrdit, že žádná platforma a WSAPlayer nejsou zaškrtnuté

    Poznámka:

    Označení těchto modulů plug-in konfiguruje jejich použití pouze v Unity Editoru. Ve složce WSA existuje jiná sada knihoven DLL, která se použije po exportu projektu z Unity jako univerzální aplikace pro Windows.

  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 je nezaškrtnutá žádná platforma a že je zaškrtnuté pouze WSAPlayer.

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

    • Ujistěte se, že není zaškrtnuté políčko Nepracovat.

      Snímek obrazovky, který ukazuje, že není vybraný proces

  7. Klikněte na tlačítko Použit.

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 všechny součásti hlavní kamery na panelu inspektoru.

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

    2. Hlavní značka fotoaparátu musí být nastavená na MainCamera (všimněte si pravopisu!)

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

    4. Nastavení jasných příznaků na plnou barvu

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

      Snímek obrazovky, který zvýrazňuje, kde nastavit barvu pozadí

  3. Konečná struktura objektu v panelu hierarchie by měla být podobná té, která je znázorněna na následujícím obrázku:

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

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

Prvním skriptem, který je potřeba 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. Pravým tlačítkem myši klikněte na složku Assets na panelu projektu a pak vyberte Vytvořit>složku. Pojmenujte složky Skripty.

    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 Skripty a potom v této složce klikněte pravým tlačítkem myši na příkaz Vytvořit>skript jazyka C#. Pojmenujte skript MeetingsUI.

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

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

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

    using System;
    using UnityEngine;
    
  5. Uvnitř 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(). Tyto se budou volat 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 při 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. Před návratem do Unity odstraňte metodu Update() a uložte změny v sadě Visual Studio.

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

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

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

  1. Poklikáním otevřete složku Skripty .

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

  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 direktiv Předkompilu, je to proto, abyste se vyhnuli problémům s knihovnami při sestavování řešení sady Visual Studio.

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

  6. Mimo třídu Graph vložte následující objekty, které jsou nezbytné k deserializaci objektu JSON představujícího každodenní 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 tak, aby byla 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é rozmezí, ve kterém se načítají naplánované schůzky.

    2. ListMeetingsAsync(), která požaduje 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. Dokončili jste 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 přicházejícího z hlavní kamery a promítání vpřed.

Vytvoření skriptu:

  1. Poklikáním otevřete složku Skripty .

  2. Klikněte pravým tlačítkem do složky Scripts (Skripty) a klikněte na Create C# 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 a přidejte značku [System.Serializable] nad třídu GazeInput , aby 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(), která vytvoří kurzor HoloLens ve scéně a zavolá 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 sledovat prioritní objekty.

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

Teď budete muset vytvořit skript Interakce , který je zodpovědný za:

  • Zpracování interakce klepnutím a pohled na kameru, která uživateli umožňuje interakci s logem "button" ve scéně.

  • Vytvoření objektu "button" ve scéně pro interakci uživatele

Vytvoření skriptu:

  1. Poklikáním otevřete složku Skripty .

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

  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.

    Interakce veřejné třídy: 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 jde o metodu přepsání, která volá metodu třídy "base" Gaze. Start() bude volána při inicializaci třídy, registraci pro rozpoznávání vstupu a vytvoření tlačítka 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í její 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. Před návratem do Unity odstraňte metodu Update() a 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 musí být.

  • Ze složky Skripty na panelu projektu přetáhněte interakce skriptu 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 s přihlášením k Microsoft Graphu.

Vytvoření značky:

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

  2. Na panelu inspektoru kliknutím na značku MainCamera 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 znázorňující tlačítko +

  4. Zadejte název značky 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 do UPW

Všechno potřebné 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 ještě ne, zaškrtněte projekty Unity C#.

  3. Klikněte na Sestavit. Unity spustí okno Průzkumník souborů, ve kterém potřebujete vytvořit a pak vybrat složku pro sestavení aplikace. Vytvořte teď složku a pojmenujte ji App. Potom s vybranou složkou Aplikace klikněte na Vybrat složku.

  4. Unity začne sestavovat projekt do složky Aplikace .

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

Kapitola 12 – Nasazení do HoloLens

Nasazení na HoloLens:

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

    1. Když nosíte HoloLens, otevřete Nastavení.

    2. Přejít na možnosti Rozšířené možnosti sítě a internetu>Wi-Fi>

    3. Poznamenejte si adresu IPv4 .

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

    5. Nastavte režim vývojáře.

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

  3. V konfiguraci ř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 znázorňující, kde vybrat x86 a vzdálený počítač

  5. Přejděte do nabídky Sestavení a kliknutím na Nasadit řešení načtěte aplikaci na HoloLens.

  6. Vaše aplikace by se teď měla zobrazit v seznamu nainstalovaných aplikací na holoLensu, připravených 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 znázorňující dokončenou aplikaci 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

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