Xamarin'de watchOS Egzersiz Uygulamaları

Bu makale, Apple'ın watchOS 3'teki antrenman uygulamalarında yaptığı geliştirmeleri ve bunları Xamarin'de nasıl uygulayacaklarını kapsar.

watchOS 3'te yeni olan antrenmanla ilgili uygulamalar, Apple Watch'ta arka planda çalışabilir ve HealthKit verilerine erişim elde edebilir. Üst iOS 10 tabanlı uygulamaları, watchOS 3 tabanlı uygulamayı kullanıcı müdahalesi olmadan da başlatabilme özelliğine sahiptir.

Aşağıdaki konular ayrıntılı olarak ele alınacaktır:

Antrenman Uygulamaları Hakkında

Fitness ve egzersiz uygulamaları kullanıcıları, günün birkaç saatini sağlık ve fitness hedeflerine ayırarak son derece adanmış olabilir. Sonuç olarak, verileri doğru bir şekilde toplayıp görüntüleyen ve Apple Health ile sorunsuz bir şekilde tümleşen, hızlı yanıt veren, kullanımı kolay uygulamalar beklerler.

İyi tasarlanmış bir fitness veya egzersiz uygulaması, kullanıcıların fitness hedeflerine ulaşmak için etkinliklerini grafiğini oluşturmalarına yardımcı olur. Apple Watch kullanarak, fitness ve egzersiz uygulamaları kalp atış hızına, kalori yanıklarına ve etkinlik algılamaya anında erişime sahiptir.

Fitness ve egzersiz uygulaması örneği

watchOS 3'te yeni olan Arka Plan Çalıştırma, antrenmanla ilgili uygulamalara Apple Watch'ta arka planda çalışma ve HealthKit verilerine erişim sağlama olanağı sağlar.

Bu belgede Arka Plan Çalıştırma özelliği tanıtılacak, egzersiz uygulaması yaşam döngüsünü kapsayacak ve bir egzersiz uygulamasının Apple Watch'ta kullanıcının Etkinlik Halkalarına nasıl katkıda bulunabileceği gösterilecektir.

Antrenman Oturumları Hakkında

Her egzersiz uygulamasının kalbi, kullanıcının başlatabileceği ve durdurabileceği bir Egzersiz Oturumudur (HKWorkoutSession). Egzersiz Oturumu API'sinin uygulanması kolaydır ve bir egzersiz uygulaması için aşağıdakiler gibi çeşitli avantajlar sağlar:

  • Etkinlik Türüne göre hareket ve kalori yanık algılaması.
  • Kullanıcının Etkinlik Halkalarına otomatik katkı.
  • Oturumdayken, kullanıcı cihazı her uyandırdığında (bileğini kaldırarak veya Apple Watch ile etkileşim kurarak) uygulama otomatik olarak görüntülenir.

Arka Plan Çalıştırma Hakkında

Yukarıda belirtildiği gibi watchOS 3 ile bir egzersiz uygulaması arka planda çalışacak şekilde ayarlanabilir. Arka Plan'ı kullanma Egzersiz uygulaması çalıştırmak, arka planda çalışırken Apple Watch'un algılayıcılarındaki verileri işleyebilir. Örneğin, bir uygulama artık ekranda görüntülenmese bile kullanıcının kalp atış hızını izlemeye devam edebilir.

Arka Plan Çalıştırma, etkin bir Egzersiz Oturumu sırasında kullanıcıya mevcut ilerleme durumunu bildirmek için dokunsal bir uyarı gönderme gibi herhangi bir zamanda canlı geri bildirim sunma olanağı da sağlar.

Buna ek olarak, Arka Plan Çalıştırma, kullanıcının Apple Watch'larına hızla göz attığında en son verilere sahip olması için uygulamanın Kullanıcı Arabirimini hızla güncelleştirmesine olanak tanır.

Apple Watch'ta yüksek performansı korumak için Arka Plan Çalıştırma kullanan bir izleme uygulaması, pil tasarrufu sağlamak için arka plan çalışması miktarını sınırlamalıdır. Bir uygulama arka planda aşırı CPU kullanıyorsa watchOS tarafından askıya alınabilir.

Arka Plan Çalıştırmayı Etkinleştirme

Arka Plan Çalıştırma'yı etkinleştirmek için aşağıdakileri yapın:

  1. Çözüm Gezgini, düzenleme için açmak üzere İzleme Uzantısının eşlikçisi i Telefon uygulamasının Info.plist dosyasına çift tıklayın.

  2. Kaynak görünümüne geçin:

    Kaynak görünümü

  3. adlı WKBackgroundModes yeni bir anahtar ekleyin ve TürArrayolarak ayarlayın:

    WKBackgroundModes adlı yeni bir anahtar ekleyin

  4. TürüString ve değeriyle workout-processingdiziye yeni bir öğe ekleyin:

    Dize Türü ve antrenman işleme değeriyle diziye yeni bir öğe ekleyin

  5. Dosyadaki değişiklikleri kaydedin.

Antrenman Oturumu Başlatma

Antrenman Oturumu başlatmanın üç ana adımı vardır:

Antrenman Oturumu başlatmanın üç ana adımı

  1. Uygulamanın HealthKit'teki verilere erişmek için yetkilendirme istemesi gerekir.
  2. Başlatılmakta olan antrenman türü için bir Antrenman Yapılandırması nesnesi oluşturun.
  3. Yeni oluşturulan Antrenman Yapılandırması'nı kullanarak bir Antrenman Oturumu oluşturun ve başlatın.

Yetkilendirme İsteniyor

Bir uygulamanın kullanıcının HealthKit verilerine erişebilmesi için önce kullanıcıdan yetkilendirme istemesi ve alması gerekir. Antrenman uygulamasının yapısına bağlı olarak aşağıdaki istek türlerini yapabilir:

  • Veri yazma yetkisi:
    • Egzersiz
  • Verileri okumak için yetkilendirme:
    • Enerji yandı
    • Mesafe
    • Kalp Atış Hızı

Bir uygulamanın yetkilendirme isteğinde bulunabilmesi için önce HealthKit'e erişecek şekilde yapılandırılması gerekir.

Aşağıdakileri yapın:

  1. Çözüm Gezgini, dosyayı düzenlemek üzere açmak için çift tıklayınEntitlements.plist.

  2. En alta kaydırın ve HealthKit'i Etkinleştir'i işaretleyin:

    HealthKit'i Etkinleştir'i denetleme

  3. Dosyadaki değişiklikleri kaydedin.

  4. Uygulamayı doğru bir şekilde sağlamak için, HealthKit'e Giriş makalesinin Açık Uygulama Kimliği ve Sağlama Profili ile Uygulama Kimliği ve Sağlama Profilini Xamarin.iOS Uygulamanızla İlişkilendirme bölümündeki yönergeleri izleyin.

  5. Son olarak, Kullanıcının HealthKit veri deposuna erişmek için yetkilendirme istemek için HealthKit'e Giriş makalesinin Programlama Sistem Durumu Seti ve Kullanıcıdan İzin İsteme bölümündeki yönergeleri kullanın.

Antrenman Yapılandırmasını Ayarlama

Antrenman Oturumları, antrenman türünü (örneğinHKWorkoutActivityType.Running) ve antrenman konumunu (HKWorkoutConfigurationörneğinHKWorkoutSessionLocationType.Outdoor) belirten bir Egzersiz Yapılandırma nesnesi () kullanılarak oluşturulur:

using HealthKit;
...

// Create a workout configuration
var configuration = new HKWorkoutConfiguration () {
  ActivityType = HKWorkoutActivityType.Running,
  LocationType = HKWorkoutSessionLocationType.Outdoor
};

Antrenman Oturumu Temsilcisi Oluşturma

Antrenman Oturumu sırasında gerçekleşebilecek olayları işlemek için uygulamanın bir Antrenman Oturumu Temsilcisi örneği oluşturması gerekir. Projeye yeni bir sınıf ekleyin ve sınıfın dışına dayandırın HKWorkoutSessionDelegate . Dış mekan çalıştırması örneği için aşağıdaki gibi görünebilir:

using System;
using Foundation;
using WatchKit;
using HealthKit;

namespace MonkeyWorkout.MWWatchExtension
{
  public class OutdoorRunDelegate : HKWorkoutSessionDelegate
  {
    #region Computed Properties
    public HKHealthStore HealthStore { get; private set; }
    public HKWorkoutSession WorkoutSession { get; private set;}
    #endregion

    #region Constructors
    public OutdoorRunDelegate (HKHealthStore healthStore, HKWorkoutSession workoutSession)
    {
      // Initialize
      this.HealthStore = healthStore;
      this.WorkoutSession = workoutSession;

      // Attach this delegate to the session
      workoutSession.Delegate = this;
    }
    #endregion

    #region Override Methods
    public override void DidFail (HKWorkoutSession workoutSession, NSError error)
    {
      // Handle workout session failing
      RaiseFailed ();
    }

    public override void DidChangeToState (HKWorkoutSession workoutSession, HKWorkoutSessionState toState, HKWorkoutSessionState fromState, NSDate date)
    {
      // Take action based on the change in state
      switch (toState) {
      case HKWorkoutSessionState.NotStarted:
        break;
      case HKWorkoutSessionState.Paused:
        RaisePaused ();
        break;
      case HKWorkoutSessionState.Running:
        RaiseRunning ();
        break;
      case HKWorkoutSessionState.Ended:
        RaiseEnded ();
        break;
      }

    }

    public override void DidGenerateEvent (HKWorkoutSession workoutSession, HKWorkoutEvent @event)
    {
      base.DidGenerateEvent (workoutSession, @event);
    }
    #endregion

    #region Events
    public delegate void OutdoorRunEventDelegate ();

    public event OutdoorRunEventDelegate Failed;
    internal void RaiseFailed ()
    {
      if (this.Failed != null) this.Failed ();
    }

    public event OutdoorRunEventDelegate Paused;
    internal void RaisePaused ()
    {
      if (this.Paused != null) this.Paused ();
    }

    public event OutdoorRunEventDelegate Running;
    internal void RaiseRunning ()
    {
      if (this.Running != null) this.Running ();
    }

    public event OutdoorRunEventDelegate Ended;
    internal void RaiseEnded ()
    {
      if (this.Ended != null) this.Ended ();
    }
    #endregion
  }
}

Bu sınıf, Antrenman Oturumu'nun durumu değiştikçe () ve Antrenman Oturumu başarısız olursa (DidChangeToStateDidFail) tetiklenecek birkaç olay oluşturur.

Antrenman Oturumu Oluşturma

Yeni bir Antrenman Oturumu oluşturmak ve kullanıcının varsayılan HealthKit mağazasında başlatmak için yukarıda oluşturulan Antrenman Yapılandırması ve Antrenman Oturumu Temsilcisi'ni kullanarak:

using HealthKit;
...

#region Computed Properties
public HKHealthStore HealthStore { get; set;} = new HKHealthStore ();
public OutdoorRunDelegate RunDelegate { get; set; }
#endregion
...

private void StartOutdoorRun ()
{
  // Create a workout configuration
  var configuration = new HKWorkoutConfiguration () {
    ActivityType = HKWorkoutActivityType.Running,
    LocationType = HKWorkoutSessionLocationType.Outdoor
  };

  // Create workout session
  // Start workout session
  NSError error = null;
  var workoutSession = new HKWorkoutSession (configuration, out error);

  // Successful?
  if (error != null) {
    // Report error to user and return
    return;
  }

  // Create workout session delegate and wire-up events
  RunDelegate = new OutdoorRunDelegate (HealthStore, workoutSession);

  RunDelegate.Failed += () => {
    // Handle the session failing
  };

  RunDelegate.Paused += () => {
    // Handle the session being paused
  };

  RunDelegate.Running += () => {
    // Handle the session running
  };

  RunDelegate.Ended += () => {
    // Handle the session ending
  };

  // Start session
  HealthStore.StartWorkoutSession (workoutSession);
}

Uygulama bu Antrenman Oturumunu başlatırsa ve kullanıcı saat yüzüne geri dönerse, yüzün üzerinde küçük bir yeşil "çalışan adam" simgesi görüntülenir:

Yüzün üzerinde küçük bir yeşil koşan adam simgesi görüntüleniyor

Kullanıcı bu simgeye dokunursa uygulamaya geri döner.

Veri Toplama ve Denetim

Bir Antrenman Oturumu yapılandırılıp başlatıldıktan sonra uygulamanın oturum hakkında veri toplaması (kullanıcının kalp atış hızı gibi) ve oturumun durumunu denetlemesi gerekir:

Veri Toplama ve Denetim Diyagramı

  1. Örnekleri Gözlemleme - Uygulamanın HealthKit'ten üzerinde işlem yapılacak ve kullanıcıya görüntülenecek bilgileri alması gerekir.
  2. Olayları Gözlemleme - Uygulamanın HealthKit tarafından veya uygulamanın kullanıcı arabiriminden (egzersizi duraklatan kullanıcı gibi) oluşturulan olaylara yanıt vermesi gerekir.
  3. Çalışıyor Durumunu Girin - Oturum başlatıldı ve şu anda çalışıyor.
  4. Duraklatılmış Durum Girin - Kullanıcı geçerli antrenman oturumunu duraklatmıştır ve daha sonraki bir tarihte yeniden başlatabilir. Kullanıcı, tek bir Antrenman Oturumunda çalışan ve duraklatılan durumlar arasında birkaç kez geçiş yapabilir.
  5. Egzersiz Oturumunu Sonlandır - Herhangi bir noktada kullanıcı Egzersiz Oturumunu sonlandırabilir veya tarifeli bir egzersiz ise (iki mil koşu gibi) süresi dolabilir ve kendi başına sona erebilir.

Son adım, Antrenman Oturumu sonuçlarını kullanıcının HealthKit veri deposuna kaydetmektir.

HealthKit Örneklerini Gözlemleme

Uygulamanın ilgilendiği her HealthKit veri noktası için kalp atış hızı veya yakılan aktif enerji gibi bir Anchor Nesne Sorgusu açması gerekir. Gözlemlenen her veri noktası için, uygulamaya gönderilirken yeni verileri yakalamak için bir güncelleştirme işleyicisi oluşturulması gerekir.

Bu veri noktalarından uygulama toplamları (toplam çalışma mesafesi gibi) birikebilir ve kullanıcı arabirimini gerektiği gibi güncelleştirebilir. Ayrıca uygulama, belirli bir hedefe veya başarıya ulaştıklarında (bir çalıştırmanın sonraki milini tamamlama gibi) kullanıcılara bildirimde bulunabilir.

Aşağıdaki örnek koda göz atın:

private void ObserveHealthKitSamples ()
{
  // Get the starting date of the required samples
  var datePredicate = HKQuery.GetPredicateForSamples (WorkoutSession.StartDate, null, HKQueryOptions.StrictStartDate);

  // Get data from the local device
  var devices = new NSSet<HKDevice> (new HKDevice [] { HKDevice.LocalDevice });
  var devicePredicate = HKQuery.GetPredicateForObjectsFromDevices (devices);

  // Assemble compound predicate
  var queryPredicate = NSCompoundPredicate.CreateAndPredicate (new NSPredicate [] { datePredicate, devicePredicate });

  // Get ActiveEnergyBurned
  var queryActiveEnergyBurned = new HKAnchoredObjectQuery (HKQuantityType.Create (HKQuantityTypeIdentifier.ActiveEnergyBurned), queryPredicate, null, HKSampleQuery.NoLimit, (query, addedObjects, deletedObjects, newAnchor, error) => {
    // Valid?
    if (error == null) {
      // Yes, process all returned samples
      foreach (HKSample sample in addedObjects) {
        var quantitySample = sample as HKQuantitySample;
        ActiveEnergyBurned += quantitySample.Quantity.GetDoubleValue (HKUnit.Joule);
      }

      // Update User Interface
      ...
    }
  });

  // Start Query
  HealthStore.ExecuteQuery (queryActiveEnergyBurned);

}

Yöntemini kullanarak GetPredicateForSamples veri almak istediği başlangıç tarihini ayarlamak için bir koşul oluşturur. Yöntemi kullanarak GetPredicateForObjectsFromDevices HealthKit bilgilerini çekmek için bir cihaz kümesi oluşturur, bu durumda yalnızca yerel Apple Watch (HKDevice.LocalDevice). İki koşul, yöntemi kullanılarak CreateAndPredicate bir Bileşik Koşulda (NSCompoundPredicate) birleştirilir.

İstenen veri noktası için bir yeni HKAnchoredObjectQuery oluşturulur (bu örnekte HKQuantityTypeIdentifier.ActiveEnergyBurned Etkin Enerji Yakılan veri noktası için), döndürülenHKSampleQuery.NoLimit () veri miktarına bir sınır uygulanmaz ve HealthKit'ten uygulamaya döndürülen verileri işlemek için bir güncelleştirme işleyicisi tanımlanır.

Güncelleştirme işleyicisi, belirli bir veri noktası için uygulamaya yeni veriler her teslim edilişinde çağrılır. Hata döndürülmezse uygulama verileri güvenle okuyabilir, gerekli hesaplamaları yapabilir ve kullanıcı arabirimini gerektiği gibi güncelleştirebilir.

Kod, dizide döndürülen tüm örnekleri (HKSample) döngüye addedObjects alır ve bunları Bir Miktar Örneğine (HKQuantitySample ) dönüştürür. Ardından, örneğin çift değerini bir joule (HKUnit.Joule) olarak alır ve egzersiz için yakılan aktif enerjinin çalışan toplamına biriktirir ve Kullanıcı Arabirimini güncelleştirir.

Ulaşılan Hedef Bildirimi

Yukarıda belirtildiği gibi, kullanıcı antrenman uygulamasında bir hedefe ulaştığı zaman (bir çalıştırmanın ilk milini tamamlamak gibi), Taptic Engine aracılığıyla kullanıcıya dokunsal geri bildirim gönderebilir. Kullanıcı, geri bildirimi soran olayı görmek için büyük olasılıkla bileğini kaldıracağı için uygulamanın kullanıcı arabirimini de bu noktada güncelleştirmesi gerekir.

Dokunsal geri bildirimi yürütmek için aşağıdaki kodu kullanın:

// Play haptic feedback
WKInterfaceDevice.CurrentDevice.PlayHaptic (WKHapticType.Notification);

Olayları Gözlemleme

Olaylar, uygulamanın kullanıcının antrenmanı sırasında belirli noktaları vurgulamak için kullanabileceği zaman damgalarıdır. Bazı etkinlikler doğrudan uygulama tarafından oluşturulur ve antrenmana kaydedilir ve bazı etkinlikler HealthKit tarafından otomatik olarak oluşturulur.

HealthKit tarafından oluşturulan olayları gözlemlemek için, uygulama yöntemini HKWorkoutSessionDelegategeçersiz kılarDidGenerateEvent:

using System.Collections.Generic;
...

public List<HKWorkoutEvent> WorkoutEvents { get; set; } = new List<HKWorkoutEvent> ();
...

public override void DidGenerateEvent (HKWorkoutSession workoutSession, HKWorkoutEvent @event)
{
  base.DidGenerateEvent (workoutSession, @event);

  // Save HealthKit generated event
  WorkoutEvents.Add (@event);

  // Take action based on the type of event
  switch (@event.Type) {
  case HKWorkoutEventType.Lap:
    break;
  case HKWorkoutEventType.Marker:
    break;
  case HKWorkoutEventType.MotionPaused:
    break;
  case HKWorkoutEventType.MotionResumed:
    break;
  case HKWorkoutEventType.Pause:
    break;
  case HKWorkoutEventType.Resume:
    break;
  }
}

Apple, watchOS 3'te aşağıdaki yeni olay türlerini eklemiştir:

  • HKWorkoutEventType.Lap - Antrenmanı eşit mesafe bölümlerine bölen olaylar içindir. Örneğin, koşu sırasında bir tur boyunca bir tur işaretlemek için.
  • HKWorkoutEventType.Marker - Egzersiz içinde rastgele ilgi çekici noktalar içindir. Örneğin, bir dış mekan koşusunun rotası üzerinde belirli bir noktaya ulaşmak.

Bu yeni türler uygulama tarafından oluşturulabilir ve grafik ve istatistik oluşturmada daha sonra kullanmak üzere antrenmanda depolanabilir.

İşaretçi Olayı oluşturmak için aşağıdakileri yapın:

using System.Collections.Generic;
...

public float MilesRun { get; set; }
public List<HKWorkoutEvent> WorkoutEvents { get; set; } = new List<HKWorkoutEvent> ();
...

public void ReachedNextMile ()
{
  // Create and save marker event
  var markerEvent = HKWorkoutEvent.Create (HKWorkoutEventType.Marker, NSDate.Now);
  WorkoutEvents.Add (markerEvent);

  // Notify user
  NotifyUserOfReachedMileGoal (++MilesRun);
}

Bu kod, bir İşaretçi Olayının (HKWorkoutEvent) yeni bir örneğini oluşturur ve bunu özel bir olay koleksiyonuna kaydeder (daha sonra Antrenman Oturumuna yazılır) ve dokunsal aracılığıyla olayı kullanıcıya bildirir.

Antrenmanları Duraklatma ve Devam Ettir

Bir egzersiz oturumunun herhangi bir noktasında, kullanıcı antrenmanı geçici olarak duraklatabilir ve daha sonra devam ettirebilir. Örneğin, önemli bir çağrı almak ve arama tamamlandıktan sonra çalıştırmayı sürdürmek için iç mekan çalıştırmasını duraklatabilir.

Uygulamanın kullanıcı arabirimi, Kullanıcı etkinliğini askıya alırken Apple Watch'un hem güç hem de veri alanından tasarruf edebilmesi için antrenmanı duraklatmak ve sürdürmek için bir yol sağlamalıdır (HealthKit'e arayarak). Ayrıca uygulama, Antrenman Oturumu duraklatılmış durumdayken alınabilecek yeni veri noktalarını yoksaymalıdır.

HealthKit, Duraklat ve Sürdür olayları oluşturarak duraklatma ve sürdürme çağrılarına yanıt verir. Antrenman Oturumu duraklatılırken, oturum devam edene kadar HealthKit tarafından uygulamaya yeni olay veya veri gönderilmez.

Bir Antrenman Oturumunu duraklatmak ve sürdürmek için aşağıdaki kodu kullanın:

public HKHealthStore HealthStore { get; set;} = new HKHealthStore ();
public HKWorkoutSession WorkoutSession { get; set;}
...

public void PauseWorkout ()
{
  // Pause the current workout
  HealthStore.PauseWorkoutSession (WorkoutSession);
}

public void ResumeWorkout ()
{
  // Pause the current workout
  HealthStore.ResumeWorkoutSession (WorkoutSession);
}

HealthKit'ten oluşturulacak Duraklatma ve Sürdürme olayları, yöntemini HKWorkoutSessionDelegategeçersiz kılarak DidGenerateEvent işlenebilir:

public override void DidGenerateEvent (HKWorkoutSession workoutSession, HKWorkoutEvent @event)
{
  base.DidGenerateEvent (workoutSession, @event);

  // Take action based on the type of event
  switch (@event.Type) {
  case HKWorkoutEventType.Pause:
    break;
  case HKWorkoutEventType.Resume:
    break;
  }
}

Hareket Olayları

WatchOS 3'e yeni eklenenler arasında Hareket Duraklatıldı (HKWorkoutEventType.MotionPaused) ve Hareket Sürdürüldü (HKWorkoutEventType.MotionResumed) olayları yer alır. Bu olaylar, kullanıcı hareket etmeye başladığında ve durduğunda çalışan bir antrenman sırasında HealthKit tarafından otomatik olarak oluşturulur.

Uygulama Bir Hareket Duraklatıldı olayı aldığında, kullanıcı hareketi sürdürene ve Hareket Özgeçmişleri olayı alınana kadar veri toplamayı durdurması gerekir. Uygulama, Hareket Duraklatıldı olayına yanıt olarak Antrenman oturumunu duraklatmamalıdır.

Önemli

Hareket Duraklatıldı ve Hareket Sürdürme olayları yalnızca RunningWorkout Etkinlik Türü (HKWorkoutActivityType.Running) için desteklenir.

Bu olaylar yine yöntemini HKWorkoutSessionDelegategeçersiz kılarak DidGenerateEvent işlenebilir:

public override void DidGenerateEvent (HKWorkoutSession workoutSession, HKWorkoutEvent @event)
{
  base.DidGenerateEvent (workoutSession, @event);

  // Take action based on the type of event
  switch (@event.Type) {
  case HKWorkoutEventType.MotionPaused:
    break;
  case HKWorkoutEventType.MotionResumed:
    break;
  }
}

Antrenman Oturumunu Sonlandırma ve Kaydetme

Kullanıcı antrenmanını tamamladığında, uygulamanın geçerli Antrenman Oturumu'na son vermesi ve HealthKit veritabanına kaydetmesi gerekir. HealthKit'e kaydedilen antrenmanlar otomatik olarak Antrenman Etkinlik Listesi'nde görüntülenir.

iOS 10'da yeni olan bu liste, kullanıcının i Telefon'sinde Egzersiz Etkinliği Listesi'ni de içerir. Bu nedenle Apple Watch yakında olmasa bile, egzersiz telefonda sunulacaktır.

Enerji Örnekleri içeren egzersizler, 3. taraf uygulamaların artık kullanıcının günlük Taşıma hedeflerine katkıda bulunabilmesi için Etkinlikler uygulamasında kullanıcının Taşıma Halkasını güncelleştirir.

Bir Antrenman Oturumunu sonlandırmak ve kaydetmek için aşağıdaki adımlar gereklidir:

Antrenman Oturumu Diyagramını Sonlandırma ve Kaydetme

  1. İlk olarak, uygulamanın Antrenman Oturumu'na son vermesi gerekir.
  2. Antrenman Oturumu HealthKit'e kaydedilir.
  3. Kaydedilen Antrenman Oturumuna herhangi bir örneği (yakılan enerji veya mesafe gibi) ekleyin.

Oturumu Sonlandırma

Antrenman Oturumunu sonlandırmak için, öğesini geçirme yöntemini HKHealthStore çağırın:EndWorkoutSessionHKWorkoutSession

public HKHealthStore HealthStore { get; private set; }
public HKWorkoutSession WorkoutSession { get; private set;}
...

public void EndOutdoorRun ()
{
  // End the current workout session
  HealthStore.EndWorkoutSession (WorkoutSession);
}

Bu, cihaz algılayıcılarını normal modlarına sıfırlar. HealthKit, antrenmanı sonlandırmayı bitirdiğinde yönteminin geri DidChangeToState çağrısını HKWorkoutSessionDelegatealır:

public override void DidChangeToState (HKWorkoutSession workoutSession, HKWorkoutSessionState toState, HKWorkoutSessionState fromState, NSDate date)
{
  // Take action based on the change in state
  switch (toState) {
  ...
  case HKWorkoutSessionState.Ended:
    StopObservingHealthKitSamples ();
    RaiseEnded ();
    break;
  }

}

Oturumu Kaydetme

Uygulama Antrenman Oturumu'nun sona erdikten sonra bir Antrenman () oluşturması ve bunu (HKWorkoutbir etkinlikle birlikte) HealthKit veri deposuna (HKHealthStore):

public HKHealthStore HealthStore { get; private set; }
public HKWorkoutSession WorkoutSession { get; private set;}
public float MilesRun { get; set; }
public double ActiveEnergyBurned { get; set;}
public List<HKWorkoutEvent> WorkoutEvents { get; set; } = new List<HKWorkoutEvent> ();
...

private void SaveWorkoutSession ()
{
  // Build required workout quantities
  var energyBurned = HKQuantity.FromQuantity (HKUnit.Joule, ActiveEnergyBurned);
  var distance = HKQuantity.FromQuantity (HKUnit.Mile, MilesRun);

  // Create any required metadata
  var metadata = new NSMutableDictionary ();
  metadata.Add (new NSString ("HKMetadataKeyIndoorWorkout"), new NSString ("NO"));

  // Create workout
  var workout = HKWorkout.Create (HKWorkoutActivityType.Running,
                                  WorkoutSession.StartDate,
                                  NSDate.Now,
                                  WorkoutEvents.ToArray (),
                                  energyBurned,
                                  distance,
                                  metadata);

  // Save to HealthKit
  HealthStore.SaveObject (workout, (successful, error) => {
    // Handle any errors
    if (error == null) {
      // Was the save successful
      if (successful) {

      }
    } else {
      // Report error
    }
  });

}

Bu kod, egzersiz için yakılan toplam enerji miktarını ve mesafeyi nesne olarak HKQuantity oluşturur. Antrenmanı tanımlayan meta veri sözlüğü oluşturulur ve antrenmanın konumu belirtilir:

metadata.Add (new NSString ("HKMetadataKeyIndoorWorkout"), new NSString ("NO"));

yeni HKWorkout bir nesne, ile aynı HKWorkoutActivityTypeHKWorkoutSessionile oluşturulur, başlangıç ve bitiş tarihleri, olay listesi (yukarıdaki bölümlerden birikir), yakılan enerji, toplam uzaklık ve meta veri sözlüğü. Bu nesne Sistem Durumu Deposu'na kaydedilir ve işlenen tüm hatalar.

Örnek Ekleme

Uygulama bir dizi örneği antrenmana kaydettiğinde HealthKit, örneklerle Antrenmanın kendisi arasında bir bağlantı oluşturur, böylece uygulama belirli bir antrenmanla ilişkili tüm örnekler için Daha sonraki bir tarihte HealthKit'i sorgulayabilir. Bu bilgileri kullanarak uygulama, antrenman verilerinden grafikler oluşturabilir ve bunları bir egzersiz zaman çizelgesine göre çizebilir.

Bir uygulamanın Etkinlik uygulamasının Taşıma Halkasına katkıda bulunması için kaydedilen egzersizle birlikte enerji örneklerini içermesi gerekir. Ayrıca, mesafe ve enerji toplamları, uygulamanın kaydedilmiş bir antrenmanla ilişkilendirdiği örneklerin toplamıyla eşleşmelidir.

Kaydedilmiş bir antrenmana örnek eklemek için aşağıdakileri yapın:

using System.Collections.Generic;
using WatchKit;
using HealthKit;
...

public HKHealthStore HealthStore { get; private set; }
public List<HKSample> WorkoutSamples { get; set; } = new List<HKSample> ();
...

private void SaveWorkoutSamples (HKWorkout workout)
{
  // Add samples to saved workout
  HealthStore.AddSamples (WorkoutSamples.ToArray (), workout, (success, error) => {
    // Handle any errors
    if (error == null) {
      // Was the save successful
      if (success) {

      }
    } else {
      // Report error
    }
  });
}

İsteğe bağlı olarak, uygulama daha küçük bir örnek alt kümesini veya kaydedilmiş antrenmanla ilişkilendirilen bir mega örneği (tüm antrenman aralığını kapsayan) hesaplayabilir ve oluşturabilir.

Antrenmanlar ve iOS 10

Her watchOS 3 antrenman uygulamasının ana iOS 10 tabanlı bir antrenman uygulaması vardır ve iOS 10'da yeni olan bu iOS uygulaması, Apple Watch'u Antrenman Modu'na yerleştirecek (kullanıcı müdahalesi olmadan) ve watchOS uygulamasını Arka Plan Çalıştırma modunda çalıştıracak bir antrenman başlatmak için kullanılabilir (daha fazla ayrıntı için yukarıdaki Arka Plan Çalıştırma Hakkında bölümüne bakın).

watchOS uygulaması çalışırken, üst iOS uygulamasıyla mesajlaşma ve iletişim için Watch Bağlan ivity kullanabilir.

Bu işlemin nasıl çalıştığına göz atın:

i Telefon ve Apple Watch iletişim diyagramı

  1. i Telefon uygulaması bir HKWorkoutConfiguration nesne oluşturur ve Antrenman Türü ile Konumu ayarlar.
  2. HKWorkoutConfiguration Nesne, uygulamanın Apple Watch sürümüne gönderilir ve henüz çalışmıyorsa sistem tarafından başlatılır.
  3. Geçirilen Antrenman Yapılandırması'nı kullanarak watchOS 3 uygulaması yeni bir Antrenman Oturumu (HKWorkoutSession ) başlatır.

Önemli

Ebeveyn i Telefon uygulamasının Apple Watch'ta bir antrenman başlatması için watchOS 3 uygulamasında Arka Plan Çalışıyor özelliğinin etkin olması gerekir. Daha fazla ayrıntı için lütfen yukarıdaki Arka Plan Çalıştırmayı Etkinleştirme bölümüne bakın.

Bu işlem, doğrudan watchOS 3 uygulamasında Egzersiz Oturumu başlatma işlemine çok benzer. i Telefon aşağıdaki kodu kullanın:

using System;
using HealthKit;
using WatchConnectivity;
...

#region Computed Properties
public HKHealthStore HealthStore { get; set; } = new HKHealthStore ();
public WCSession ConnectivitySession { get; set; } = WCSession.DefaultSession;
#endregion
...

private void StartOutdoorRun ()
{
  // Can the app communicate with the watchOS version of the app?
  if (ConnectivitySession.ActivationState == WCSessionActivationState.Activated && ConnectivitySession.WatchAppInstalled) {
    // Create a workout configuration
    var configuration = new HKWorkoutConfiguration () {
      ActivityType = HKWorkoutActivityType.Running,
      LocationType = HKWorkoutSessionLocationType.Outdoor
    };

    // Start watch app
    HealthStore.StartWatchApp (configuration, (success, error) => {
      // Handle any errors
      if (error == null) {
        // Was the save successful
        if (success) {
          ...
        }
      } else {
        // Report error
        ...
      }
    });
  }
}

Bu kod, uygulamanın watchOS sürümünün yüklenmesini ve i Telefon sürümünün önce buna bağlanmasını sağlar:

if (ConnectivitySession.ActivationState == WCSessionActivationState.Activated && ConnectivitySession.WatchAppInstalled) {
  ...
}

Ardından her zamanki gibi bir HKWorkoutConfiguration oluşturur ve apple watch'a göndermek ve uygulamayı ve Antrenman Oturumu'na başlatmak için yöntemini HKHealthStore kullanırStartWatchApp.

watch işletim sistemi uygulamasında da WKExtensionDelegateiçinde aşağıdaki kodu kullanın:

using WatchKit;
using HealthKit;
...

#region Computed Properties
public HKHealthStore HealthStore { get; set;} = new HKHealthStore ();
public OutdoorRunDelegate RunDelegate { get; set; }
#endregion
...

public override void HandleWorkoutConfiguration (HKWorkoutConfiguration workoutConfiguration)
{
  // Create workout session
  // Start workout session
  NSError error = null;
  var workoutSession = new HKWorkoutSession (workoutConfiguration, out error);

  // Successful?
  if (error != null) {
    // Report error to user and return
    return;
  }

  // Create workout session delegate and wire-up events
  RunDelegate = new OutdoorRunDelegate (HealthStore, workoutSession);

  RunDelegate.Failed += () => {
    // Handle the session failing
  };

  RunDelegate.Paused += () => {
    // Handle the session being paused
  };

  RunDelegate.Running += () => {
    // Handle the session running
  };

  RunDelegate.Ended += () => {
    // Handle the session ending
  };

  // Start session
  HealthStore.StartWorkoutSession (workoutSession);
}

öğesini alır HKWorkoutConfiguration ve yeni HKWorkoutSession bir oluşturur ve özel HKWorkoutSessionDelegateöğesinin bir örneğini ekler. Kullanıcının HealthKit Health Store'unun antrenman oturumu başlatılır.

Tüm Parçaları Bir Araya Getirme

Bu belgede sunulan tüm bilgileri alarak, watchOS 3 tabanlı bir egzersiz uygulaması ve ana iOS 10 tabanlı egzersiz uygulaması aşağıdaki bölümleri içerebilir:

  1. iOS 10 ViewController.cs - Apple Watch'ta watch Bağlan ivity oturumunu ve antrenmanı başlatır.
  2. watchOS 3 ExtensionDelegate.cs - Antrenman uygulamasının watchOS 3 sürümünü işler.
  3. watchOS 3 OutdoorRunDelegate.cs - Antrenman olaylarını işlemek için özel HKWorkoutSessionDelegate bir öğedir.

Önemli

Aşağıdaki bölümlerde gösterilen kod yalnızca watchOS 3'teki Antrenman uygulamalarına sağlanan yeni, gelişmiş özellikleri uygulamak için gereken parçaları içerir. Tüm destekleyici kodlar ve kullanıcı arabirimini sunmak ve güncelleştirmek için kod dahil değildir, ancak diğer watchOS belgelerimiz izlenerek kolayca oluşturulabilir.

ViewController.cs

ViewController.cs Antrenman uygulamasının üst iOS 10 sürümündeki dosya aşağıdaki kodu içerir:

using System;
using HealthKit;
using UIKit;
using WatchConnectivity;

namespace MonkeyWorkout
{
  public partial class ViewController : UIViewController
  {
    #region Computed Properties
    public HKHealthStore HealthStore { get; set; } = new HKHealthStore ();
    public WCSession ConnectivitySession { get; set; } = WCSession.DefaultSession;
    #endregion

    #region Constructors
    protected ViewController (IntPtr handle) : base (handle)
    {
      // Note: this .ctor should not contain any initialization logic.
    }
    #endregion

    #region Private Methods
    private void InitializeWatchConnectivity ()
    {
      // Is Watch Connectivity supported?
      if (!WCSession.IsSupported) {
        // No, abort
        return;
      }

      // Is the session already active?
      if (ConnectivitySession.ActivationState != WCSessionActivationState.Activated) {
        // No, start session
        ConnectivitySession.ActivateSession ();
      }
    }

    private void StartOutdoorRun ()
    {
      // Can the app communicate with the watchOS version of the app?
      if (ConnectivitySession.ActivationState == WCSessionActivationState.Activated && ConnectivitySession.WatchAppInstalled) {
        // Create a workout configuration
        var configuration = new HKWorkoutConfiguration () {
          ActivityType = HKWorkoutActivityType.Running,
          LocationType = HKWorkoutSessionLocationType.Outdoor
        };

        // Start watch app
        HealthStore.StartWatchApp (configuration, (success, error) => {
          // Handle any errors
          if (error == null) {
            // Was the save successful
            if (success) {
              ...
            }
          } else {
            // Report error
            ...
          }
        });
      }
    }
    #endregion

    #region Override Methods
    public override void ViewDidLoad ()
    {
      base.ViewDidLoad ();

      // Start Watch Connectivity
      InitializeWatchConnectivity ();
    }
    #endregion
  }
}

ExtensionDelegate.cs

ExtensionDelegate.cs Antrenman uygulamasının watchOS 3 sürümündeki dosya aşağıdaki kodu içerir:

using System;
using Foundation;
using WatchKit;
using HealthKit;

namespace MonkeyWorkout.MWWatchExtension
{
  public class ExtensionDelegate : WKExtensionDelegate
  {
    #region Computed Properties
    public HKHealthStore HealthStore { get; set;} = new HKHealthStore ();
    public OutdoorRunDelegate RunDelegate { get; set; }
    #endregion

    #region Constructors
    public ExtensionDelegate ()
    {

    }
    #endregion

    #region Private Methods
    private void StartWorkoutSession (HKWorkoutConfiguration workoutConfiguration)
    {
      // Create workout session
      // Start workout session
      NSError error = null;
      var workoutSession = new HKWorkoutSession (workoutConfiguration, out error);

      // Successful?
      if (error != null) {
        // Report error to user and return
        return;
      }

      // Create workout session delegate and wire-up events
      RunDelegate = new OutdoorRunDelegate (HealthStore, workoutSession);

      RunDelegate.Failed += () => {
        // Handle the session failing
        ...
      };

      RunDelegate.Paused += () => {
        // Handle the session being paused
        ...
      };

      RunDelegate.Running += () => {
        // Handle the session running
        ...
      };

      RunDelegate.Ended += () => {
        // Handle the session ending
        ...
      };

      RunDelegate.ReachedMileGoal += (miles) => {
        // Handle the reaching a session goal
        ...
      };

      RunDelegate.HealthKitSamplesUpdated += () => {
        // Update UI as required
        ...
      };

      // Start session
      HealthStore.StartWorkoutSession (workoutSession);
    }

    private void StartOutdoorRun ()
    {
      // Create a workout configuration
      var workoutConfiguration = new HKWorkoutConfiguration () {
        ActivityType = HKWorkoutActivityType.Running,
        LocationType = HKWorkoutSessionLocationType.Outdoor
      };

      // Start the session
      StartWorkoutSession (workoutConfiguration);
    }
    #endregion

    #region Override Methods
    public override void HandleWorkoutConfiguration (HKWorkoutConfiguration workoutConfiguration)
    {
      // Start the session
      StartWorkoutSession (workoutConfiguration);
    }
    #endregion
  }
}

OutdoorRunDelegate.cs

OutdoorRunDelegate.cs Antrenman uygulamasının watchOS 3 sürümündeki dosya aşağıdaki kodu içerir:

using System;
using System.Collections.Generic;
using Foundation;
using WatchKit;
using HealthKit;

namespace MonkeyWorkout.MWWatchExtension
{
  public class OutdoorRunDelegate : HKWorkoutSessionDelegate
  {
    #region Private Variables
    private HKAnchoredObjectQuery QueryActiveEnergyBurned;
    #endregion

    #region Computed Properties
    public HKHealthStore HealthStore { get; private set; }
    public HKWorkoutSession WorkoutSession { get; private set;}
    public float MilesRun { get; set; }
    public double ActiveEnergyBurned { get; set;}
    public List<HKWorkoutEvent> WorkoutEvents { get; set; } = new List<HKWorkoutEvent> ();
    public List<HKSample> WorkoutSamples { get; set; } = new List<HKSample> ();
    #endregion

    #region Constructors
    public OutdoorRunDelegate (HKHealthStore healthStore, HKWorkoutSession workoutSession)
    {
      // Initialize
      this.HealthStore = healthStore;
      this.WorkoutSession = workoutSession;

      // Attach this delegate to the session
      workoutSession.Delegate = this;

    }
    #endregion

    #region Private Methods
    private void ObserveHealthKitSamples ()
    {
      // Get the starting date of the required samples
      var datePredicate = HKQuery.GetPredicateForSamples (WorkoutSession.StartDate, null, HKQueryOptions.StrictStartDate);

      // Get data from the local device
      var devices = new NSSet<HKDevice> (new HKDevice [] { HKDevice.LocalDevice });
      var devicePredicate = HKQuery.GetPredicateForObjectsFromDevices (devices);

      // Assemble compound predicate
      var queryPredicate = NSCompoundPredicate.CreateAndPredicate (new NSPredicate [] { datePredicate, devicePredicate });

      // Get ActiveEnergyBurned
      QueryActiveEnergyBurned = new HKAnchoredObjectQuery (HKQuantityType.Create (HKQuantityTypeIdentifier.ActiveEnergyBurned), queryPredicate, null, HKSampleQuery.NoLimit, (query, addedObjects, deletedObjects, newAnchor, error) => {
        // Valid?
        if (error == null) {
          // Yes, process all returned samples
          foreach (HKSample sample in addedObjects) {
            // Accumulate totals
            var quantitySample = sample as HKQuantitySample;
            ActiveEnergyBurned += quantitySample.Quantity.GetDoubleValue (HKUnit.Joule);

            // Save samples
            WorkoutSamples.Add (sample);
          }

          // Inform caller
          RaiseHealthKitSamplesUpdated ();
        }
      });

      // Start Query
      HealthStore.ExecuteQuery (QueryActiveEnergyBurned);

    }

    private void StopObservingHealthKitSamples ()
    {
      // Stop query
      HealthStore.StopQuery (QueryActiveEnergyBurned);
    }

    private void ResumeObservingHealthkitSamples ()
    {
      // Resume current queries
      HealthStore.ExecuteQuery (QueryActiveEnergyBurned);
    }

    private void NotifyUserOfReachedMileGoal (float miles)
    {
      // Play haptic feedback
      WKInterfaceDevice.CurrentDevice.PlayHaptic (WKHapticType.Notification);

      // Raise event
      RaiseReachedMileGoal (miles);
    }

    private void SaveWorkoutSession ()
    {
      // Build required workout quantities
      var energyBurned = HKQuantity.FromQuantity (HKUnit.Joule, ActiveEnergyBurned);
      var distance = HKQuantity.FromQuantity (HKUnit.Mile, MilesRun);

      // Create any required metadata
      var metadata = new NSMutableDictionary ();
      metadata.Add (new NSString ("HKMetadataKeyIndoorWorkout"), new NSString ("NO"));

      // Create workout
      var workout = HKWorkout.Create (HKWorkoutActivityType.Running,
                                      WorkoutSession.StartDate,
                                      NSDate.Now,
                                      WorkoutEvents.ToArray (),
                                      energyBurned,
                                      distance,
                                      metadata);

      // Save to HealthKit
      HealthStore.SaveObject (workout, (successful, error) => {
        // Handle any errors
        if (error == null) {
          // Was the save successful
          if (successful) {
            // Add samples to workout
            SaveWorkoutSamples (workout);
          }
        } else {
          // Report error
          ...
        }
      });

    }

    private void SaveWorkoutSamples (HKWorkout workout)
    {
      // Add samples to saved workout
      HealthStore.AddSamples (WorkoutSamples.ToArray (), workout, (success, error) => {
        // Handle any errors
        if (error == null) {
          // Was the save successful
          if (success) {
            ...
          }
        } else {
          // Report error
          ...
        }
      });
    }
    #endregion

    #region Public Methods
    public void PauseWorkout ()
    {
      // Pause the current workout
      HealthStore.PauseWorkoutSession (WorkoutSession);
    }

    public void ResumeWorkout ()
    {
      // Pause the current workout
      HealthStore.ResumeWorkoutSession (WorkoutSession);
    }

    public void ReachedNextMile ()
    {
      // Create and save marker event
      var markerEvent = HKWorkoutEvent.Create (HKWorkoutEventType.Marker, NSDate.Now);
      WorkoutEvents.Add (markerEvent);

      // Notify user
      NotifyUserOfReachedMileGoal (++MilesRun);
    }

    public void EndOutdoorRun ()
    {
      // End the current workout session
      HealthStore.EndWorkoutSession (WorkoutSession);
    }
    #endregion

    #region Override Methods
    public override void DidFail (HKWorkoutSession workoutSession, NSError error)
    {
      // Handle workout session failing
      RaiseFailed ();
    }

    public override void DidChangeToState (HKWorkoutSession workoutSession, HKWorkoutSessionState toState, HKWorkoutSessionState fromState, NSDate date)
    {
      // Take action based on the change in state
      switch (toState) {
      case HKWorkoutSessionState.NotStarted:
        break;
      case HKWorkoutSessionState.Paused:
        StopObservingHealthKitSamples ();
        RaisePaused ();
        break;
      case HKWorkoutSessionState.Running:
        if (fromState == HKWorkoutSessionState.Paused) {
          ResumeObservingHealthkitSamples ();
        } else {
          ObserveHealthKitSamples ();
        }
        RaiseRunning ();
        break;
      case HKWorkoutSessionState.Ended:
        StopObservingHealthKitSamples ();
        SaveWorkoutSession ();
        RaiseEnded ();
        break;
      }

    }

    public override void DidGenerateEvent (HKWorkoutSession workoutSession, HKWorkoutEvent @event)
    {
      base.DidGenerateEvent (workoutSession, @event);

      // Save HealthKit generated event
      WorkoutEvents.Add (@event);

      // Take action based on the type of event
      switch (@event.Type) {
      case HKWorkoutEventType.Lap:
        ...
        break;
      case HKWorkoutEventType.Marker:
        ...
        break;
      case HKWorkoutEventType.MotionPaused:
        ...
        break;
      case HKWorkoutEventType.MotionResumed:
        ...
        break;
      case HKWorkoutEventType.Pause:
        ...
        break;
      case HKWorkoutEventType.Resume:
        ...
        break;
      }
    }
    #endregion

    #region Events
    public delegate void OutdoorRunEventDelegate ();
    public delegate void OutdoorRunMileGoalDelegate (float miles);

    public event OutdoorRunEventDelegate Failed;
    internal void RaiseFailed ()
    {
      if (this.Failed != null) this.Failed ();
    }

    public event OutdoorRunEventDelegate Paused;
    internal void RaisePaused ()
    {
      if (this.Paused != null) this.Paused ();
    }

    public event OutdoorRunEventDelegate Running;
    internal void RaiseRunning ()
    {
      if (this.Running != null) this.Running ();
    }

    public event OutdoorRunEventDelegate Ended;
    internal void RaiseEnded ()
    {
      if (this.Ended != null) this.Ended ();
    }

    public event OutdoorRunMileGoalDelegate ReachedMileGoal;
    internal void RaiseReachedMileGoal (float miles)
    {
      if (this.ReachedMileGoal != null) this.ReachedMileGoal (miles);
    }

    public event OutdoorRunEventDelegate HealthKitSamplesUpdated;
    internal void RaiseHealthKitSamplesUpdated ()
    {
      if (this.HealthKitSamplesUpdated != null) this.HealthKitSamplesUpdated ();
    }
    #endregion
  }
}

En İyi Uygulamalar

Apple, watchOS 3 ve iOS 10'da Antrenman uygulamaları tasarlarken ve uygularken aşağıdaki en iyi yöntemlerin kullanılmasını önerir:

  • watchOS 3 Antrenman uygulamasının i Telefon ve uygulamanın iOS 10 sürümüne bağlanamadığında bile çalışır durumda olduğundan emin olun.
  • GPS olmadan mesafe örnekleri oluşturabildiği için GPS kullanılamadığında HealthKit mesafesini kullanın.
  • Kullanıcının antrenmanı Apple Watch'tan veya i Telefon'den başlatmasına izin verin.
  • Uygulamanın geçmiş veri görünümlerinde diğer kaynaklardan (diğer üçüncü taraf uygulamalar gibi) egzersizleri görüntülemesine izin verin.
  • Uygulamanın silinen antrenmanları geçmiş verilerde göstermediğinden emin olun.

Özet

Bu makale, Apple'ın watchOS 3'teki antrenman uygulamaları için yaptığı geliştirmeleri ve bunları Xamarin'de nasıl uygulayacaklarını ele almıştır.