Observação

Os tutoriais misturados do Academia de realidade foram projetados com o HoloLens (1º gen) e com o fone de cabeça de imersão de realidade misturada.The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. Como tal, achamos que é importante deixar esses tutoriais em vigor para os desenvolvedores que ainda estão procurando orientação no desenvolvimento para esses dispositivos.As such, we feel it is important to leave these tutorials in place for developers who are still looking for guidance in developing for those devices. Esses tutoriais não serão atualizados com os conjuntos de ferramentas e as interações mais recentes usados para o HoloLens 2.These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. Eles serão mantidos para continuar a trabalhar nos dispositivos com suporte.They will be maintained to continue working on the supported devices. Haverá uma nova série de tutoriais que serão publicados no futuro, que demonstrarão como desenvolver para o HoloLens 2.There will be a new series of tutorials that will be posted in the future that will demonstrate how to develop for HoloLens 2. Esse aviso será atualizado com um link para esses tutoriais quando eles forem postados.This notice will be updated with a link to those tutorials when they are posted.

Sr e Azure 311-Microsoft GraphMR and Azure 311 - Microsoft Graph

Neste curso, você aprenderá a usar o Microsoft Graph para fazer logon em seu conta Microsoft usando a autenticação segura em um aplicativo de realidade misturada.In this course, you will learn how to use Microsoft Graph to log in into your Microsoft account using secure authentication within a mixed reality application. Em seguida, você irá recuperar e exibir suas reuniões agendadas na interface do aplicativo.You will then retrieve and display your scheduled meetings in the application interface.

Microsoft Graph é um conjunto de APIs criadas para permitir o acesso a muitos dos serviços da Microsoft.Microsoft Graph is a set of APIs designed to enable access to many of Microsoft's services. A Microsoft descreve Microsoft Graph como sendo uma matriz de recursos conectados por relações, o que significa que ele permite que um aplicativo acesse todos os tipos de dados de usuário conectados.Microsoft describes Microsoft Graph as being a matrix of resources connected by relationships, meaning it allows an application to access all sorts of connected user data. Para obter mais informações, visite a página Microsoft Graph.For more information, visit the Microsoft Graph page.

O desenvolvimento incluirá a criação de um aplicativo no qual o usuário será instruído a olhar e, em seguida, tocará em uma esfera, que solicitará que o usuário faça logon com segurança em um conta Microsoft.Development will include the creation of an app where the user will be instructed to gaze at and then tap a sphere, which will prompt the user to log in safely to a Microsoft account. Depois de conectado à sua conta, o usuário poderá ver uma lista de reuniões agendadas para o dia.Once logged in to their account, the user will be able to see a list of meetings scheduled for the day.

Após a conclusão deste curso, você terá um aplicativo de HoloLens de realidade misturada, que poderá fazer o seguinte:Having completed this course, you will have a mixed reality HoloLens application, which will be able to do the following:

  1. Usando o gesto de toque, toque em um objeto, que solicitará que o usuário faça logon em uma conta da Microsoft (saindo do aplicativo para fazer logon e, em seguida, volte para o aplicativo novamente).Using the Tap gesture, tap on an object, which will prompt the user to log into a Microsoft Account (moving out of the app to log in, and then back into the app again).
  2. Exiba uma lista de reuniões agendadas para o dia.View a list of meetings scheduled for the day.

Em seu aplicativo, cabe a você como você integrará os resultados com seu design.In your application, it is up to you as to how you will integrate the results with your design. Este curso foi projetado para ensinar a você como integrar um serviço do Azure com seu projeto do Unity.This course is designed to teach you how to integrate an Azure Service with your Unity project. É seu trabalho usar o conhecimento obtido deste curso para aprimorar seu aplicativo de realidade misturada.It is your job to use the knowledge you gain from this course to enhance your mixed reality application.

Suporte a dispositivosDevice support

CourseCourse HoloLensHoloLens Headsets imersivosImmersive headsets
Sr e Azure 311: Microsoft GraphMR and Azure 311: Microsoft Graph ✔️✔️

Pré-requisitosPrerequisites

Observação

Este tutorial foi desenvolvido para desenvolvedores que têm experiência básica com o Unity C#e o.This tutorial is designed for developers who have basic experience with Unity and C#. Além disso, lembre-se de que os pré-requisitos e as instruções escritas neste documento representam o que foi testado e verificado no momento da gravação (julho de 2018).Please also be aware that the prerequisites and written instructions within this document represent what has been tested and verified at the time of writing (July 2018). Você está livre para usar o software mais recente, conforme listado no artigo instalar as ferramentas , embora não seja recomendável que as informações neste curso correspondam perfeitamente ao que você encontrará no software mais recente do que o que está listado abaixo.You are free to use the latest software, as listed within the install the tools article, though it should not be assumed that the information in this course will perfectly match what you will find in newer software than what is listed below.

Recomendamos o seguinte hardware e software para este curso:We recommend the following hardware and software for this course:

Antes de começarBefore you start

  1. Para evitar problemas de criação desse projeto, é altamente recomendável que você crie o projeto mencionado neste tutorial em uma pasta raiz ou quase raiz (caminhos de pasta longos podem causar problemas em tempo de compilação).To avoid encountering issues building this project, it is strongly suggested that you create the project mentioned in this tutorial in a root or near-root folder (long folder paths can cause issues at build-time).
  2. Configure e teste seu HoloLens.Set up and test your HoloLens. Se você precisar de suporte para configurar seu HoloLens, visite o artigo configuração do hololens.If you need support setting up your HoloLens, make sure to visit the HoloLens setup article.
  3. É uma boa ideia executar a calibragem e o ajuste do sensor ao começar a desenvolver um novo aplicativo do HoloLens (às vezes, ele pode ajudar a executar essas tarefas para cada usuário).It is a good idea to perform Calibration and Sensor Tuning when beginning developing a new HoloLens App (sometimes it can help to perform those tasks for each user).

Para obter ajuda sobre calibragem, siga este link para o artigo Calibration do HoloLens.For help on Calibration, please follow this link to the HoloLens Calibration article.

Para obter ajuda sobre o ajuste do sensor, siga este link para o artigo de ajuste do sensor do HoloLens.For help on Sensor Tuning, please follow this link to the HoloLens Sensor Tuning article.

Capítulo 1-criar seu aplicativo no portal de registro de aplicativosChapter 1 - Create your app in the Application Registration Portal

Para começar, você precisará criar e registrar seu aplicativo no portal de registro de aplicativos.To begin with, you will need to create and register your application in the Application Registration Portal.

Neste capítulo, você também encontrará a chave de serviço que permitirá fazer chamadas para Microsoft Graph acessar o conteúdo da conta.In this Chapter you will also find the Service Key that will allow you to make calls to Microsoft Graph to access your account content.

  1. Navegue até o portal de registro de aplicativos da Microsoft e faça logon com sua conta da Microsoft.Navigate to the Microsoft Application Registration Portal and login with your Microsoft Account. Depois de fazer logon, você será redirecionado para o portal de registro de aplicativo.Once you have logged in, you will be redirected to the Application Registration Portal.

  2. Na seção meus aplicativos , clique no botão Adicionar um aplicativo.In the My applications section, click on the button Add an app.

    Importante

    O portal de registro de aplicativos pode parecer diferente, dependendo se você já trabalhou com Microsoft Graph.The Application Registration Portal can look different, depending on whether you have previously worked with Microsoft Graph. As capturas de tela abaixo exibem essas versões diferentes.The below screenshots display these different versions.

  3. Adicione um nome para seu aplicativo e clique em criar.Add a name for your application and click Create.

  4. Depois que o aplicativo tiver sido criado, você será redirecionado para a página principal do aplicativo.Once the application has been created, you will be redirected to the application main page. Copie a ID do aplicativo e anote esse valor em algum lugar seguro, você o usará em breve no seu código.Copy the Application Id and make sure to note this value somewhere safe, you will use it soon in your code.

  5. Na seção plataformas , verifique se o aplicativo nativo é exibido.In the Platforms section, make sure Native Application is displayed. Se não clique em Adicionar plataforma e selecione aplicativo nativo.If not click on Add Platform and select Native Application.

  6. Role para baixo na mesma página e, na seção chamada Microsoft Graph permissões , você precisará adicionar permissões adicionais para o aplicativo.Scroll down in the same page and in the section called Microsoft Graph Permissions you will need to add additional permissions for the application. Clique em Adicionar ao lado de permissões delegadas.Click on Add next to Delegated Permissions.

  7. Como você deseja que seu aplicativo acesse o calendário do usuário, marque a caixa chamada calendários. Leia e clique em OK.Since you want your application to access the user's Calendar, check the box called Calendars.Read and click OK.

  8. Role até a parte inferior e clique no botão salvar .Scroll to the bottom and click the Save button.

  9. Seu salvamento será confirmado e você poderá fazer logoff do portal de registro de aplicativos.Your save will be confirmed, and you can log out from the Application Registration Portal.

Capítulo 2 – configurar o projeto do UnityChapter 2 - Set up the Unity project

A seguir está uma configuração típica para o desenvolvimento com realidade misturada e, como tal, é um bom modelo para outros projetos.The following is a typical set up for developing with mixed reality, and as such, is a good template for other projects.

  1. Abra o Unity e clique em novo.Open Unity and click New.

  2. Você precisa fornecer um nome de projeto de Unity.You need to provide a Unity project name. Insira MSGraphMR.Insert MSGraphMR. Verifique se o modelo de projeto está definido como 3D.Make sure the project template is set to 3D. Defina o local como algum lugar apropriado para você (Lembre-se de que, mais próximo de diretórios raiz é melhor).Set the Location to somewhere appropriate for you (remember, closer to root directories is better). Em seguida, clique em criar projeto.Then, click Create project.

  3. Com o Unity Open, vale a pena verificar se o Editor de script padrão está definido como Visual Studio.With Unity open, it is worth checking the default Script Editor is set to Visual Studio. Vá para Editar > preferências e, em seguida, na janela novo, navegue até Ferramentas externas.Go to Edit > Preferences and then from the new window, navigate to External Tools. Altere o Editor de script externo para o Visual Studio 2017.Change External Script Editor to Visual Studio 2017. Feche a janela preferências .Close the Preferences window.

  4. Vá para arquivo > configurações de compilação e selecione plataforma universal do Windows, em seguida, clique no botão alternar plataforma para aplicar sua seleção.Go to File > Build Settings and select Universal Windows Platform, then click on the Switch Platform button to apply your selection.

  5. Ainda emconfigurações de compilaçãode arquivo > , verifique se:While still in File > Build Settings, make sure that:

    1. O dispositivo de destino está definido como HoloLensTarget Device is set to HoloLens

    2. O tipo de compilação está definido como D3DBuild Type is set to D3D

    3. O SDK está definido para o mais recente instaladoSDK is set to Latest installed

    4. A versão do Visual Studio está definida para o mais recente instaladoVisual Studio Version is set to Latest installed

    5. Compilar e executar é definido como computador localBuild and Run is set to Local Machine

    6. Salve a cena e adicione-a à compilação.Save the scene and add it to the build.

      1. Faça isso selecionando Adicionar abrir cenas.Do this by selecting Add Open Scenes. Uma janela salvar será exibida.A save window will appear.

      2. Crie uma nova pasta para isso e qualquer cena futura.Create a new folder for this, and any future, scene. Selecione o botão nova pasta , para criar uma nova pasta, nomeie-a como cenas.Select the New folder button, to create a new folder, name it Scenes.

      3. Abra sua pasta de cenas recém-criada e, no campo nome do arquivo:, digite MR_ComputerVisionScenee clique em salvar.Open your newly created Scenes folder, and then in the File name: text field, type MR_ComputerVisionScene, then click Save.

        Importante

        Lembre-se de que você deve salvar as cenas do Unity na pasta ativos , pois elas devem ser associadas ao projeto do Unity.Be aware, you must save your Unity scenes within the Assets folder, as they must be associated with the Unity project. Criar a pasta de cenas (e outras pastas semelhantes) é uma maneira típica de estruturar um projeto do Unity.Creating the scenes folder (and other similar folders) is a typical way of structuring a Unity project.

    7. As configurações restantes, em configurações de compilação, devem ser deixadas como padrão por enquanto.The remaining settings, in Build Settings, should be left as default for now.

  6. Na janela configurações de compilação , clique no botão configurações do Player , isso abrirá o painel relacionado no espaço onde o Inspetor está localizado.In the Build Settings window, click on the Player Settings button, this will open the related panel in the space where the Inspector is located.

  7. Nesse painel, algumas configurações precisam ser verificadas:In this panel, a few settings need to be verified:

    1. Na guia outras configurações :In the Other Settings tab:

      1. Criando scripts A versão de tempo de execução deve ser Experimental (.NET 4,6 equivalente), o que irá disparar uma necessidade de reiniciar o editor.Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.

      2. O back-end de script deve ser .netScripting Backend should be .NET

      3. O nível de compatibilidade da API deve ser .NET 4,6API Compatibility Level should be .NET 4.6

    2. Na guia configurações de publicação , em recursos, marque:Within the Publishing Settings tab, under Capabilities, check:

      • InternetClientInternetClient

    3. Mais adiante no painel, em configurações de XR (encontradas abaixo de configurações de publicação), verifique a realidade virtual com suporte, verifique se o SDK do Windows Mixed Reality foi adicionado.Further down the panel, in XR Settings (found below Publish Settings), check Virtual Reality Supported, make sure the Windows Mixed Reality SDK is added.

  8. De volta às configurações de compilação, os projetos de C# Unity não ficam mais esmaecidos; Marque a caixa de seleção ao lado disso.Back in Build Settings, Unity C# Projects is no longer greyed out; check the checkbox next to this.

  9. Feche a janela configurações de compilação .Close the Build Settings window.

  10. Salve sua cena e seu projeto (arquivo salvar arquivos > de salvamento / > salvararquivo).Save your scene and project (FILE > SAVE SCENES / FILE > SAVE PROJECT).

Capítulo 3 – importar bibliotecas no UnityChapter 3 - Import Libraries in Unity

Importante

Se você quiser ignorar o componente de configuração do Unity deste curso e continuar diretamente no código, sinta-se à vontade para baixar este Azure-Mr-311. unitypackage, importá-lo em seu projeto como um pacote personalizadoe, em seguida, continuar no capítulo 5 .If you wish to skip the Unity Set up component of this course, and continue straight into code, feel free to download this Azure-MR-311.unitypackage, import it into your project as a Custom Package, and then continue from Chapter 5.

Para usar Microsoft Graph no Unity, você precisa fazer uso da dll Microsoft. Identity. Client .To use Microsoft Graph within Unity you need to make use of the Microsoft.Identity.Client DLL. É possível usar o SDK do Microsoft Graph, no entanto, ele exigirá a adição de um pacote NuGet depois que você criar o projeto do Unity (ou seja, editando o projeto após a compilação).It is possible to use the Microsoft Graph SDK, however, it will require the addition of a NuGet package after you build the Unity project (meaning editing the project post-build). É considerado mais simples importar as DLLs necessárias diretamente para o Unity.It is considered simpler to import the required DLLs directly into Unity.

Observação

Atualmente, há um problema conhecido no Unity que exige que os plugins sejam reconfigurados após a importação.There is currently a known issue in Unity which requires plugins to be reconfigured after import. Essas etapas (4-7 nesta seção) não serão mais necessárias depois que o bug for resolvido.These steps (4 - 7 in this section) will no longer be required after the bug has been resolved.

Para importar Microsoft Graph para seu próprio projeto, Baixe o arquivo MSGraph_LabPlugins. zip.To import Microsoft Graph into your own project, download the MSGraph_LabPlugins.zip file. Este pacote foi criado com versões das bibliotecas que foram testadas.This package has been created with versions of the libraries that have been tested.

Se você quiser saber mais sobre como adicionar DLLs personalizadas ao seu projeto do Unity, siga este link.If you wish to know more about how to add custom DLLs to your Unity project, follow this link.

Para importar o pacote:To import the package:

  1. Adicione o pacote do Unity ao Unity usando a opção de menupacote personalizado dopacote > de importação de ativos > .Add the Unity Package to Unity by using the Assets > Import Package > Custom Package menu option. Selecione o pacote que você acabou de baixar.Select the package you just downloaded.

  2. Na caixa Importar pacote de Unity que é exibida, verifique se tudo em (e incluindo) plug-ins está selecionado.In the Import Unity Package box that pops up, ensure everything under (and including) Plugins is selected.

  3. Clique no botão importar para adicionar os itens ao seu projeto.Click the Import button to add the items to your project.

  4. Vá para a pasta MSGraph em plug-ins no painel Projeto e selecione o plug-in chamado Microsoft. Identity. Client.Go to the MSGraph folder under Plugins in the Project Panel and select the plugin called Microsoft.Identity.Client.

  5. Com o plug-in selecionado, verifique se qualquer plataforma está desmarcada e, em seguida, verifique se WSAPlayer também está desmarcado e clique em aplicar.With the plugin selected, ensure that Any Platform is unchecked, then ensure that WSAPlayer is also unchecked, then click Apply. Isso é apenas para confirmar que os arquivos estão configurados corretamente.This is just to confirm that the files are configured correctly.

    Observação

    Marcar esses plug-ins os configura para ser usado apenas no editor do Unity.Marking these plugins configures them to only be used in the Unity Editor. Há um conjunto diferente de DLLs na pasta WSA que será usado depois que o projeto for exportado do Unity como um aplicativo universal do Windows.There are a different set of DLLs in the WSA folder which will be used after the project is exported from Unity as a Universal Windows Application.

  6. Em seguida, você precisa abrir a pasta WSA , dentro da pasta MSGraph .Next, you need to open the WSA folder, within the MSGraph folder. Você verá uma cópia do mesmo arquivo que acabou de configurar.You will see a copy of the same file you just configured. Selecione o arquivo e, em seguida, no Inspetor:Select the file, and then in the inspector:

    • Verifique se qualquer plataforma estádesmarcada e se somente WSAPlayer está marcado.ensure that Any Platform is unchecked, and that only WSAPlayer is checked.

    • Verifique se o SDK está definido como UWPe se o back-end de script está definido como dot netEnsure SDK is set to UWP, and Scripting Backend is set to Dot Net

    • Verifique se não processar está marcado.Ensure that Don't process is checked.

  7. Clique em Aplicar.Click Apply.

Capítulo 4 – configuração da câmeraChapter 4 - Camera Setup

Durante este capítulo, você configurará a câmera principal da sua cena:During this Chapter you will set up the Main Camera of your scene:

  1. No painel hierarquia, selecione a câmera principal.In the Hierarchy Panel, select the Main Camera.

  2. Depois de selecionado, você poderá ver todos os componentes da câmera principal no painel Inspetor .Once selected, you will be able to see all the components of the Main Camera in the Inspector panel.

    1. O objeto de câmera deve ser nomeado como a câmera principal (Observe a grafia!)The Camera object must be named Main Camera (note the spelling!)

    2. A marca da câmera principal deve ser definida como MainCamera (Observe a ortografia!)The Main Camera Tag must be set to MainCamera (note the spelling!)

    3. Verifique se a posição de transformação está definida como 0, 0, 0Make sure the Transform Position is set to 0, 0, 0

    4. Definir sinalizadores de limpeza como cor sólidaSet Clear Flags to Solid Color

    5. Defina a cor do plano de fundo do componente da câmera como preto, alfa 0 (código hex: #00000000)Set the Background Color of the Camera Component to Black, Alpha 0 (Hex Code: #00000000)

  3. A estrutura final do objeto no painel hierarquia deve ser parecida com a mostrada na imagem abaixo:The final object structure in the Hierarchy Panel should be like the one shown in the image below:

Capítulo 5-criar classe MeetingsUIChapter 5 - Create MeetingsUI class

O primeiro script que você precisa criar é MeetingsUI, que é responsável por hospedar e preencher a interface do usuário do aplicativo (mensagem de boas-vindas, instruções e os detalhes da reunião).The first script you need to create is MeetingsUI, which is responsible for hosting and populating the UI of the application (welcome message, instructions and the meetings details).

Para criar esta classe:To create this class:

  1. Clique com o botão direito do mouse na pasta ativos no painel Projetoe selecione criar > pasta.Right-click on the Assets folder in the Project Panel, then select Create > Folder. Nomeie a pasta scripts.Name the folder Scripts.

  2. Abra a pasta scripts e, nessa pasta, clique com o botão direito do mouse em criar > C# script.Open the Scripts folder then, within that folder, right-click, Create > C# Script. Nomeie o script MeetingsUI.Name the script MeetingsUI.

  3. Clique duas vezes no novo script MeetingsUI para abri-lo com o Visual Studio.Double-click on the new MeetingsUI script to open it with Visual Studio.

  4. Insira os seguintes namespaces:Insert the following namespaces:

    using System;
    using UnityEngine;
    
  5. Dentro da classe, insira as seguintes variáveis:Inside the class insert the following variables:

        /// <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. Em seguida, substitua o método Start () e adicione um método ativo () .Then replace the Start() method and add an Awake() method. Eles serão chamados quando a classe for inicializada:These will be called when the class initializes:

        /// <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. Adicione os métodos responsáveis por criar a interface do usuário de reuniões e preenchê-la com as reuniões atuais quando solicitado:Add the methods responsible for creating the Meetings UI and populate it with the current meetings when requested:

        /// <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. Exclua o método Update () e salve as alterações no Visual Studio antes de retornar ao Unity.Delete the Update() method, and save your changes in Visual Studio before returning to Unity.

Capítulo 6 – criar a classe do grafoChapter 6 - Create the Graph class

O próximo script a ser criado é o script do grafo .The next script to create is the Graph script. Esse script é responsável por fazer as chamadas autenticar o usuário e recuperar as reuniões agendadas para o dia atual do calendário do usuário.This script is responsible for making the calls to authenticate the user and retrieve the scheduled meetings for the current day from the user's calendar.

Para criar esta classe:To create this class:

  1. Clique duas vezes na pasta scripts para abri-la.Double-click on the Scripts folder, to open it.

  2. Clique com botão direito dentro de Scripts pasta, clique em Create > C# Script.Right-click inside the Scripts folder, click Create > C# Script. Nomeie o gráficode script.Name the script Graph.

  3. Clique duas vezes no script para abri-lo com o Visual Studio.Double-click on the script to open it with Visual Studio.

  4. Insira os seguintes namespaces:Insert the following namespaces:

    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
    

    Importante

    Você observará que partes do código nesse script são encapsuladas em torno de diretivas de pré-compilação, isso é para evitar problemas com as bibliotecas ao criar a solução do Visual Studio.You will notice that parts of the code in this script are wrapped around Precompile Directives, this is to avoid issues with the libraries when building the Visual Studio Solution.

  5. Exclua os métodos Start () e Update () , pois eles não serão usados.Delete the Start() and Update() methods, as they will not be used.

  6. Fora da classe do grafo , insira os seguintes objetos, que são necessários para desserializar o objeto JSON que representa as reuniões agendadas diariamente:Outside the Graph class, insert the following objects, which are necessary to deserialize the JSON object representing the daily scheduled meetings:

    /// <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. Dentro da classe do grafo , adicione as seguintes variáveis:Inside the Graph class, add the following variables:

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

    Observação

    Altere o valor AppID para que seja a ID do aplicativo que você anotou no capítulo 1, etapa 4.Change the appId value to be the App Id that you have noted in Chapter 1, step 4. Esse valor deve ser o mesmo que o exibido no portal de registro de aplicativos, na página de registro do aplicativo.This value should be the same as that displayed in the Application Registration Portal, in your application registration page.

  8. Dentro da classe do grafo , adicione os métodos SignInAsync () e AquireTokenAsync () , que solicitará que o usuário insira as credenciais de logon.Within the Graph class, add the methods SignInAsync() and AquireTokenAsync(), that will prompt the user to insert the log-in credentials.

        /// <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 successfull, 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. Adicione os dois métodos a seguir:Add the following two methods:

    1. BuildTodayCalendarEndpoint () , que compila o URI que especifica o dia e o período de tempo em que as reuniões agendadas são recuperadas.BuildTodayCalendarEndpoint(), which builds the URI specifying the day, and time span, in which the scheduled meetings are retrieved.

    2. ListMeetingsAsync () , que solicita as reuniões agendadas de Microsoft Graph.ListMeetingsAsync(), which requests the scheduled meetings from 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. Agora você concluiu o script do grafo .You have now completed the Graph script. Salve suas alterações no Visual Studio antes de retornar ao Unity.Save your changes in Visual Studio before returning to Unity.

Capítulo 7-criar o script GazeInputChapter 7 - Create the GazeInput script

Agora, você criará o GazeInput.You will now create the GazeInput. Essa classe manipula e controla o olhar do usuário, usando um Raycast proveniente da câmera principal, projetando em frente.This class handles and keeps track of the user's gaze, using a Raycast coming from the Main Camera, projecting forward.

Para criar o script:To create the script:

  1. Clique duas vezes na pasta scripts para abri-la.Double-click on the Scripts folder, to open it.

  2. Clique com botão direito dentro de Scripts pasta, clique em Create > C# Script.Right-click inside the Scripts folder, click Create > C# Script. Nomeie o script GazeInput.Name the script GazeInput.

  3. Clique duas vezes no script para abri-lo com o Visual Studio.Double-click on the script to open it with Visual Studio.

  4. Altere o código de namespaces para corresponder ao mostrado abaixo, juntamente com a adição da marca ' [System. Serializable] ' acima da classe GazeInput , para que possa ser serializada:Change the namespaces code to match the one below, along with adding the '[System.Serializable]' tag above your GazeInput class, so that it can be serialized:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Dentro da classe GazeInput , adicione as seguintes variáveis:Inside the GazeInput class, add the following variables:

        [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. Adicione o método CreateCursor () para criar o cursor do HoloLens na cena e chame o método do método Start () :Add the CreateCursor() method to create the HoloLens cursor in the scene, and call the method from the Start() method:

        /// <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. Os métodos a seguir habilitam o olhar Raycast e controlam os objetos focados.The following methods enable the gaze Raycast and keep track of the focused objects.

    /// <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. Salve suas alterações no Visual Studio antes de retornar ao Unity.Save your changes in Visual Studio before returning to Unity.

Capítulo 8-criar a classe interaçõesChapter 8 - Create the Interactions class

Agora será necessário criar o script de interações , que é responsável por:You will now need to create the Interactions script, which is responsible for:

  • Manipular a interação de toque e a câmera olhar, que permite ao usuário interagir com o logon "Button" na cena.Handling the Tap interaction and the Camera Gaze, which enables the user to interact with the log in "button" in the scene.

  • Criando o objeto "Button" de logon na cena para o usuário interagir com o.Creating the log in "button" object in the scene for the user to interact with.

Para criar o script:To create the script:

  1. Clique duas vezes na pasta scripts para abri-la.Double-click on the Scripts folder, to open it.

  2. Clique com botão direito dentro de Scripts pasta, clique em Create > C# Script.Right-click inside the Scripts folder, click Create > C# Script. Nomeie o scriptde interações.Name the script Interactions.

  3. Clique duas vezes no script para abri-lo com o Visual Studio.Double-click on the script to open it with Visual Studio.

  4. Insira os seguintes namespaces:Insert the following namespaces:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Altere a herança da classe de interação de monocomportamento para GazeInput.Change the inheritance of the Interaction class from MonoBehaviour to GazeInput.

    interações de classe pública: MonoBehaviourpublic class Interactions : MonoBehaviour

    public class Interactions : GazeInput
    
  6. Dentro da classe de interação , insira a seguinte variável:Inside the Interaction class insert the following variable:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Substituir o método Start ; Observe que é um método override, que chama o método de classe ' base ' olhar.Replace the Start method; notice it is an override method, which calls the 'base' Gaze class method. Start () será chamado quando a classe for inicializada, registrando-se para o reconhecimento de entrada e criando o botão entrar na cena:Start() will be called when the class initializes, registering for input recognition and creating the sign in button in the scene:

        /// <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. Adicione o método CreateSignInButton () , que criará uma instância do botão entrar na cena e definirá suas propriedades:Add the CreateSignInButton() method, which will instantiate the sign in button in the scene and set its properties:

        /// <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. Adicione o método GestureRecognizer_Tapped () , que será respondido para o evento Tap User.Add the GestureRecognizer_Tapped() method, which be respond for the Tap user event.

        /// <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. Exclua o método Update () e salve as alterações no Visual Studio antes de retornar ao Unity.Delete the Update() method, and then save your changes in Visual Studio before returning to Unity.

Capítulo 9-configurar as referências de scriptChapter 9 - Set up the script references

Neste capítulo, você precisa posicionar o script de interações na câmera principal.In this Chapter you need to place the Interactions script onto the Main Camera. Esse script manipulará a colocação dos outros scripts onde eles precisam ser.That script will then handle placing the other scripts where they need to be.

  • Na pasta scripts do painel Projeto, arraste as interações de script para o objeto da câmera principal , conforme mostrado abaixo.From the Scripts folder in the Project Panel, drag the script Interactions to the Main Camera object, as pictured below.

Capítulo 10-Configurando a marcaChapter 10 - Setting up the Tag

O código que manipula o olhar fará uso da marca SignInButton para identificar a qual objeto o usuário irá interagir para entrar no Microsoft Graph.The code handling the gaze will make use of the Tag SignInButton to identify which object the user will interact with to sign-in to Microsoft Graph.

Para criar a marca:To create the Tag:

  1. No editor do Unity, clique na câmera principal no painel hierarquia.In the Unity Editor click on the Main Camera in the Hierarchy Panel.

  2. No painel Inspetor , clique na marca MainCamera para abrir uma lista suspensa.In the Inspector Panel click on the MainCamera Tag to open a drop-down list. Clique em adicionar marca.. .Click on Add Tag...

  3. Clique no + botão.Click on the + button.

  4. Escreva o nome da marca como SignInButton e clique em salvar.Write the Tag name as SignInButton and click Save.

Capítulo 11-criar o projeto do Unity para UWPChapter 11 - Build the Unity project to UWP

Tudo o que é necessário para a seção do Unity deste projeto foi concluído, portanto, é hora de compilá-lo a partir do Unity.Everything needed for the Unity section of this project has now been completed, so it is time to build it from Unity.

  1. Navegue até configurações de Build (arquivo>Compilar configurações).Navigate to Build Settings (*File > *Build Settings**).

  2. Se ainda não tiver feito isso, projetos de unidade C# Tick.If not already, tick Unity C# Projects.

  3. Clique em Compilar.Click Build. O Unity iniciará uma janela Explorador de arquivos , onde você precisará criar e, em seguida, selecionar uma pasta na qual o aplicativo será compilado.Unity will launch a File Explorer window, where you need to create and then select a folder to build the app into. Crie essa pasta agora e nomeie-a como aplicativo.Create that folder now, and name it App. Em seguida, com a pasta de aplicativo selecionada, clique em Selecionar pasta.Then with the App folder selected, click Select Folder.

  4. O Unity começará a criar seu projeto na pasta do aplicativo .Unity will begin building your project to the App folder.

  5. Depois que o Unity terminar a compilação (pode levar algum tempo), ele abrirá uma janela do Explorador de arquivos no local de sua compilação (verifique sua barra de tarefas, pois ela nem sempre aparecerá acima das janelas, mas o notificará sobre a adição de uma nova janela).Once Unity has finished building (it might take some time), it will open a File Explorer window at the location of your build (check your task bar, as it may not always appear above your windows, but will notify you of the addition of a new window).

Capítulo 12 – implantar no HoloLensChapter 12 - Deploy to HoloLens

Para implantar no HoloLens:To deploy on HoloLens:

  1. Você precisará do endereço IP do seu HoloLens (para implantação remota) e para garantir que seu HoloLens esteja no modo de desenvolvedor.You will need the IP Address of your HoloLens (for Remote Deploy), and to ensure your HoloLens is in Developer Mode. Para fazer isso:To do this:

    1. Enquanto estiver desgastando seu HoloLens, abra as configurações.Whilst wearing your HoloLens, open the Settings.

    2. Vá para rede & > Opções avançadas de Internet Wi-Fi > Go to Network & Internet > Wi-Fi > Advanced Options

    3. Anote o endereço IPv4 .Note the IPv4 address.

    4. Em seguida, navegue de volta para configuraçõese, em seguida, para Atualizar & segurança > para desenvolvedoresNext, navigate back to Settings, and then to Update & Security > For Developers

    5. Defina o modo de desenvolvedor em.Set Developer Mode On.

  2. Navegue até sua nova compilação do Unity (a pasta do aplicativo ) e abra o arquivo de solução com o Visual Studio.Navigate to your new Unity build (the App folder) and open the solution file with Visual Studio.

  3. Na configuração da solução , selecione depurar.In the Solution Configuration select Debug.

  4. Na plataforma da solução, selecione x86, computador remoto.In the Solution Platform, select x86, Remote Machine. Você será solicitado a inserir o endereço IP de um dispositivo remoto (o HoloLens, neste caso, que você anotou).You will be prompted to insert the IP address of a remote device (the HoloLens, in this case, which you noted).

  5. Vá para o menu Compilar e clique em implantar solução para Sideload o aplicativo em seu HoloLens.Go to Build menu and click on Deploy Solution to sideload the application to your HoloLens.

  6. Seu aplicativo agora deve aparecer na lista de aplicativos instalados em seu HoloLens, pronto para ser iniciado!Your app should now appear in the list of installed apps on your HoloLens, ready to be launched!

Seu aplicativo Microsoft Graph HoloLensYour Microsoft Graph HoloLens application

Parabéns, você criou um aplicativo de realidade misturada que aproveita o Microsoft Graph, para ler e exibir dados de calendário do usuário.Congratulations, you built a mixed reality app that leverages the Microsoft Graph, to read and display user Calendar data.

Exercícios de bônusBonus exercises

Exercício 1Exercise 1

Use Microsoft Graph para exibir outras informações sobre o usuárioUse Microsoft Graph to display other information about the user

  • Email do usuário/número do telefone/imagem do perfilUser email / phone number / profile picture

Exercício 1Exercise 1

Implemente o controle de voz para navegar na interface do usuário do Microsoft Graph.Implement voice control to navigate the Microsoft Graph UI.