HoloLens (1. nesil) ve Azure 311 - Microsoft Graph

Not

Karma Gerçeklik Academy öğreticileri HoloLens (1. nesil) ve Karma Gerçeklik Immersive Headsets düşünülerek tasarlanmıştır. Bu nedenle, bu cihazlar için geliştirme konusunda hala rehberlik arayan geliştiriciler için bu öğreticileri yerinde bırakmanın önemli olduğunu hissediyoruz. Bu öğreticiler, HoloLens 2 için kullanılan en son araç kümeleri veya etkileşimlerle güncelleştirilmez. Desteklenen cihazlarda çalışmaya devam etmek için bakımları yapılır. Gelecekte HoloLens 2 için nasıl geliştirileceğini gösteren yeni bir öğretici serisi sunulacaktır. Bu bildirim, gönderildiğinde bu öğreticilerin bağlantısıyla güncelleştirilir.

Bu kursta, karma gerçeklik uygulamasında güvenli kimlik doğrulaması kullanarak Microsoft hesabınızda oturum açmak için Microsoft Graph'ı kullanmayı öğreneceksiniz. Ardından zamanlanmış toplantılarınızı uygulama arabiriminde alır ve görüntülersiniz.

Uygulama arabiriminde zamanlanmış toplantıları gösteren ekran görüntüsü.

Microsoft Graph, Microsoft'un birçok hizmeti için erişim sağlamak için tasarlanmış bir DIZI API'dir. Microsoft, Microsoft Graph'ı ilişkilere bağlı bir kaynak matrisi olarak tanımlar, yani bir uygulamanın her türlü bağlı kullanıcı verisine erişmesine izin verir. Daha fazla bilgi için Microsoft Graph sayfasını ziyaret edin.

Geliştirme, kullanıcının bakması ve ardından bir küreye dokunarak kullanıcıdan bir Microsoft hesabında güvenli bir şekilde oturum açmasını isteyecek bir uygulama oluşturulmasını içerir. Kullanıcı hesabında oturum açtıktan sonra, gün için zamanlanmış toplantıların listesini görebilir.

Bu kursu tamamladıktan sonra aşağıdakileri yapabilecek bir karma gerçeklik HoloLens uygulamanız olacak:

  1. Dokunma hareketini kullanarak bir nesneye dokunun; bu nesne, kullanıcıdan bir Microsoft Hesabında oturum açmasını ister (oturum açmak için uygulamadan çıkıp tekrar uygulamaya geri döner).
  2. Gün için zamanlanmış toplantıların listesini görüntüleyin.

Uygulamanızda, sonuçları tasarımınızla nasıl tümleştireceğiniz size bağlı. Bu kurs, bir Azure Hizmetini Unity projenizle tümleştirmeyi öğretmek için tasarlanmıştır. Karma gerçeklik uygulamanızı geliştirmek için bu kurstan elde ettiğiniz bilgileri kullanmak sizin işinizdir.

Cihaz desteği

Kurs HoloLens Çevreleyici kulaklıklar
MR ve Azure 311: Microsoft Graph ✔️

Önkoşullar

Not

Bu öğretici, Unity ve C# ile ilgili temel deneyime sahip geliştiriciler için tasarlanmıştır. Bu belgedeki önkoşulların ve yazılı yönergelerin, yazma sırasında (Temmuz 2018) test edilen ve doğrulananları temsil ettiğini de unutmayın. Araçları yükleme makalesinde listelendiği gibi en son yazılımı kullanabilirsiniz, ancak bu kurstaki bilgilerin aşağıda listelenenlerden daha yeni yazılımlarda bulacağınız bilgilerle mükemmel bir şekilde eşleşeceği varsayılmamalıdır.

Bu kurs için aşağıdaki donanım ve yazılımları öneririz:

Başlamadan önce

  1. Bu projeyi oluştururken sorunlarla karşılaşmamak için, bu öğreticide bahsedilen projeyi kök veya köke yakın bir klasörde oluşturmanız önemle önerilir (uzun klasör yolları derleme zamanında sorunlara neden olabilir).
  2. HoloLens'inizi ayarlayın ve test edin. HoloLens'inizi ayarlamak için desteğe ihtiyacınız varsa HoloLens kurulum makalesini ziyaret edin.
  3. Yeni bir HoloLens Uygulaması geliştirmeye başlarken Kalibrasyon ve Algılayıcı Ayarlaması yapmak iyi bir fikirdir (bazen bu görevleri her kullanıcı için gerçekleştirmeye yardımcı olabilir).

Kalibrasyon hakkında yardım için lütfen HoloLens Kalibrasyon makalesinin bağlantısını izleyin.

Algılayıcı Ayarlama hakkında yardım için lütfen HoloLens Algılayıcı Ayarlama makalesinin bağlantısını izleyin.

1. Bölüm - Uygulamanızı Uygulama Kayıt Portalı'nda oluşturma

Başlangıç olarak, uygulamanızı Uygulama Kayıt Portalı'nda oluşturmanız ve kaydetmeniz gerekir.

Bu Bölümde, hesap içeriğinize erişmek için Microsoft Graph'a çağrı yapmanıza olanak sağlayan Hizmet Anahtarı'nı da bulacaksınız.

  1. Microsoft Uygulama Kayıt Portalı'na gidin ve Microsoft Hesabınızla oturum açın. Oturum açtıktan sonra Uygulama Kayıt Portalı'na yönlendirilirsiniz.

  2. Uygulamalarım bölümünde Uygulama ekle düğmesine tıklayın.

    Uygulama ekle'nin seçileceği yeri gösteren ekran görüntüsü.

    Önemli

    Uygulama Kayıt Portalı, daha önce Microsoft Graph ile çalışıp çalışmadığınıza bağlı olarak farklı görünebilir. Aşağıdaki ekran görüntüleri bu farklı sürümleri gösterir.

  3. Uygulamanız için bir ad ekleyin ve Oluştur'a tıklayın.

    Uygulamanız için bir adın nereye ekleneceğini gösteren ekran görüntüsü.

  4. Uygulama oluşturulduktan sonra uygulama ana sayfasına yönlendirilirsiniz. Uygulama Kimliği'ni kopyalayın ve bu değeri güvenli bir yere not edin, kısa süre içinde kodunuzda kullanacaksınız.

    Uygulama Kimliğinin nerede görüntülendiğini gösteren ekran görüntüsü.

  5. Platformlar bölümünde Yerel Uygulama'nın görüntülendiğinden emin olun. Aksi takdirdePlatform Ekle'ye tıklayın ve Yerel Uygulama'ya tıklayın.

    Yerel Uygulama bölümünü vurgulayan ekran görüntüsü.

  6. Aynı sayfada aşağı kaydırın ve Microsoft Graph İzinleri adlı bölümde uygulama için ek izinler eklemeniz gerekir. Temsilci İzinleri'nin yanındaki Ekle'ye tıklayın.

    Temsilci İzinleri'nin yanında Ekle'nin seçileceği yeri gösteren ekran görüntüsü.

  7. Uygulamanızın kullanıcının Takvimine erişmesini istediğiniz için Takvimler.Oku adlı kutuyu işaretleyin ve Tamam'a tıklayın.

    Calendars.Read onay kutusunu gösteren ekran görüntüsü.

  8. Ekranı en alta kaydırın ve Kaydet düğmesine tıklayın.

    Kaydet'in seçileceği yeri gösteren ekran görüntüsü.

  9. Kaydetme işleminiz onaylanır ve Uygulama Kayıt Portalı'ndan oturumunuzu kapatabilirsiniz.

2. Bölüm - Unity projesini ayarlama

Aşağıda karma gerçeklikle geliştirmeye yönelik tipik bir kurulum verilmiştir ve bu nedenle diğer projeler için iyi bir şablondur.

  1. Unity'yi açın ve Yeni'ye tıklayın.

    Unity arabirimini gösteren ekran görüntüsü.

  2. Unity proje adı sağlamanız gerekir. MSGraphMR'yi ekleyin. Proje şablonunun 3B olarak ayarlandığından emin olun. Konum değerini sizin için uygun bir konuma ayarlayın (kök dizinlere daha yakın olmak daha iyidir). Ardından Proje oluştur'a tıklayın.

    Proje Oluştur'un seçileceği yeri gösteren ekran görüntüsü.

  3. Unity açıkken, varsayılan Betik Düzenleyicisi'ninVisual Studio olarak ayarlandığını denetlemeye değer. TercihleriDüzenle'ye> gidin ve yeni pencerede Dış Araçlar'a gidin. Dış Betik Düzenleyicisi'niVisual Studio 2017 olarak değiştirin. Tercihler penceresini kapatın.

    Dış Betik Düzenleyicisi'nin Visual Studio 2017 olarak ayarlanacağı yeri gösteren ekran görüntüsü.

  4. Dosya>Derleme Ayarları'na gidin ve Evrensel Windows Platformu seçin, ardından seçiminizi uygulamak için Platform Değiştir düğmesine tıklayın.

    Platform Değiştir'in seçileceği yeri gösteren ekran görüntüsü.

  5. Dosya>Derleme Ayarları'ndayken şunları yaptığınızdan emin olun:

    1. Hedef CihazHoloLens olarak ayarlandı

    2. Derleme TürüD3D olarak ayarlandı

    3. SDK en son yüklü olarak ayarlandı

    4. Visual Studio SürümüEn son yüklü olarak ayarlandı

    5. Derleme ve Çalıştırma, Yerel Makine olarak ayarlanır

    6. Sahneyi kaydedin ve derlemeye ekleyin.

      1. Bunu yapmak için Açık Sahne Ekle'yi seçin. Bir kaydetme penceresi görüntülenir.

        Açık Sahne Ekle'nin nerede seçildiğini gösteren ekran görüntüsü.

      2. Bunun için yeni bir klasör ve gelecekteki herhangi bir sahneyi oluşturun. Yeni klasör düğmesini seçerek yeni bir klasör oluşturun ve Bunu Sahneler olarak adlandırın.

        Yeni klasörün nerede adlandırıldığını gösteren ekran görüntüsü.

      3. Yeni oluşturduğunuz Sahneler klasörünüzü açın ve Dosya adı: metin alanına MR_ComputerVisionScene yazın ve Kaydet'e tıklayın.

        Dosya adının nereye yazıldığını gösteren ekran görüntüsü.

        Önemli

        Unity projenizle ilişkilendirilmeleri gerektiğinden Unity sahnelerinizi Varlıklar klasörüne kaydetmeniz gerektiğini unutmayın. Sahneler klasörünü (ve diğer benzer klasörleri) oluşturmak, Unity projesini yapılandırmanın tipik bir yoludur.

    7. Derleme Ayarları'nda kalan ayarlar şimdilik varsayılan olarak bırakılmalıdır.

  6. Derleme Ayarları penceresinde Oynatıcı Ayarları düğmesine tıklayın; bu işlem, Denetçi'nin bulunduğu alanda ilgili paneli açar.

    Yürütücü Ayarları iletişim kutusunu gösteren ekran görüntüsü.

  7. Bu panelde birkaç ayarın doğrulanması gerekir:

    1. Diğer Ayarlar sekmesinde:

      1. Betik ÇalışmaZamanı SürümüDeneysel (.NET 4.6 Eşdeğeri) olmalıdır ve bu da Düzenleyici'yi yeniden başlatma gereksinimini tetikler.

      2. Betik Arka Ucu.NET olmalıdır

      3. API Uyumluluk Düzeyi.NET 4.6 olmalıdır

        API uyumluluk düzeyinin nerede denetlendiğini gösteren ekran görüntüsü.

    2. Yayımlama Ayarları sekmesindeki Özellikler'in altında şunları denetleyin:

      • InternetClient

        InternetClient seçeneğinin nerede seçildiğini gösteren ekran görüntüsü.

    3. Panelin aşağısında, XR Ayarları'nda (Yayımlama Ayarları'nın altında bulunur) Sanal Gerçeklik Desteği'ne bakın, Windows Mixed Reality SDK'sının eklendiğinden emin olun.

      Windows Mixed Reality SDK'nın nereye ekleneceğini gösteren ekran görüntüsü.

  8. Derleme Ayarları'ndaUnity C# Projeleri artık gri değil; bunun yanındaki onay kutusunu işaretleyin.

  9. Derleme Ayarları penceresini kapatın.

  10. Sahnenizi ve projenizi kaydedin (FILE>SAVE SCENES / FILE>SAVE PROJECT).

3. Bölüm - Unity'de Kitaplıkları İçeri Aktarma

Önemli

Bu kursun Unity Set up bileşenini atlamak ve doğrudan koda geçmek istiyorsanız, bu Azure-MR-311.unitypackage'ı indirebilir, özel paket olarak projenize aktarıp 5. Bölümden devam edebilirsiniz.

Unity'de Microsoft Graph'ı kullanmak için Microsoft.Identity.Client DLL'sini kullanmanız gerekir. Microsoft Graph SDK'sını kullanmak mümkündür, ancak Unity projesini derledikten sonra (derleme sonrasında projeyi düzenlemek anlamına gelir) nuGet paketinin eklenmesi gerekir. Gerekli DLL'lerin doğrudan Unity'ye aktarılması daha basit kabul edilir.

Not

Şu anda Unity'de eklentilerin içeri aktarma işleminden sonra yeniden yapılandırılmasını gerektiren bilinen bir sorun vardır. Hata çözüldükten sonra bu adımlar (bu bölümdeki 4 - 7) artık gerekli olmayacaktır.

Microsoft Graph'ı kendi projenize aktarmak için MSGraph_LabPlugins.zip dosyasını indirin. Bu paket, test edilmiş kitaplıkların sürümleriyle oluşturulmuştur.

Unity projenize özel DLL'ler ekleme hakkında daha fazla bilgi edinmek istiyorsanız bu bağlantıyı izleyin.

Paketi içeri aktarmak için:

  1. Varlıklar> İçeri Aktarma Paketi Özel Paket menü seçeneğini kullanarak UnityPaketi'ni>Unity'ye ekleyin. Yeni indirdiğiniz paketi seçin.

  2. Açılan Unity Paketini İçeri Aktar kutusunda Eklentiler altındaki (ve dahil) her şeyin seçili olduğundan emin olun.

    Eklentiler'in altında seçili yapılandırma parametrelerini gösteren ekran görüntüsü.

  3. Öğeleri projenize eklemek için İçeri Aktar düğmesine tıklayın.

  4. Proje Paneli'ndekiEklentiler'in altındaki MSGraph klasörüne gidin ve Microsoft.Identity.Client adlı eklentiyi seçin.

    Microsoft.Identity.Client eklentisini gösteren ekran görüntüsü.

  5. Eklenti seçiliyken Herhangi Bir Platform'un işaretinin kaldırıldığından emin olun, ardından WSAPlayer'ın da işaretinin kaldırıldığından emin olun, ardından Uygula'ya tıklayın. Bu yalnızca dosyaların doğru yapılandırıldığını onaylamak için kullanılır.

    Herhangi bir Platform ve WSAPlayer'ın işaretlenmediğinin nerede onaylandığını gösteren ekran görüntüsü.

    Not

    Bu eklentilerin işaretlenmesi, bunları yalnızca Unity Düzenleyicisi'nde kullanılacak şekilde yapılandırılır. WSA klasöründe, proje Unity'den Evrensel Windows Uygulaması olarak dışarı aktarıldıktan sonra kullanılacak farklı bir DLL kümesi vardır.

  6. Ardından, MSGraph klasörünün içindeki WSA klasörünü açmanız gerekir. Az önce yapılandırdığınız dosyanın bir kopyasını görürsünüz. Dosyayı seçin ve ardından denetçide:

    • Herhangi bir Platformunişaretinin kaldırıldığından ve yalnızcaWSAPlayer'ınişaretli olduğundan emin olun.

    • SDK'nınUWP ve Betik Arka Ucu'nınNokta Net olarak ayarlandığından emin olun

    • İşleme seçeneğinin işaretli olduğundan emin olun.

      İşleme seçeneğinin belirlendiğini gösteren ekran görüntüsü.

  7. Uygula’ya tıklayın.

Bölüm 4 - Kamera Kurulumu

Bu Bölüm sırasında sahnenizin Ana Kamerasını ayarlayacaksınız:

  1. Hiyerarşi Paneli'ndeAna Kamera'yı seçin.

  2. Seçildikten sonra, Ana Kamera'nın tüm bileşenlerini Denetçi panelinde görebilirsiniz.

    1. Kamera nesnesiAna Kamera olarak adlandırılmalıdır (yazımı not edin!)

    2. Ana Kamera EtiketiMainCamera olarak ayarlanmalıdır (yazım denetimine dikkat edin!)

    3. Dönüştürme Konumunun0, 0, 0 olarak ayarlandığından emin olun

    4. Bayrakları Temizle'yiDüz Renk olarak ayarlama

    5. Kamera Bileşeninin Arka Plan RenginiSiyah, Alfa 0(Onaltılık Kod: #000000000) olarak ayarlayın

      Arka plan renginin ayarlanacağı yeri vurgulayan ekran görüntüsü.

  3. Hiyerarşi Panelindeki son nesne yapısı aşağıdaki resimde gösterilene benzer olmalıdır:

    Hiyerarşi Panelindeki son nesne yapısını gösteren ekran görüntüsü.

5. Bölüm - Toplantı oluşturmaUI sınıfı

Oluşturmanız gereken ilk betik, uygulamanın kullanıcı arabirimini barındırmaktan ve doldurmaktan sorumlu olan MeetingsUI'dir (hoş geldiniz iletisi, yönergeler ve toplantı ayrıntıları).

Bu sınıfı oluşturmak için:

  1. Proje Paneli'ndeVarlıklar klasörüne sağ tıklayın veKlasörOluştur'u> seçin. Klasöre Betikler adını verin.

    Varlıklar klasörünün nerede bulunacağı gösteren ekran görüntüsü.Betikler klasörünün nerede oluşturulacağını gösteren ekran görüntüsü.

  2. Betikler klasörünü açın ve ardından bu klasörün içindeC# BetiğiOluştur'a> sağ tıklayın. Betiği MeetingsUI olarak adlandırın.

    MeetingsUI klasörünün nerede oluşturulacağını gösteren ekran görüntüsü.

  3. Yeni MeetingsUI betiğine çift tıklayarak Visual Studio ile açın.

  4. Aşağıdaki ad alanlarını ekleyin:

    using System;
    using UnityEngine;
    
  5. sınıfının içine aşağıdaki değişkenleri ekleyin:

        /// <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. Ardından Start() yöntemini değiştirin ve bir Awake() yöntemi ekleyin. Sınıf başlatıldığında bunlar çağrılır:

        /// <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. Toplantılar kullanıcı arabirimini oluşturmakla sorumlu yöntemleri ekleyin ve istendiğinde geçerli toplantılarla doldurun:

        /// <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. Update() yöntemini silin ve Unity'ye dönmeden önce değişikliklerinizi Visual Studio'ya kaydedin.

6. Bölüm - Graph sınıfını oluşturma

Oluşturulacak bir sonraki betik Graph betiğidir. Bu betik, kullanıcının kimliğini doğrulamak ve kullanıcının takviminden geçerli gün için zamanlanmış toplantıları almak için çağrı yapmaktan sorumludur.

Bu sınıfı oluşturmak için:

  1. Betikler klasörüne çift tıklayarak açın.

  2. Betikler klasörünün içine sağ tıklayın,C# BetiğiOluştur'a> tıklayın. Betiği Graph olarak adlandırın.

  3. Betiği çift tıklayarak Visual Studio ile açın.

  4. Aşağıdaki ad alanlarını ekleyin:

    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
    

    Önemli

    Bu betikteki kodun bölümlerinin, Visual Studio Çözümünü oluştururken kitaplıklarla ilgili sorunları önlemek için Ön Derleme Yönergeleri çevresinde sarmalandığını fark edeceksiniz.

  5. Kullanılmayacağı için Start() ve Update() yöntemlerini silin.

  6. Graph sınıfının dışında, günlük zamanlanmış toplantıları temsil eden JSON nesnesinin seri durumdan çıkarılması için gereken aşağıdaki nesneleri ekleyin:

    /// <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. Graph sınıfının içine aşağıdaki değişkenleri ekleyin:

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

    Not

    appId değerini, 1. Bölüm 4'te not ettiğiniz Uygulama Kimliği olarak değiştirin. Bu değer , Uygulama Kayıt Portalı'nda uygulama kaydı sayfanızda görüntülenen değerle aynı olmalıdır.

  8. Graph sınıfı içinde, kullanıcıdan oturum açma kimlik bilgilerini eklemesini isteyecek SignInAsync() ve AquireTokenAsync() yöntemlerini ekleyin.

        /// <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. Aşağıdaki iki yöntemi ekleyin:

    1. Zamanlanmış toplantıların alındığı gün ve zaman aralığını belirten URI'yi oluşturan BuildTodayCalendarEndpoint().

    2. Zamanlanmış toplantıları Microsoft Graph'tan isteyen ListMeetingsAsync().

        /// <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. Şimdi Graph betiğini tamamladınız. Unity'ye dönmeden önce değişikliklerinizi Visual Studio'ya kaydedin.

7. Bölüm - GazeInput betiğini oluşturma

Şimdi GazeInput'u oluşturacaksınız. Bu sınıf, Ana Kameradan gelen bir Raycast kullanarak ileriye doğru yansıtarak kullanıcının bakışını işler ve izler.

Betiği oluşturmak için:

  1. Betikler klasörüne çift tıklayarak açın.

  2. Betikler klasörünün içine sağ tıklayın,C# BetiğiOluştur'a> tıklayın. Betiği GazeInput olarak adlandırın.

  3. Betiği çift tıklayarak Visual Studio ile açın.

  4. Ad alanı kodunu aşağıdaki kodla eşleşecek şekilde değiştirin ve Seri hale getirilebilmesi için GazeInput sınıfınızın üzerine '[System.Serializable]' etiketini ekleyin:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. GazeInput sınıfının içine aşağıdaki değişkenleri ekleyin:

        [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. Sahnede HoloLens imlecini oluşturmak için CreateCursor() yöntemini ekleyin ve Start() yönteminden yöntemini çağırın:

        /// <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. Aşağıdaki yöntemler Raycast'a bakmayı ve odaklanmış nesneleri izlemeyi sağlar.

    /// <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. Unity'ye dönmeden önce değişikliklerinizi Visual Studio'ya kaydedin.

8. Bölüm - Etkileşimler sınıfını oluşturma

Şimdi aşağıdakilerden sorumlu olan Etkileşimler betiğini oluşturmanız gerekir:

  • Dokunma etkileşimini ve kullanıcının sahnedeki "düğme" ile etkileşim kurmasını sağlayan Kamera Bakışı'nı işleme.

  • Kullanıcının etkileşim kurması için sahnedeki "düğme" nesnesinde oturum açma oluşturma.

Betiği oluşturmak için:

  1. Betikler klasörüne çift tıklayarak açın.

  2. Betikler klasörünün içine sağ tıklayın,C# BetiğiOluştur'a> tıklayın. Betiği Etkileşimler olarak adlandırın.

  3. Betiği çift tıklayarak Visual Studio ile açın.

  4. Aşağıdaki ad alanlarını ekleyin:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Interaction sınıfının devralını MonoBehaviour olan GazeInput olarak değiştirin.

    public class Interactions : MonoBehaviour

    public class Interactions : GazeInput
    
  6. Interaction sınıfının içine aşağıdaki değişkeni ekleyin:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Start yöntemini değiştirin; 'base' Gaze sınıf yöntemini çağıran bir geçersiz kılma yöntemi olduğuna dikkat edin. Start() sınıfı başlatıldığında çağrılır, giriş tanımaya kaydolup sahnede oturum açma düğmesi oluşturulur:

        /// <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. Sahnede oturum açma düğmesinin örneğini oluşturacak ve özelliklerini ayarlayacak CreateSignInButton() yöntemini ekleyin:

        /// <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. Dokun kullanıcı olayı için yanıtlanacak GestureRecognizer_Tapped() yöntemini ekleyin.

        /// <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. Update() yöntemini silin ve Unity'ye dönmeden önce değişikliklerinizi Visual Studio'ya kaydedin.

9. Bölüm - Betik başvurularını ayarlama

Bu Bölümde Etkileşimler betiğini Ana Kameraya yerleştirmeniz gerekir. Bu betik daha sonra diğer betiklerin olması gereken yere yerleştirilmesini işler.

  • Aşağıda gösterildiği gibi, Proje Paneli'ndekiBetikler klasöründen Etkileşimler betiğini Ana Kamera nesnesine sürükleyin.

    Etkileşimler betiğinin nereye sürüklendiğini gösteren ekran görüntüsü.

10. Bölüm - Etiketi Ayarlama

Bakışını işleyen kod, kullanıcının Microsoft Graph'ta oturum açmak için hangi nesneyle etkileşim kuracağını belirlemek için Tag SignInButton'ı kullanır.

Etiketi oluşturmak için:

  1. Unity Düzenleyicisi'nde Hiyerarşi PanelindeAna Kamera'ya tıklayın.

  2. Denetçi PanelindeMainCameraEtiketi'ne tıklayarak açılan listeyi açın. Etiket Ekle'ye tıklayın...

    Etiket Ekle'yi vurgulayan ekran görüntüsü... Seçeneği.

  3. Düğmeye + tıklayın.

    + düğmesini gösteren ekran görüntüsü.

  4. Etiket adını SignInButton olarak yazın ve Kaydet'e tıklayın.

    SignInButton etiket adının nereye ekleneceğini gösteren ekran görüntüsü.

11. Bölüm - Unity projesini UWP'ye derleme

Bu projenin Unity bölümü için gereken her şey tamamlandı, bu nedenle Unity'den derleme zamanı geldi.

  1. Derleme Ayarları'na (Dosya>Derleme Ayarları) gidin.

    Derleme Ayarları iletişim kutusunu gösteren ekran görüntüsü.

  2. Henüz yapmadıysanız Unity C# Projeleri'ni işaretleyin.

  3. Oluştur'a tıklayın. Unity, uygulamayı oluşturmak için bir klasör oluşturmanız ve ardından seçmeniz gereken bir Dosya Gezgini penceresi başlatır. Bu klasörü şimdi oluşturun ve Uygulama olarak adlandırlayın. Ardından Uygulama klasörü seçiliyken Klasör Seç'e tıklayın.

  4. Unity, projenizi Uygulama klasörüne oluşturmaya başlar.

  5. Unity derlemeyi tamamladıktan sonra (biraz zaman alabilir), derlemenizin konumunda bir Dosya Gezgini penceresi açar (görev çubuğunuzu denetleyin, her zaman pencerelerinizin üzerinde görünmeyebilir, ancak yeni bir pencere eklenmesini size bildirir).

12. Bölüm - HoloLens'e dağıtma

HoloLens'te dağıtmak için:

  1. HoloLens'inizin IP Adresine (Uzaktan Dağıtım için) ve HoloLens'inizin Geliştirici Modu'nda olduğundan emin olmanız gerekir. Bunu yapmak için:

    1. HoloLens'inizi takarken Ayarlar'ı açın.

    2. Ağ & İnternet>Wi-Fi>Gelişmiş Seçenekleri'ne gidin

    3. IPv4 adresini not edin.

    4. Ardından Ayarlar'a ve ardındanGeliştiriciler için& Güvenliği> Güncelleştir'e gidin

    5. Geliştirici modunu açık olarak ayarlayın.

  2. Yeni Unity derlemenize ( Uygulama klasörü) gidin ve Çözüm dosyasını Visual Studio ile açın.

  3. Çözüm Yapılandırması'ndaHata Ayıkla'ya tıklayın.

  4. Çözüm Platformu'ndax86, Uzak Makine'yi seçin. Uzak bir cihazın IP adresini eklemeniz istenir (bu durumda hololens, bunu not ettiğiniz).

    x86 ve Uzak Makine'nin nerede seçildiğini gösteren ekran görüntüsü.

  5. Uygulamayı HoloLens'inize dışarıdan yüklemek için Oluştur menüsüne gidin ve Çözümü Dağıt'a tıklayın.

  6. Uygulamanız artık HoloLens'inizde yüklenmeye hazır yüklü uygulamalar listesinde görünmelidir!

Microsoft Graph HoloLens uygulamanız

Tebrikler, kullanıcı Takvimi verilerini okumak ve görüntülemek için Microsoft Graph'ı kullanan bir karma gerçeklik uygulaması oluşturmuştsunuz.

Tamamlanan karma gerçeklik uygulamasını gösteren ekran görüntüsü.

Ek alıştırmalar

Alıştırma 1

Kullanıcı hakkındaki diğer bilgileri görüntülemek için Microsoft Graph'ı kullanma

  • Kullanıcı e-postası / telefon numarası / profil resmi

Alıştırma 1

Microsoft Graph kullanıcı arabiriminde gezinmek için ses denetimi uygulayın.