HoloLens (1ª geração) e Azure 311 – Microsoft Graph

Observação

Os tutoriais do Mixed Reality Academy foram projetados com o HoloLens (1ª geração) e os headsets imersivos de realidade misturada em mente. Dessa forma, achamos que é importante continuar disponibilizando esses tutoriais para os desenvolvedores que ainda buscam obter diretrizes para o desenvolvimento visando esses dispositivos. Esses tutoriais não serão atualizados com os conjuntos de ferramentas mais recentes nem com as interações usadas para o HoloLens 2. Eles serão mantidos para continuar funcionando nos dispositivos compatíveis. Haverá uma nova série de tutoriais que serão postados no futuro que demonstrarão como desenvolver para HoloLens 2. Este aviso será atualizado com um link para esses tutoriais quando eles forem postados.

Neste curso, você aprenderá a usar o Microsoft Graph para fazer logon em sua conta Microsoft usando a autenticação segura em um aplicativo de realidade misturada. Em seguida, você recuperará e exibirá suas reuniões agendadas na interface do aplicativo.

Captura de tela que mostra as reuniões agendadas na interface do aplicativo.

O Microsoft Graph é um conjunto de APIs projetado para habilitar o acesso a muitos dos serviços da Microsoft. A Microsoft descreve o Microsoft Graph como sendo uma matriz de recursos conectados por relações, o que significa que permite que um aplicativo acesse todos os tipos de dados de usuário conectados. Para obter mais informações, visite a página do Microsoft Graph.

O desenvolvimento incluirá a criação de um aplicativo em que o usuário será instruído a olhar e, em seguida, tocar em uma esfera, o que solicitará que o usuário faça logon com segurança em uma conta Microsoft. Depois de fazer logon em sua conta, o usuário poderá ver uma lista de reuniões agendadas para o dia.

Depois de concluir este curso, você terá um aplicativo HoloLens de realidade misturada, que poderá fazer o seguinte:

  1. Usando o gesto Tocar, toque em um objeto , o que solicitará que o usuário faça logon em uma Conta Microsoft (saindo do aplicativo para fazer logon e, em seguida, volte para o aplicativo novamente).
  2. Exibir uma lista de reuniões agendadas para o dia.

Em seu aplicativo, cabe a você saber como você integrará os resultados ao seu design. Este curso foi projetado para ensinar você a integrar um Serviço do Azure ao seu projeto do Unity. É seu trabalho usar o conhecimento obtido com este curso para aprimorar seu aplicativo de realidade misturada.

Suporte a dispositivos

Curso HoloLens Headsets imersivos
MR e Azure 311: Microsoft Graph ✔️

Pré-requisitos

Observação

Este tutorial foi projetado para desenvolvedores que têm experiência básica com Unity e C#. Lembre-se também 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). Você é livre para usar o software mais recente, conforme listado no artigo instalar as ferramentas , embora não se presuma que as informações neste curso corresponderão perfeitamente ao que você encontrará no software mais recente do que o listado abaixo.

Recomendamos o seguinte hardware e software para este curso:

Antes de começar

  1. Para evitar problemas ao criar esse projeto, é altamente sugerido que você crie o projeto mencionado neste tutorial em uma pasta raiz ou quase raiz (caminhos de pasta longa podem causar problemas no tempo de build).
  2. Configure e teste o HoloLens. Se você precisar de suporte para configurar o HoloLens, visite o artigo configuração do HoloLens.
  3. É uma boa ideia executar a Calibragem e o Ajuste do Sensor ao começar a desenvolver um novo Aplicativo HoloLens (às vezes, pode ajudar a executar essas tarefas para cada usuário).

Para obter ajuda sobre a Calibragem, siga este link para o artigo Calibração do HoloLens.

Para obter ajuda sobre o Ajuste do Sensor, siga este link para o artigo Ajuste do Sensor do HoloLens.

Capítulo 1 – Criar seu aplicativo no Portal de Registro de Aplicativo

Para começar, você precisará criar e registrar seu aplicativo no Portal de Registro de Aplicativo.

Neste Capítulo, você também encontrará a Chave de Serviço que permitirá que você faça chamadas ao Microsoft Graph para acessar o conteúdo da sua conta.

  1. Navegue até o Portal de Registro de Aplicativos da Microsoft e faça logon com sua Conta Microsoft. Depois de fazer logon, você será redirecionado para o Portal de Registro de Aplicativo.

  2. Na seção Meus aplicativos , clique no botão Adicionar um aplicativo.

    Captura de tela que mostra onde selecionar Adicionar um aplicativo.

    Importante

    O Portal de Registro de Aplicativo pode parecer diferente, dependendo se você já trabalhou com o Microsoft Graph. As capturas de tela abaixo exibem essas versões diferentes.

  3. Adicione um nome para seu aplicativo e clique em Criar.

    Captura de tela que mostra onde adicionar um nome para seu aplicativo.

  4. Depois que o aplicativo for criado, você será redirecionado para o aplicativo main página. Copie a ID do Aplicativo e certifique-se de observar esse valor em algum lugar seguro, você o usará em breve em seu código.

    Captura de tela que mostra onde exibir a ID do Aplicativo.

  5. Na seção Plataformas , verifique se o Aplicativo Nativo está exibido. Se não clicar em Adicionar Plataforma e selecionar Aplicativo Nativo.

    Captura de tela que realça a seção Aplicativo Nativo.

  6. Role para baixo na mesma página e, na seção chamada Permissões do Microsoft Graph , você precisará adicionar permissões adicionais para o aplicativo. Clique em Adicionar ao lado de Permissões Delegadas.

    Captura de tela que mostra onde selecionar Adicionar ao lado de Permissões Delegadas.

  7. Como você deseja que seu aplicativo acesse o Calendário do usuário, marcar a caixa chamada Calendars.Read e clique em OK.

    Captura de tela que mostra a caixa de seleção Calendários.Leitura.

  8. Role até a parte inferior e clique no botão Salvar .

    Captura de tela que mostra onde selecionar Salvar.

  9. Seu salvamento será confirmado e você poderá fazer logoff no Portal de Registro de Aplicativo.

Capítulo 2 – Configurar o projeto do Unity

Veja a seguir uma configuração típica para o desenvolvimento com realidade misturada e, como tal, é um bom modelo para outros projetos.

  1. Abra o Unity e clique em Novo.

    Captura de tela que mostra a interface do Unity.

  2. Você precisa fornecer um nome de projeto do Unity. Insira MSGraphMR. Verifique se o modelo de projeto está definido como 3D. Defina o Local como um lugar apropriado para você (lembre-se, mais próximo dos diretórios raiz é melhor). Em seguida, clique em Criar projeto.

    Captura de tela que mostra onde selecionar Criar Projeto.

  3. Com o Unity aberto, vale a pena verificar se o Editor de Scripts padrão está definido como Visual Studio. Vá para Editar>Preferências e, em seguida, na nova janela, navegue até Ferramentas Externas. Altere o Editor de Script Externo para o Visual Studio 2017. Feche a janela Preferências.

    Captura de tela que mostra onde definir o Editor de Script Externo para o Visual Studio 2017.

  4. Vá paraConfigurações de Build de Arquivo> e selecione Plataforma Universal do Windows e clique no botão Alternar Plataforma para aplicar sua seleção.

    Captura de tela que mostra onde selecionar Alternar Plataforma.

  5. Enquanto ainda estiver emConfigurações de Build de Arquivo>, verifique se:

    1. O dispositivo de destino está definido como HoloLens

    2. O Tipo de Build é definido como D3D

    3. O SDK está definido como Mais recente instalado

    4. A versão do Visual Studio está definida como Mais Recente instalada

    5. Compilar e Executar é definido como Computador Local

    6. Salve a cena e adicione-a ao build.

      1. Faça isso selecionando Adicionar Cenas Abertas. Uma janela de salvamento será exibida.

        Captura de tela que mostra onde selecionar Adicionar Cenas Abertas.

      2. Crie uma nova pasta para essa e qualquer cena futura. Selecione o botão Nova pasta para criar uma nova pasta, nomeie-a cenas.

        Captura de tela que mostra onde nomear a nova pasta.

      3. Abra a pasta Cenas recém-criada e, em seguida, no campo Nome do arquivo: texto, digite MR_ComputerVisionScene e clique em Salvar.

        Captura de tela que mostra onde digitar o nome do arquivo.

        Importante

        Lembre-se de que você deve salvar suas cenas do Unity na pasta Ativos, pois elas devem ser associadas ao projeto do Unity. Criar a pasta scenes (e outras pastas semelhantes) é uma maneira típica de estruturar um projeto do Unity.

    7. As configurações restantes, em Configurações de Build, devem ser deixadas como padrão por enquanto.

  6. Na janela Configurações de Build, clique no botão Configurações do Player , isso abrirá o painel relacionado no espaço em que o Inspetor está localizado.

    Captura de tela que mostra a caixa de diálogo Configurações do Player.

  7. Neste painel, algumas configurações precisam ser verificadas:

    1. Na guia Outras Configurações :

      1. Aversão de runtime de script deve ser experimental (equivalente ao .NET 4.6), o que disparará a necessidade de reiniciar o Editor.

      2. O back-end de script deve ser .NET

      3. O Nível de Compatibilidade da API deve ser .NET 4.6

        Captura de tela que mostra onde marcar o nível de compatibilidade da API.

    2. Na guia Configurações de Publicação, em Recursos, marcar:

      • InternetClient

        Captura de tela que mostra onde selecionar a opção InternetClient.

    3. Mais abaixo no painel, em Configurações de XR (encontradas abaixo de Configurações de Publicação), marcar Com suporte para Realidade Virtual, verifique se o SDK do Windows Mixed Reality foi adicionado.

      Captura de tela que mostra onde adicionar Windows Mixed Reality SDK.

  8. De volta às Configurações de Build, os Projetos C# do Unity não estão mais esmaecidos; marcar a caixa de seleção ao lado disso.

  9. Feche a janela Configurações de Build.

  10. Salve a cena e o projeto (FILE>SAVE SCENES/FILE>SAVE PROJECT).

Capítulo 3 – Importar bibliotecas no Unity

Importante

Se você quiser ignorar o componente Configurar do Unity deste curso e continuar diretamente no código, fique à vontade para baixar este pacote do Azure-MR-311.unity, importá-lo para seu projeto como um Pacote Personalizado e, em seguida, continuar a partir do Capítulo 5.

Para usar o Microsoft Graph no Unity, você precisa usar a DLL Microsoft.Identity.Client . É possível usar o SDK do Microsoft Graph, no entanto, ele exigirá a adição de um pacote NuGet depois que você compilar o projeto do Unity (ou seja, editar o projeto após o build). É considerado mais simples importar as DLLs necessárias diretamente para o Unity.

Observação

Atualmente, há um problema conhecido no Unity que exige que os plug-ins sejam reconfigurados após a importação. Essas etapas (4 a 7 nesta seção) não serão mais necessárias depois que o bug for resolvido.

Para importar o Microsoft Graph para seu próprio projeto, baixe o arquivo MSGraph_LabPlugins.zip. Esse pacote foi criado com versões das bibliotecas que foram testadas.

Se você quiser saber mais sobre como adicionar DLLs personalizadas ao seu projeto do Unity, siga este link.

Para importar o pacote:

  1. Adicione o Pacote do Unity ao Unity usando a opção de menuPacote Personalizado deImportaçãode Ativos>>. Selecione o pacote que você acabou de baixar.

  2. Na caixa Importar Pacote do Unity que aparece, verifique se tudo em (e incluindo) Plug-ins está selecionado.

    Captura de tela que mostra os parâmetros de configuração selecionados em Plug-ins.

  3. Clique no botão Importar para adicionar os itens ao seu projeto.

  4. Vá para a pasta MSGraph em Plug-ins no Painel de Projeto e selecione o plug-in chamado Microsoft.Identity.Client.

    Captura de tela que mostra o plug-in Microsoft.Identity.Client.

  5. Com o plug-in selecionado, verifique se Qualquer Plataforma está desmarcada e verifique se o WSAPlayer também está desmarcado e clique em Aplicar. Isso é apenas para confirmar se os arquivos estão configurados corretamente.

    Captura de tela que mostra onde confirmar se Qualquer Plataforma e WSAPlayer não estão marcados.

    Observação

    Marcar esses plug-ins configura-os para serem usados apenas no Editor do Unity. 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.

  6. Em seguida, você precisa abrir a pasta WSA , dentro da pasta MSGraph . Você verá uma cópia do mesmo arquivo que acabou de configurar. Selecione o arquivo e, em seguida, no inspetor:

    • verifique se Qualquer Plataforma está desmarcada e se somenteo WSAPlayer está marcado.

    • Verifique se o SDK está definido como UWP e se o back-end de script está definido como Dot Net

    • Verifique se Não processar está marcado.

      Captura de tela que mostra que Não Processar está selecionado.

  7. Clique em Aplicar.

Capítulo 4 – Instalação da câmera

Durante este Capítulo, você configurará a Câmera Principal de sua cena:

  1. No Painel hierarquia, selecione a Câmera Principal.

  2. Depois de selecionado, você poderá ver todos os componentes da Câmera Principal no painel Inspetor .

    1. O objeto Câmera deve ser nomeado Câmera Principal (observe a ortografia!)

    2. A Marca da Câmera Principal deve ser definida como MainCamera (observe a ortografia!)

    3. Verifique se a Posição de Transformação está definida como 0, 0, 0

    4. Definir Sinalizadores Desmarcados como Cor Sólida

    5. Defina a Cor da Tela de Fundo do Componente da Câmera como Preto, Alfa 0(Código Hex: #000000000)

      Captura de tela que realça onde definir a cor da tela de fundo.

  3. A estrutura final do objeto no Painel de Hierarquia deve ser semelhante à mostrada na imagem abaixo:

    Captura de tela que mostra a estrutura final do objeto no Painel de Hierarquia.

Capítulo 5 – Criar reuniõesUsa classe UI

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 detalhes das reuniões).

Para criar essa classe:

  1. Clique com o botão direito do mouse na pasta Ativos no Painel de Projeto e selecione Criar>Pasta. Nomeie a pasta Scripts.

    Captura de tela que mostra onde encontrar a pasta Ativos.Captura de tela que mostra onde criar a pasta Scripts.

  2. Abra a pasta Scripts e, dentro dessa pasta, clique com o botão direito do mouse em Criar>Script C#. Nomeie o script MeetingsUI.

    Captura de tela que mostra onde criar a pasta MeetingsUI.

  3. Clique duas vezes no novo script MeetingsUI para abri-lo com o Visual Studio.

  4. Insira os seguintes namespaces:

    using System;
    using UnityEngine;
    
  5. Dentro da classe, insira as seguintes variáveis:

        /// <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 Awake(). Eles serão chamados quando a classe inicializar:

        /// <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 pela criação da interface do usuário de Reuniões e preencha-a com as reuniões atuais quando solicitado:

        /// <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 suas alterações no Visual Studio antes de retornar ao Unity.

Capítulo 6 – Criar a classe Graph

O próximo script a ser criado é o script do Graph . Esse script é responsável por fazer as chamadas para autenticar o usuário e recuperar as reuniões agendadas para o dia atual do calendário do usuário.

Para criar essa classe:

  1. Clique duas vezes na pasta Scripts para abri-la.

  2. Clique com o botão direito do mouse na pasta Scripts e clique em Criar>Script C#. Nomeie o script Graph.

  3. Clique duas vezes no script para abri-lo com o Visual Studio.

  4. Insira os seguintes 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 neste script são encapsuladas em diretivas de pré-preenchimento, isso é para evitar problemas com as bibliotecas ao criar a Solução do Visual Studio.

  5. Exclua os métodos Start() e Update(), pois eles não serão usados.

  6. Fora da classe Graph , insira os seguintes objetos, que são necessários para desserializar o objeto JSON que representa as reuniões agendadas diárias:

    /// <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 Graph , adicione as seguintes variáveis:

        /// <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 ser a ID do aplicativo que você anotou no Capítulo 1, etapa 4. Esse valor deve ser o mesmo exibido no Portal de Registro de Aplicativo, na página de registro do aplicativo.

  8. Na classe Graph , adicione os métodos SignInAsync() e AquireTokenAsync(), que solicitarão que o usuário insira as credenciais de logon.

        /// <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. Adicione os dois métodos a seguir:

    1. BuildTodayCalendarEndpoint(), que cria o URI que especifica o dia e o período de tempo, no qual as reuniões agendadas são recuperadas.

    2. ListMeetingsAsync(), que solicita as reuniões agendadas do 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. Você concluiu o script do Graph . Salve suas alterações no Visual Studio antes de retornar ao Unity.

Capítulo 7 – Criar o script GazeInput

Agora você criará o GazeInput. Essa classe manipula e controla o foco do usuário, usando um Raycast proveniente da Câmera Principal, projetando para frente.

Para criar o script:

  1. Clique duas vezes na pasta Scripts para abri-la.

  2. Clique com o botão direito do mouse na pasta Scripts e clique em Criar>Script C#. Nomeie o script GazeInput.

  3. Clique duas vezes no script para abri-lo com o Visual Studio.

  4. Altere o código de namespaces para corresponder ao abaixo, juntamente com a adição da marca '[System.Serializable]' acima da classe GazeInput , para que ele possa ser serializado:

    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:

        [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( ):

        /// <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 raycast de foco e controlam os objetos focados.

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

Capítulo 8 – Criar a classe Interactions

Agora você precisará criar o script De interações , que é responsável por:

  • Manipulando a interação de toque e o Olhar da Câmera, que permite que o usuário interaja com o "botão" de logon na cena.

  • Criando o objeto "button" de logon na cena para o usuário interagir.

Para criar o script:

  1. Clique duas vezes na pasta Scripts para abri-la.

  2. Clique com o botão direito do mouse na pasta Scripts e clique em Criar>Script C#. Nomeie o script Interações.

  3. Clique duas vezes no script para abri-lo com o Visual Studio.

  4. Insira os seguintes namespaces:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Altere a herança da classe Interaction de MonoBehaviour para GazeInput.

    Interações de classe pública: MonoBehaviour

    public class Interactions : GazeInput
    
  6. Dentro da classe Interação , insira a seguinte variável:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Substitua o método Start ; observe que é um método de substituição, que chama o método de classe Gaze 'base'. Start() será chamado quando a classe for inicializada, registrando-se para reconhecimento de entrada e criando o botão de entrada na cena:

        /// <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 de entrada na cena e definirá suas propriedades:

        /// <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 responderá ao evento Tocar usuário.

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

Capítulo 9 – Configurar as referências de script

Neste Capítulo, você precisa colocar o script de Interações na Câmera Principal. Em seguida, esse script manipulará a colocação dos outros scripts em que eles precisam estar.

  • Na pasta Scripts no Painel de Projeto, arraste o script Interações para o objeto Câmera Principal , conforme mostrado abaixo.

    Captura de tela que mostra onde arrastar o script de Interações.

Capítulo 10 – Configurando a marca

O código que manipula o foco usará o Tag SignInButton para identificar com qual objeto o usuário interagirá para entrar no Microsoft Graph.

Para criar a marca:

  1. No Editor do Unity, clique na Câmera Principal no Painel de Hierarquia.

  2. No Painel do Inspetor, clique na MarcaMainCamera para abrir uma lista suspensa. Clique em Adicionar Marca...

    Captura de tela que realça a Marca de Adição... Opção.

  3. Clique no botão +.

    Captura de tela que mostra o botão + .

  4. Escreva o nome da marca como SignInButton e clique em Salvar.

    Captura de tela que mostra onde adicionar o nome da marca SignInButton.

Capítulo 11 – Criar o projeto do Unity para UWP

Tudo o que é necessário para a seção unity deste projeto foi concluído, portanto, é hora de compilá-lo do Unity.

  1. Navegue até Configurações de Build (Configurações de Build de Arquivo>).

    Captura de tela que mostra a caixa de diálogo Configurações de Build.

  2. Se ainda não estiver, marque Projetos C# do Unity.

  3. Clique em Compilar. O Unity iniciará uma janela Explorador de Arquivos, na qual você precisa criar e, em seguida, selecionará uma pasta para criar o aplicativo. Crie essa pasta agora e nomeie-a como Aplicativo. Em seguida, com a pasta Aplicativo selecionada, clique em Selecionar Pasta.

  4. O Unity começará a compilar seu projeto para a pasta Aplicativo .

  5. Depois que o Unity terminar de compilar (pode levar algum tempo), ele abrirá uma janela Explorador de Arquivos no local do build (marcar sua barra de tarefas, pois ela pode nem sempre aparecer acima das janelas, mas notificará você sobre a adição de uma nova janela).

Capítulo 12 – Implantar no HoloLens

Para implantar no HoloLens:

  1. Você precisará do endereço IP do HoloLens (para Implantação Remota) e para garantir que o HoloLens esteja no Modo de Desenvolvedor. Para fazer isso:

    1. Ao usar o HoloLens, abra as Configurações.

    2. Vá para Rede &Opções Avançadasde Wi-Fi> da Internet >

    3. Observe o endereço IPv4 .

    4. Em seguida, navegue de volta para Configurações e, em seguida, para Atualizar & Segurança>para Desenvolvedores

    5. Defina Modo de Desenvolvedor Ativado.

  2. Navegue até o novo build do Unity (a pasta Aplicativo ) e abra o arquivo de solução com o Visual Studio.

  3. Na Configuração da Solução , selecione Depurar.

  4. Na Plataforma de Solução, selecione x86, Computador Remoto. Você será solicitado a inserir o endereço IP de um dispositivo remoto (o HoloLens, nesse caso, que você anotou).

    Captura de tela que mostra onde selecionar x86 e Computador Remoto.

  5. Vá para o menu Compilar e clique em Implantar Solução para fazer sideload do aplicativo no HoloLens.

  6. Seu aplicativo agora deve aparecer na lista de aplicativos instalados no HoloLens, pronto para ser iniciado!

Seu aplicativo HoloLens do Microsoft Graph

Parabéns, você criou um aplicativo de realidade misturada que aproveita o Microsoft Graph para ler e exibir dados do Calendário do usuário.

Captura de tela que mostra o aplicativo de realidade misturada concluído.

Exercícios de bônus

Exercício 1

Usar o Microsoft Graph para exibir outras informações sobre o usuário

  • Email do usuário/número de telefone/imagem de perfil

Exercício 1

Implemente o controle de voz para navegar pela interface do usuário do Microsoft Graph.