HoloLens (1ère génération) et Azure 311 - Microsoft Graph

Notes

Les tutoriels Mixed Reality Academy ont été conçus pour les appareils HoloLens (1re génération) et les casques immersifs de réalité mixte. Nous estimons qu’il est important de laisser ces tutoriels à la disposition des développeurs qui recherchent encore des conseils pour développer des applications sur ces appareils. Notez que ces tutoriels ne sont pas mis à jour avec les derniers ensembles d’outils ou interactions utilisés pour HoloLens 2. Ils sont fournis dans le but de fonctionner sur les appareils pris en charge. Il y aura une nouvelle série de tutoriels qui seront publiés à l’avenir qui démontreront comment développer pour HoloLens 2. Cet avis sera mis à jour avec un lien vers ces tutoriels lorsqu’ils sont publiés.

Dans ce cours, vous allez apprendre à utiliser Microsoft Graph pour vous connecter à votre compte Microsoft à l’aide de l’authentification sécurisée dans une application de réalité mixte. Vous allez ensuite récupérer et afficher vos réunions planifiées dans l’interface de l’application.

Screenshot that shows the scheduled meetings in the application interface.

Microsoft Graph est un ensemble d’API conçues pour permettre l’accès à de nombreux services Microsoft. Microsoft décrit Microsoft Graph comme étant une matrice de ressources connectées par des relations, ce qui signifie qu’une application permet à une application d’accéder à toutes sortes de données utilisateur connectées. Pour plus d’informations, consultez la page Microsoft Graph.

Le développement inclut la création d’une application dans laquelle l’utilisateur sera invité à regarder, puis appuyez sur une sphère, ce qui invite l’utilisateur à se connecter en toute sécurité à un compte Microsoft. Une fois connecté à son compte, l’utilisateur peut voir la liste des réunions planifiées pour la journée.

Après avoir terminé ce cours, vous aurez une application de réalité mixte HoloLens, qui sera en mesure d’effectuer les opérations suivantes :

  1. À l’aide du mouvement Tap, appuyez sur un objet, ce qui invite l’utilisateur à se connecter à un compte Microsoft (en sortant de l’application pour se connecter, puis à nouveau dans l’application).
  2. Affichez la liste des réunions planifiées pour la journée.

Dans votre application, il vous suffit de savoir comment intégrer les résultats à votre conception. Ce cours est conçu pour vous apprendre à intégrer un service Azure à votre projet Unity. Il s’agit de votre travail d’utiliser les connaissances que vous obtenez de ce cours pour améliorer votre application de réalité mixte.

Prise en charge des appareils

Cours HoloLens Casques immersifs
Réalité mixte - Azure - Cours 311 : Microsoft Graph ✔️

Prérequis

Notes

Ce didacticiel est conçu pour les développeurs qui ont une expérience de base avec Unity et C#. Sachez également que les prérequis et les instructions écrites de ce document représentent ce qui a été testé et vérifié au moment de l’écriture (juillet 2018). Vous êtes libre d’utiliser le logiciel le plus récent, comme indiqué dans l’article sur l’installation des outils , mais il ne doit pas être supposé que les informations de ce cours correspondent parfaitement à ce que vous trouverez dans un logiciel plus récent que ce qui est répertorié ci-dessous.

Nous vous recommandons le matériel et le logiciel suivants pour ce cours :

Avant de commencer

  1. Pour éviter de rencontrer des problèmes de création de ce projet, il est fortement suggéré de créer le projet mentionné dans ce didacticiel dans un dossier racine ou proche (des chemins d’accès de dossier longs peuvent provoquer des problèmes au moment de la build).
  2. Configurez et testez votre HoloLens. Si vous avez besoin de support pour configurer votre HoloLens, veillez à consulter l’article de configuration HoloLens.
  3. Il est judicieux d’effectuer le réglage de l’étalonnage et du capteur lors du développement d’une nouvelle application HoloLens (parfois, il peut aider à effectuer ces tâches pour chaque utilisateur).

Pour obtenir de l’aide sur l’étalonnage, suivez ce lien vers l’article HoloLens Étalonnage.

Pour obtenir de l’aide sur le réglage du capteur, suivez ce lien vers l’article HoloLens Paramétrage du capteur.

Chapitre 1 : Créer votre application dans le portail d’inscription d’application

Pour commencer, vous devez créer et inscrire votre application dans le portail d’inscription d’application.

Dans ce chapitre, vous trouverez également la clé de service qui vous permettra d’effectuer des appels à Microsoft Graph pour accéder au contenu de votre compte.

  1. Accédez au portail d’inscription des applications Microsoft et connectez-vous avec votre compte Microsoft. Une fois connecté, vous êtes redirigé vers le portail d’inscription d’application.

  2. Dans la section Mes applications , cliquez sur le bouton Ajouter une application.

    Screenshot that shows where to select Add an app.

    Important

    Le portail d’inscription d’application peut ressembler à différent, selon que vous avez déjà travaillé avec Microsoft Graph. Les captures d’écran ci-dessous affichent ces différentes versions.

  3. Ajoutez un nom pour votre application, puis cliquez sur Créer.

    Screenshot that shows where to add a name for your application.

  4. Une fois l’application créée, vous êtes redirigé vers la page principale de l’application. Copiez l’ID d’application et veillez à noter cette valeur quelque part en toute sécurité, vous l’utiliserez bientôt dans votre code.

    Screenshot that shows where to view the Application Id.

  5. Dans la section Plateformes , vérifiez que l’application native s’affiche. Si vous ne cliquez pas sur Ajouter une plateforme et sélectionnez Application native.

    Screenshot that highlights the Native Application section.

  6. Faites défiler vers le bas dans la même page et dans la section appelée Microsoft Graph Autorisations, vous devez ajouter des autorisations supplémentaires pour l’application. Cliquez sur Ajouter en regard des autorisations déléguées.

    Screenshot that shows where to select Add next to Delegated Permissions.

  7. Étant donné que vous souhaitez que votre application accède au calendrier de l’utilisateur, cochez la case appelée Calendars.Read et cliquez sur OK.

    Screenshot that shows the Calendars.Read checkbox.

  8. Faites défiler vers le bas, puis cliquez sur le bouton Enregistrer .

    Screenshot that shows where to select Save.

  9. Votre enregistrement sera confirmé et vous pouvez vous déconnecter du portail d’inscription d’application.

Chapitre 2 - Configurer le projet Unity

Voici une configuration classique pour le développement avec la réalité mixte, et par conséquent, est un bon modèle pour d’autres projets.

  1. Ouvrez Unity , puis cliquez sur Nouveau.

    Screenshot that shows the Unity interface.

  2. Vous devez fournir un nom de projet Unity. Insérez MSGraphMR. Vérifiez que le modèle de projet est défini sur 3D. Définissez l’emplacement sur un emplacement approprié pour vous (n’oubliez pas que les répertoires racines sont meilleurs). Ensuite, cliquez sur Créer un projet.

    Screenshot that shows where to select Create Project.

  3. Avec Unity ouvert, il vaut la peine de vérifier que l’éditeur de script par défaut est défini sur Visual Studio. Accédez à EditPreferences>, puis à partir de la nouvelle fenêtre, accédez aux outils externes. Modifiez l’éditeur de script externeen Visual Studio 2017. Fermez la fenêtre Préférences .

    Screenshot that shows where to set the External Script Editor to Visual Studio 2017.

  4. Accédez à FileBuild>Paramètres et sélectionnez plateforme Windows universelle, puis cliquez sur le bouton Basculer la plateforme pour appliquer votre sélection.

    Screenshot that shows where to select Switch Platform.

  5. Bien que toujours dans FileBuild>Paramètres, assurez-vous que :

    1. L’appareil cible est défini sur HoloLens

    2. Le type de build est défini sur D3D

    3. Le Kit de développement logiciel (SDK) est défini sur La dernière version installée

    4. Visual Studio Version est définie sur La dernière version installée

    5. La génération et l’exécution sont définies sur Ordinateur local

    6. Enregistrez la scène et ajoutez-la à la build.

      1. Pour ce faire, sélectionnez Ajouter des scènes ouvertes. Une fenêtre d’enregistrement s’affiche.

        Screenshot that shows where to select Add Open Scenes.

      2. Créez un dossier pour cela, ainsi que toute scène future. Sélectionnez le bouton Nouveau dossier pour créer un dossier, nommez-le Scenes.

        Screenshot that shows where to name the new folder.

      3. Ouvrez votre dossier Scenes nouvellement créé, puis, dans le champ Fichier : champ de texte, tapez MR_ComputerVisionScene, puis cliquez sur Enregistrer.

        Screenshot that shows where to type the file name.

        Important

        Sachez que vous devez enregistrer vos scènes Unity dans le dossier Ressources , car elles doivent être associées au projet Unity. La création du dossier de scènes (et d’autres dossiers similaires) est un moyen classique de structurer un projet Unity.

    7. Les autres paramètres, dans Build Paramètres, doivent être conservés comme paramètres par défaut pour l’instant.

  6. Dans la fenêtre Build Paramètres, cliquez sur le bouton Player Paramètres, ce qui ouvre le panneau associé dans l’espace où se trouve l’Inspecteur.

    Screenshot that shows the Player Settings dialog box.

  7. Dans ce panneau, quelques paramètres doivent être vérifiés :

    1. Sous l’onglet Autres Paramètres :

      1. La version scriptingRuntime doit être expérimentale (équivalent .NET 4.6), ce qui déclenche un redémarrage de l’éditeur.

      2. Le serveur principal de script doit être .NET

      3. Le niveau de compatibilité des API doit être .NET 4.6

        Screenshot that shows where to check the API compatibility level.

    2. Sous l’onglet Publication Paramètres, sous Fonctionnalités, vérifiez :

      • InternetClient

        Screenshot that shows where to select the InternetClient option.

    3. Plus loin dans le panneau, dans XR Paramètres (trouvé ci-dessous Publier Paramètres), vérifiez Virtual Reality Supported, assurez-vous que le kit de développement logiciel (SDK) Windows Mixed Reality est ajouté.

      Screenshot that shows where to add Windows Mixed Reality SDK.

  8. De retour dans Build Paramètres, Unity C# Projects n’est plus grisé ; cochez la case en regard de cela.

  9. Fermez la fenêtre Build Settings.

  10. Enregistrez votre scène et votre projet (FILESAVE>SCENES /FILESAVE> PROJECT).

Chapitre 3 - Importer des bibliothèques dans Unity

Important

Si vous souhaitez ignorer le composant De configuration Unity de ce cours et continuer directement dans le code, n’hésitez pas à télécharger ce package Azure-MR-311.unity, à l’importer dans votre projet en tant que package personnalisé, puis à partir du chapitre 5.

Pour utiliser Microsoft Graph dans Unity, vous devez utiliser la DLL Microsoft.Identity.Client. Toutefois, il est possible d’utiliser le Kit de développement logiciel (SDK) Microsoft Graph, il nécessite l’ajout d’un package NuGet une fois que vous avez généré le projet Unity (ce qui signifie que vous modifiez le projet après la génération). Il est considéré comme plus simple d’importer les DLL requises directement dans Unity.

Notes

Il existe actuellement un problème connu dans Unity qui nécessite la reconfiguration des plug-ins après l’importation. Ces étapes (4 à 7 dans cette section) ne seront plus nécessaires une fois le bogue résolu.

Pour importer Microsoft Graph dans votre propre projet, téléchargez le fichier MSGraph_LabPlugins.zip. Ce package a été créé avec des versions des bibliothèques qui ont été testées.

Si vous souhaitez en savoir plus sur l’ajout de DLL personnalisées à votre projet Unity, suivez ce lien.

Pour importer le package :

  1. Ajoutez le package Unity à Unity à l’aide de l’option de menu Package AssetsImport>PackageCustom>. Sélectionnez le package que vous venez de télécharger.

  2. Dans la zone Importer un package Unity qui s’affiche, vérifiez que tous les plug-ins sous (et y compris) sont sélectionnés.

    Screenshot that shows the selected configuration parameters under Plugins.

  3. Cliquez sur le bouton Importer pour ajouter les éléments à votre projet.

  4. Accédez au dossier MSGraph sous Plug-ins dans le panneau Project et sélectionnez le plug-in appelé Microsoft.Identity.Client.

    Screenshot that shows the Microsoft.Identity.Client plugin.

  5. Une fois le plug-in sélectionné, vérifiez que n’importe quelle plateforme est décochée, vérifiez que WSAPlayer est également désactivé, puis cliquez sur Appliquer. Il s’agit simplement de confirmer que les fichiers sont correctement configurés.

    Screenshot that shows where to confirm that Any Platform and WSAPlayer aren't checked.

    Notes

    Le marquage de ces plug-ins les configure pour qu’ils soient utilisés uniquement dans l’éditeur Unity. Il existe un autre ensemble de DLL dans le dossier WSA qui sera utilisé après l’exportation du projet à partir d’Unity en tant qu’application de Windows universelle.

  6. Ensuite, vous devez ouvrir le dossier WSA dans le dossier MSGraph . Vous verrez une copie du même fichier que celui que vous venez de configurer. Sélectionnez le fichier, puis dans l’inspecteur :

    • vérifiez que n’importe quelle plateforme n’est pas cochée et que seulWSAPlayer est activé.

    • Vérifiez que le SDK est défini sur UWP et que le serveur principal de script est défini sur Dot Net

    • Vérifiez que Don’t process is checked.

      Screenshot that shows that Don't Process is selected.

  7. Cliquez sur Appliquer.

Chapitre 4 - Configuration de l’appareil photo

Au cours de ce chapitre, vous allez configurer la caméra principale de votre scène :

  1. Dans le panneau Hiérarchie, sélectionnez l’appareil photo principal.

  2. Une fois sélectionné, vous pourrez voir tous les composants de l’appareil photo principal dans le panneau Inspecteur .

    1. L’objet Camera doit être nommé Main Camera (notez l’orthographe !)

    2. La balise Main Camera doit être définie sur MainCamera (notez l’orthographe !)

    3. Vérifiez que la position de transformation est définie sur 0, 0, 0

    4. Définir des indicateurs clairs sur couleur unie

    5. Définir la couleur d’arrière-plan du composant caméra sur Noir, Alpha 0(Code hexadécimal : #00000000)

      Screenshot that highlights where to set the background color.

  3. La structure d’objet finale dans le panneau Hierarchy doit être semblable à celle présentée dans l’image ci-dessous :

    Screenshot that shows the final object structure in the Hierarchy Panel.

Chapitre 5 - Créer une classe MeetingsUI

Le premier script que vous devez créer est MeetingsUI, qui est responsable de l’hébergement et du remplissage de l’interface utilisateur de l’application (message d’accueil, instructions et détails des réunions).

Pour créer cette classe :

  1. Cliquez avec le bouton droit sur le dossier Ressources dans le volet Project, puis sélectionnez CreateFolder>. Nommez le dossier Scripts.

    Screenshot that shows where to find the Assets folder.Screenshot that shows where to create the Scripts folder.

  2. Ouvrez le dossier Scripts , puis, dans ce dossier, cliquez avec le bouton droit sur CreateC># Script. Nommez le script MeetingsUI.

    Screenshot that shows where to create the MeetingsUI folder.

  3. Double-cliquez sur le nouveau script MeetingsUI pour l’ouvrir avec Visual Studio.

  4. Insérez les espaces de noms suivants :

    using System;
    using UnityEngine;
    
  5. Dans la classe, insérez les variables suivantes :

        /// <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. Remplacez ensuite la méthode Start() et ajoutez une méthode Awake(). Celles-ci sont appelées lorsque la classe initialise :

        /// <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. Ajoutez les méthodes responsables de la création de l’interface utilisateur de réunions et remplissez-la avec les réunions en cours lorsque cela est demandé :

        /// <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. Supprimez la méthode Update() et enregistrez vos modifications dans Visual Studio avant de revenir à Unity.

Chapitre 6 - Créer la classe Graph

Le script suivant à créer est le script Graph. Ce script est chargé d’effectuer les appels pour authentifier l’utilisateur et de récupérer les réunions planifiées pour le jour actuel à partir du calendrier de l’utilisateur.

Pour créer cette classe :

  1. Double-cliquez sur le dossier Scripts pour l’ouvrir.

  2. Cliquez avec le bouton droit dans le dossier Scripts , puis cliquez sur CreateC># Script. Nommez le script Graph.

  3. Double-cliquez sur le script pour l’ouvrir avec Visual Studio.

  4. Insérez les espaces de noms suivants :

    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
    

    Important

    Vous remarquerez que les parties du code de ce script sont encapsulées autour des directives de précompile, c’est pour éviter les problèmes avec les bibliothèques lors de la génération de la solution Visual Studio.

  5. Supprimez les méthodes Start() et Update(), car elles ne seront pas utilisées.

  6. En dehors de la classe Graph, insérez les objets suivants, qui sont nécessaires pour désérialiser l’objet JSON représentant les réunions planifiées quotidiennes :

    /// <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. Dans la classe Graph, ajoutez les variables suivantes :

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

    Notes

    Remplacez la valeur appId par l’ID d’application que vous avez noté dans le chapitre 1, étape 4. Cette valeur doit être identique à celle affichée dans le portail d’inscription d’application, dans la page d’inscription de votre application.

  8. Dans la classe Graph, ajoutez les méthodes SignInAsync() et AquireTokenAsync(), qui inviteront l’utilisateur à insérer les informations d’identification de connexion.

        /// <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. Ajoutez les deux méthodes suivantes :

    1. BuildTodayCalendarEndpoint(), qui génère l’URI spécifiant le jour et l’intervalle de temps, dans lequel les réunions planifiées sont récupérées.

    2. ListMeetingsAsync(), qui demande les réunions planifiées de 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. Vous avez maintenant terminé le script Graph. Enregistrez vos modifications dans Visual Studio avant de revenir à Unity.

Chapitre 7 - Créer le script GazeInput

Vous allez maintenant créer le GazeInput. Cette classe gère et assure le suivi du regard de l’utilisateur, à l’aide d’un Raycast provenant de l’appareil photo principal, projetant vers l’avant.

Pour créer le script :

  1. Double-cliquez sur le dossier Scripts pour l’ouvrir.

  2. Cliquez avec le bouton droit dans le dossier Scripts , puis cliquez sur CreateC># Script. Nommez le script GazeInput.

  3. Double-cliquez sur le script pour l’ouvrir avec Visual Studio.

  4. Modifiez le code des espaces de noms pour qu’il corresponde à celui ci-dessous, ainsi que l’ajout de la balise « [System.Serializable] » au-dessus de votre classe GazeInput , afin qu’elle puisse être sérialisée :

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Dans la classe GazeInput , ajoutez les variables suivantes :

        [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. Ajoutez la méthode CreateCursor() pour créer le curseur HoloLens dans la scène et appelez la méthode à partir de la méthode 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. Les méthodes suivantes permettent le regard Raycast et de suivre les objets ciblés.

    /// <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. Enregistrez vos modifications dans Visual Studio avant de revenir à Unity.

Chapitre 8 - Créer la classe Interactions

Vous devez maintenant créer le script Interactions , qui est responsable des éléments suivants :

  • Gestion de l’interaction tap et du regard de la caméra, ce qui permet à l’utilisateur d’interagir avec le journal « bouton » dans la scène.

  • Création de l’objet « button » dans la scène pour permettre à l’utilisateur d’interagir.

Pour créer le script :

  1. Double-cliquez sur le dossier Scripts pour l’ouvrir.

  2. Cliquez avec le bouton droit dans le dossier Scripts , puis cliquez sur CreateC># Script. Nommez les interactions de script.

  3. Double-cliquez sur le script pour l’ouvrir avec Visual Studio.

  4. Insérez les espaces de noms suivants :

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Remplacez l’héritage de la classe Interaction de MonoBehaviour par GazeInput.

    interactions de classe publique : MonoBehaviour

    public class Interactions : GazeInput
    
  6. Dans la classe Interaction , insérez la variable suivante :

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Remplacez la méthode Start ; notez qu’il s’agit d’une méthode de remplacement, qui appelle la méthode de classe De regard « base ». Start() est appelé lorsque la classe initialise, s’inscrit pour la reconnaissance d’entrée et crée le bouton de connexion dans la 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. Ajoutez la méthode CreateSignInButton(), qui instancie le bouton de connexion dans la scène et définit ses propriétés :

        /// <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. Ajoutez la méthode GestureRecognizer_Tapped(), qui doit répondre à l’événement utilisateur 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. Supprimez la méthode Update(), puis enregistrez vos modifications dans Visual Studio avant de revenir à Unity.

Chapitre 9 - Configurer les références de script

Dans ce chapitre, vous devez placer le script Interactions sur la caméra principale. Ce script gère ensuite le placement des autres scripts là où ils doivent être.

  • Dans le dossier Scripts du panneau Project, faites glisser les interactions de script vers l’objet Appareil photo principal, comme illustré ci-dessous.

    Screenshot that shows where to drag the Interactions script.

Chapitre 10 - Configuration de la balise

Le code qui gère le regard utilise la balise SignInButton pour identifier l’objet avec lequel l’utilisateur interagit avec la connexion à Microsoft Graph.

Pour créer la balise :

  1. Dans l’Éditeur Unity, cliquez sur l’appareil photo principal dans le panneau Hiérarchie.

  2. Dans le panneau d’inspecteur, cliquez sur MainCameraTag pour ouvrir une liste déroulante. Cliquez sur Ajouter une balise...

    Screenshot that highlights the Add Tag... option.

  3. Cliquez sur le bouton +.

    Screenshot that shows the + button.

  4. Écrivez le nom de la balise en tant que SignInButton , puis cliquez sur Enregistrer.

    Screenshot that shows where to add the SignInButton tag name.

Chapitre 11 - Créer le projet Unity sur UWP

Tout ce qui est nécessaire pour la section Unity de ce projet a été terminé. Il est donc temps de le générer à partir d’Unity.

  1. Accédez à Build Paramètres (FileBuild>Paramètres).

    Screenshot that shows the Build Settings dialog box.

  2. Si ce n’est pas déjà fait, cochez les projets C# Unity.

  3. Cliquez sur Générer. Unity lance une fenêtre Explorateur de fichiers, dans laquelle vous devez créer, puis sélectionner un dossier dans lequel générer l’application. Créez ce dossier maintenant et nommez-le App. Ensuite, avec le dossier d’application sélectionné, cliquez sur Sélectionner un dossier.

  4. Unity commence à générer votre projet dans le dossier De l’application .

  5. Une fois que Unity a terminé la génération (cela peut prendre un certain temps), il ouvre une fenêtre Explorateur de fichiers à l’emplacement de votre build (vérifiez votre barre des tâches, car il peut ne pas toujours apparaître au-dessus de vos fenêtres, mais vous informera de l’ajout d’une nouvelle fenêtre).

Chapitre 12 - Déployer sur HoloLens

Pour effectuer un déploiement sur HoloLens :

  1. Vous aurez besoin de l’adresse IP de votre HoloLens (pour le déploiement à distance) et de vous assurer que votre HoloLens est en mode développeur. Pour ce faire :

    1. Tout en portant votre HoloLens, ouvrez le Paramètres.

    2. Accéder aux options Réseau &InternetWi-FiAdvanced>>

    3. Notez l’adresse IPv4 .

    4. Ensuite, revenez à Paramètres, puis à Update & SecurityFor>Developers

    5. Définissez le mode développeur activé.

  2. Accédez à votre nouvelle build Unity (dossier d’application) et ouvrez le fichier solution avec Visual Studio.

  3. Dans la configuration de la solution , sélectionnez Déboguer.

  4. Dans la plateforme de solution, sélectionnez x86, Ordinateur distant. Vous serez invité à insérer l’adresse IP d’un appareil distant (le HoloLens, dans ce cas, que vous avez noté).

    Screenshot that shows where to select x86 and Remote Machine.

  5. Accédez au menu Générer, puis cliquez sur Déployer la solution pour charger une version test de l’application sur votre HoloLens.

  6. Votre application doit maintenant apparaître dans la liste des applications installées sur votre HoloLens, prêtes à être lancées !

Votre application Microsoft Graph HoloLens

Félicitations, vous avez créé une application de réalité mixte qui tire parti de Microsoft Graph, pour lire et afficher les données de calendrier utilisateur.

Screenshot that shows the completed mixed reality app.

Exercices bonus

Exercice 1

Utiliser Microsoft Graph pour afficher d’autres informations sur l’utilisateur

  • Adresse e-mail/ numéro de téléphone de l’utilisateur / image de profil

Exercice 1

Implémentez le contrôle vocal pour naviguer dans l’interface utilisateur de Microsoft Graph.