HealthKit en Xamarin. iOSHealthKit in Xamarin.iOS

El kit de mantenimiento proporciona un almacén de datos seguro para la información relacionada con el estado del usuario.Health Kit provides a secure datastore for the user’s health-related information. Las aplicaciones del kit de mantenimiento pueden, con el permiso explícito del usuario, leer y escribir en este almacén de datos y recibir notificaciones cuando se agregan los datos pertinentes.Health Kit apps may, with the user’s explicit permission, read and write to this datastore and receive notifications when pertinent data is added. Las aplicaciones pueden presentar los datos o el usuario puede usar la aplicación de mantenimiento proporcionada por Apple para ver un panel de todos sus datos.Apps can present the data, or user’s can use the Apple's provided Health app to view a dashboard of all their data.

Dado que los datos relacionados con el estado son tan confidenciales y fundamentales, el kit de mantenimiento está fuertemente tipado, con unidades de medida y una asociación explícita con el tipo de información que se registra (por ejemplo, el nivel de glucosa de la sangre o la tarifa cardíaca).Because health-related data is so sensitive and crucial, Health Kit is strongly typed, with units of measure and an explicit association with the type of information being recorded (for instance, blood glucose level or heart rate). Además, las aplicaciones del kit de mantenimiento deben usar derechos explícitos, deben solicitar acceso a los tipos concretos de información y el usuario debe conceder explícitamente a la aplicación acceso a esos tipos de datos.Additionally, Health Kit apps must use explicit entitlements, must request access to the particular types of information , and the user must explicitly grant the app access to those types of data.

En este artículo se presenta:This article will introduce:

  • Requisitos de seguridad del kit de mantenimiento, incluido el aprovisionamiento de aplicaciones y la solicitud de permiso de usuario para acceder a la base de datos del kit de mantenimiento;Health Kit’s security requirements, including application provisioning and requesting user permission to access the Health Kit database;
  • Sistema de tipos del kit de mantenimiento, lo que minimiza la posibilidad de que se apliquen o malinterpreten los datos.Health Kit’s type system, which minimizes the possibility of mis-applying or misinterpreting data;
  • Escribir en el almacén de almacenes de Estados de todo el sistema compartido.Writing to the shared, system-wide Health Kit datastore.

En este artículo no se abordarán temas más avanzados, como la consulta de la base de datos, la conversión entre unidades de medida o la recepción de notificaciones de datos nuevos.This article will not cover more advanced topics, such as querying the database, converting between units of measure, or receiving notifications of new data.

En este artículo, se creará una aplicación de ejemplo para registrar la tarifa cardíaca del usuario:In this article, we will be creating a sample application to record the user's heart rate:

RequisitosRequirements

Para completar los pasos que se describen en este artículo, es necesario lo siguiente:The following are required to complete the steps presented in this article:

  • Xcode 7 e iOS 8 (o superior) : las API de Xcode y iOS más recientes de Apple deben instalarse y configurarse en el equipo del desarrollador.Xcode 7 and iOS 8 (or greater) – Apple’s latest Xcode and iOS APIs need to be installed and configured on the developer’s computer.
  • Visual Studio para Mac o Visual Studio : la versión más reciente de Visual Studio para Mac debe estar instalada y configurada en el equipo del desarrollador.Visual Studio for Mac or Visual Studio – The latest version of Visual Studio for Mac should be installed and configured on the developer’s computer.
  • dispositivo iOS 8 (o superior) : dispositivo iOS que ejecuta la versión más reciente de iOS 8 o superior para realizar pruebas.iOS 8 (or greater) Device – An iOS device running the latest version of iOS 8 or greater for testing.

Importante

El kit de mantenimiento se presentó en iOS 8.Health Kit was introduced in iOS 8. Actualmente, el kit de mantenimiento no está disponible en el simulador de iOS y la depuración requiere conexión a un dispositivo iOS físico.Currently, Health Kit is not available on the iOS simulator, and debugging requires connection to a physical iOS device.

Crear y aprovisionar una aplicación del kit de mantenimientoCreating and Provisioning A Health Kit App

Antes de que una aplicación de Xamarin iOS 8 pueda usar la API de HealthKit, debe estar correctamente configurada y aprovisionada.Before a Xamarin iOS 8 application can use the HealthKit API, it must be properly configured and provisioned. En esta sección se explican los pasos necesarios para configurar correctamente la aplicación de Xamarin.This section will cover the steps required to properly setup your Xamarin Application.

Las aplicaciones del kit de mantenimiento requieren:Health Kit apps require:

  • Un identificador de aplicaciónexplícito.An explicit App ID.
  • Un Perfil de aprovisionamiento asociado a ese ID. de aplicación explícito y con permisos del Kit de mantenimiento .A Provisioning Profile associated with that explicit App ID and with Health Kit permissions.
  • Entitlements.plist con una propiedad com.apple.developer.healthkit de tipo Boolean establecida en Yes.An Entitlements.plist with a com.apple.developer.healthkit property of type Boolean set to Yes.
  • Info.plist cuya clave de UIRequiredDeviceCapabilities contiene una entrada con el valor de String healthkit.An Info.plist whose UIRequiredDeviceCapabilities key contains an entry with the String value healthkit.
  • El Info.plist también debe tener las entradas de la explicación de la privacidad adecuada: una explicación String de la clave NSHealthUpdateUsageDescription si la aplicación va a escribir datos y una explicación de String para la clave NSHealthShareUsageDescription si la aplicación va a leer los datos del kit de mantenimiento.The Info.plist must also have appropriate privacy-explanation entries: a String explanation for the key NSHealthUpdateUsageDescription if the app is going to write data and a String explanation for the key NSHealthShareUsageDescription if the app is going to read Health Kit data.

Para obtener más información sobre el aprovisionamiento de una aplicación de iOS, en el artículo aprovisionamiento de dispositivos de la serie de Introducción de Xamarin se describe la relación entre los certificados de desarrollador, los ID. de aplicación, los perfiles de aprovisionamiento y los derechos de la aplicación.To find out more about provisioning an iOS app, the Device Provisioning article in Xamarin’s Getting Started series describes the relationship between Developer Certificates, App IDs, Provisioning Profiles, and App Entitlements.

IDENTIFICADOR de aplicación explícito y Perfil de aprovisionamientoExplicit App ID and Provisioning Profile

La creación de un identificador de aplicación explícito y un Perfil de aprovisionamiento adecuado se realiza en el centro de desarrollo de iOSde Apple.The creation of an explicit App ID and an appropriate Provisioning Profile is done within Apple’s iOS Dev Center.

Los identificadores de aplicación actuales aparecen en la sección certificados, identificadores & perfiles del centro de desarrollo.Your current App IDs are listed within the Certificates, Identifiers & Profiles section of the Dev Center. A menudo, en esta lista se mostrarán los valores de identificador de *, lo que indica que el identificador de la aplicación - nombre se puede usar con cualquier número de sufijos.Often, this list will show ID values of *, indicating that the App ID - Name can be used with any number of suffixes. Estos identificadores de aplicación comodín no se pueden usar con el kit de mantenimiento.Such Wildcard App IDs cannot be used with Health Kit.

Para crear un identificador de aplicaciónexplícito, haga clic en el botón + en la parte superior derecha para pasar a la página registrar el ID. de aplicación de iOS :To create an explicit App ID, click the + button in the upper-right to take you to the Register iOS App ID page:

Como se muestra en la imagen anterior, después de crear una descripción de la aplicación, use la sección de ID. de aplicación explícito para crear un identificador para la aplicación.As shown in the image above, after creating an app description, use the Explicit App ID section to create an ID for your application. En la sección App Services , active el Kit de estado en la sección habilitar servicios .In the App Services section, check Health Kit in the Enable Services section.

Cuando haya terminado, haga clic en el botón Continue (continuar ) para registrar el identificador de la aplicación en su cuenta.When you are done, press the Continue button to register the App ID in your account. Se le devolverá a la página certificados, identificadores y perfiles .You will be brought back to the Certificates, Identifiers, and Profiles page. Haga clic en perfiles de aprovisionamiento para pasar a la lista de perfiles de aprovisionamiento actuales y haga clic en el botón + en la esquina superior derecha para pasar a la página Agregar Perfil de aprovisionamiento de iOS .Click Provisioning Profiles to take you to the list of your current provisioning profiles, and click the + button in the upper-right corner to take you to the Add iOS Provisioning Profile page. Seleccione la opción desarrollo de aplicaciones de iOS y haga clic en continuar para acceder a la página seleccionar ID . de aplicación.Select the iOS App Development option and click Continue to get to the Select App ID page. Aquí, seleccione el identificador de aplicación explícito que especificó anteriormente:Here, select the explicit App ID that you previously specified:

Haga clic en continuar y trabaje a través de las pantallas restantes, donde se especificarán los certificados de desarrollador, los dispositivosy un nombre para este Perfil de aprovisionamiento:Click Continue and work through the remaining screens, where you will specify your Developer Certificate(s), Device(s), and a Name for this Provisioning Profile:

Haga clic en generar y espere a que se cree el perfil.Click Generate and await the creation of your profile. Descargue el archivo y haga doble clic en él para instalarlo en Xcode.Download the file and double-click it to install in Xcode. Puede confirmar su instalación en Xcode > preferencias > cuentas > ver detalles.. .You can confirm it’s installation under Xcode > Preferences > Accounts > View Details… Debería ver el perfil de aprovisionamiento recién instalado y debe tener el icono del kit de mantenimiento y cualquier otro servicio especial en su fila derechos :You should see your just-installed provisioning profile, and it should have the icon for Health Kit and any other special services in its Entitlements row:

Asociar el identificador de aplicación y el perfil de aprovisionamiento a la aplicación de Xamarin. iOSAssociating the App ID and Provisioning Profile With Your Xamarin.iOS App

Una vez que haya creado e instalado un Perfil de aprovisionamiento adecuado, tal y como se describe, normalmente sería el momento de crear una solución en Visual Studio para Mac o Visual Studio.Once you’ve created and installed an appropriate Provisioning Profile as described, it would normally be time to create a solution in Visual Studio for Mac or Visual Studio. El acceso al kit de mantenimiento está disponible C# para F# cualquier iOS o proyecto.Health Kit access is available to any iOS C# or F# project.

En lugar de recorrer el proceso de creación de un proyecto de Xamarin iOS 8, abra la aplicación de ejemplo adjunta a este artículo (que incluye un guión gráfico y un código precompilados).Rather than walk through the process of creating a Xamarin iOS 8 project by hand, open the sample app attached to this article (which includes a prebuilt Storyboard and code). Para asociar la aplicación de ejemplo con el Perfil de aprovisionamientohabilitado del kit de mantenimiento, en el Panel de solución, haga clic con el botón derecho en el proyecto y abra el cuadro de diálogo Opciones .To associate the sample app with your Health Kit enabled Provisioning Profile, in the Solution Pad, right-click on your Project and bring up its Options dialog. Cambie al panel de la aplicación iOS y escriba el identificador de aplicación explícito que creó anteriormente como identificador de lotede la aplicación:Switch to the iOS Application panel and enter the explicit App ID you created previously as the app’s Bundle Identifier:

Ahora, cambie al panel de firma de lote de iOS .Now switch to the iOS Bundle Signing panel. El Perfil de aprovisionamientoinstalado recientemente, con su asociación al identificador de aplicaciónexplícito, ahora estará disponible como el perfil de aprovisionamiento:Your recently-installed Provisioning Profile, with its association to the explicit App ID, will now be available as the Provisioning Profile:

Si el Perfil de aprovisionamiento no está disponible, compruebe el identificador de la agrupación en el panel de la aplicación iOS en comparación con el especificado en el centro de desarrollo de iOS y que el perfil de aprovisionamiento está instalado (Xcode > Preferencias > cuentas > ver detalles... ).If the Provisioning Profile is not available, double-check the Bundle Identifier in the iOS Application panel versus that specified in the iOS Dev Center and that the Provisioning Profile is installed (Xcode > Preferences > Accounts > View Details…).

Cuando esté seleccionado el perfil de aprovisionamiento habilitado para el kit de mantenimiento, haga clic en Aceptar para cerrar el cuadro de diálogo Opciones del proyecto.When the Health Kit-enabled Provisioning Profile is selected, click OK to close the Project Options dialog.

Los valores de contitles. plist y info. plistEntitlements.plist and Info.plist Values

La aplicación de ejemplo incluye un archivo Entitlements.plist (que es necesario para las aplicaciones habilitadas para el kit de mantenimiento) y no se incluye en todas las plantillas de proyecto.The sample app includes an Entitlements.plist file (which is necessary for Health Kit enabled apps), and not included in every Project Template. Si el proyecto no incluye derechos, haga clic con el botón derecho en el proyecto, seleccione archivo > nuevo archivo... > iOS > contitles. plist para agregar uno manualmente.If your project does not include entitlements, right-click on your project, choose File > New File… > iOS > Entitlements.plist to add one manually.

En última instancia, el Entitlements.plist debe tener el siguiente par de clave y valor:Ultimately, your Entitlements.plist must have the following key and value pair:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.HealthKit</key>
    <true/>
</dict>
</plist>

Del mismo modo, el Info.plist de la aplicación debe tener un valor de healthkit asociado a la clave UIRequiredDeviceCapabilities:Similarly, the Info.plist for the app must have a value of healthkit associated with the UIRequiredDeviceCapabilities key:

<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
    <string>healthkit</string>
</array>

La aplicación de ejemplo que se proporciona con este artículo incluye una Entitlements.plist preconfigurada que incluye todas las claves necesarias.The sample application provided with this article includes a preconfigured Entitlements.plist that includes all of the required keys.

Kit de mantenimiento de programaciónProgramming Health Kit

El almacén de información del kit de mantenimiento es un almacén de información privado específico del usuario que se comparte entre las aplicaciones.The Health Kit datastore is a private, user-specific datastore that is shared among apps. Dado que la información de estado es tan confidencial, el usuario debe seguir los pasos positivos para permitir el acceso a los datos.Because health information is so sensitive, the user must take positive steps to allow data access. Este acceso puede ser parcial (escritura, pero no lectura, acceso a algunos tipos de datos, pero no a otros) y se puede revocar en cualquier momento.This access may be partial (write but not read, access for some types of data but not others, etc.) and may be revoked at any time. Las aplicaciones del kit de mantenimiento deben escribirse de forma defensiva, sabiendo que muchos usuarios tendrán dudas sobre el almacenamiento de la información relacionada con el estado.Health Kit applications should be written defensively, with the understanding that many users will be hesitant about storing their health-related information.

Los datos del kit de mantenimiento se limitan a los tipos especificados de Apple.Health Kit data is limited to Apple specified types. Estos tipos están estrictamente definidos: algunos, como el tipo de sangre, se limitan a los valores concretos de una enumeración proporcionada por Apple, mientras que otros combinan una magnitud con una unidad de medida (como gramos, calorías y litros).These types are strictly defined: some, such as blood type, are limited to the particular values of an Apple supplied enumeration, while others combine a magnitude with a unit of measure (such as grams, calories, and liters). Incluso los datos que comparten una unidad de medida compatible se distinguen por su HKObjectType; por ejemplo, el sistema de tipos detectará un intento erróneo de almacenar un valor de HKQuantityTypeIdentifier.NumberOfTimesFallen en un campo que espera un HKQuantityTypeIdentifier.FlightsClimbed aunque ambos usen la unidad de medida HKUnit.Count.Even data that share a compatible unit of measure are distinguished by their HKObjectType; for instance, the type system will catch a mistaken attempt to store an HKQuantityTypeIdentifier.NumberOfTimesFallen value to a field expecting an HKQuantityTypeIdentifier.FlightsClimbed even though both use the HKUnit.Count unit of measure.

Los tipos pueda almacenar en el almacén de almacenamiento de los kits de mantenimiento son subclases de HKObjectType.The types storable in the Health Kit datastore are all subclasses of HKObjectType. HKCharacteristicType objetos almacenan el sexo biológico, el tipo de sangre y la fecha de nacimiento.HKCharacteristicType objects store Biological Sex, Blood Type, and Date of Birth. No obstante, es más común que los objetos de HKSampleType, que representan los datos muestreados en un momento específico o durante un período de tiempo.More common though, are HKSampleType objects, which represent data that is sampled at a specific time or over a period of time.

HKSampleType es abstracto y tiene cuatro subclases concretas.HKSampleType is abstract and has four concrete subclasses. Actualmente solo hay un tipo de datos HKCategoryType, que es análisis de suspensión.There is currently only one type of HKCategoryType data, which is Sleep Analysis. La mayor parte de los datos del kit de mantenimiento son del tipo HKQuantityType y almacenan sus datos en HKQuantitySample objetos, que se crean con el modelo de diseño de fábrica conocido:The large majority of data in Health Kit are of type HKQuantityType and store their data in HKQuantitySample objects, which are created using the familiar Factory design pattern:

HKQuantityType tipos van de HKQuantityTypeIdentifier.ActiveEnergyBurned a HKQuantityTypeIdentifier.StepCount.HKQuantityType types range from HKQuantityTypeIdentifier.ActiveEnergyBurned to HKQuantityTypeIdentifier.StepCount.

Solicitar permiso al usuarioRequesting Permission From the User

Los usuarios finales deben realizar pasos positivos para permitir que una aplicación lea o escriba datos del kit de mantenimiento.End users must take positive steps to allow an app to read or write Health Kit data. Esto se hace a través de la aplicación de mantenimiento que viene preinstalada en dispositivos iOS 8.This is done via the Health app that comes pre-installed on iOS 8 devices. La primera vez que se ejecuta una aplicación del kit de mantenimiento, se presenta al usuario un cuadro de diálogo de acceso de mantenimiento controlado por el sistema:The first time a Health Kit app is run, the user is presented with a system-controlled Health Access dialog:

Más adelante, el usuario puede cambiar los permisos mediante el cuadro de diálogo orígenes de la aplicación Health:Later, the user can change permissions using Health app’s Sources dialog:

Dado que la información de estado es extremadamente sensible, los desarrolladores de aplicaciones deben escribir sus programas de forma defensiva, con la expectativa de que los permisos se rechacen y cambien mientras se ejecuta la aplicación.Since health information is extremely sensitive, app developers should write their programs defensively, with the expectation that permissions will be refused and changed while the app is running. La expresión más común es solicitar permisos en el método UIApplicationDelegate.OnActivated y, a continuación, modificar la interfaz de usuario según corresponda.The most common idiom is to request permissions in the UIApplicationDelegate.OnActivated method and then modify the user interface as appropriate.

Tutorial de permisosPermissions Walkthrough

En el proyecto aprovisionado del kit de mantenimiento, abra el archivo de AppDelegate.cs.In your Health Kit-provisioned project, open the AppDelegate.cs file. Observe la instrucción con HealthKit; en la parte superior del archivo.Notice the statement using HealthKit; at the top of the file.

El siguiente código se relaciona con los permisos del kit de mantenimiento:The following code relates to Health Kit permissions:

private HKHealthStore healthKitStore = new HKHealthStore ();

public override void OnActivated (UIApplication application)
{
        ValidateAuthorization ();
}

private void ValidateAuthorization ()
{
        var heartRateId = HKQuantityTypeIdentifierKey.HeartRate;
        var heartRateType = HKObjectType.GetQuantityType (heartRateId);
        var typesToWrite = new NSSet (new [] { heartRateType });
        var typesToRead = new NSSet ();
        healthKitStore.RequestAuthorizationToShare (
                typesToWrite, 
                typesToRead, 
                ReactToHealthCarePermissions);
}

void ReactToHealthCarePermissions (bool success, NSError error)
{
        var access = healthKitStore.GetAuthorizationStatus (HKObjectType.GetQuantityType (HKQuantityTypeIdentifierKey.HeartRate));
        if (access.HasFlag (HKAuthorizationStatus.SharingAuthorized)) {
                HeartRateModel.Instance.Enabled = true;
        } else {
                HeartRateModel.Instance.Enabled = false;
        }
}

Todo el código de estos métodos puede realizarse en línea en OnActivated, pero la aplicación de ejemplo usa métodos independientes para que su intención sea más clara: ValidateAuthorization() tiene los pasos necesarios para solicitar acceso a los tipos específicos que se escriben (y leen, si la aplicación desea) y ReactToHealthCarePermissions() es una devolución de llamada que se activa después de que el usuario haya interactuado con el cuadro de diálogo de permisos en Health. app.All of the code in these methods could be done inline in OnActivated, but the sample app uses separate methods to make their intent clearer: ValidateAuthorization() has the steps necessary to request access to the specific types being written (and read, if the app desired) and ReactToHealthCarePermissions() is a callback that is activated after the user has interacted with the permissions dialog in the Health.app.

El trabajo de ValidateAuthorization() consiste en compilar el conjunto de HKObjectTypes que la aplicación escribirá y solicitará autorización para actualizar los datos.The job of ValidateAuthorization() is to build the set of HKObjectTypes that the app will write and request authorization to update that data. En la aplicación de ejemplo, el HKObjectType es para la clave KHQuantityTypeIdentifierKey.HeartRate.In the sample app, the HKObjectType is for the key KHQuantityTypeIdentifierKey.HeartRate. Este tipo se agrega al conjunto typesToWrite, mientras que el typesToRead del conjunto se deja vacío.This type is added to the set typesToWrite, while the set typesToRead is left empty. Estos conjuntos, y una referencia a la devolución de llamada de ReactToHealthCarePermissions(), se pasan a HKHealthStore.RequestAuthorizationToShare().These sets, and a reference to the ReactToHealthCarePermissions() callback, is passed to HKHealthStore.RequestAuthorizationToShare().

Se llamará a la devolución de llamada de ReactToHealthCarePermissions() después de que el usuario haya interactuado con el cuadro de diálogo de permisos y se le pasen dos fragmentos de información: un valor bool que se true si el usuario ha interactuado con el cuadro de diálogo permisos y un NSError que , si no es null, indica algún tipo de error asociado a la presentación del cuadro de diálogo de permisos.The ReactToHealthCarePermissions() callback will be called after the user has interacted with the permissions dialog and is passed two pieces of information: a bool value that will be true if the user has interacted with the permissions dialog and an NSError which, if non-null, indicates some kind of error associated with presenting the permissions dialog.

Importante

Para estar claro sobre los argumentos de esta función: los parámetros Success y error no indican si el usuario ha concedido permiso para obtener acceso a los datos del kit de mantenimiento.To be clear about the arguments to this function: the success and error parameters do not indicate whether the user has granted permission to access Health Kit data! Solo indican que el usuario tiene la oportunidad de permitir el acceso a los datos.They only indicate that the user has been given the opportunity to permit access to the data.

Para confirmar si la aplicación tiene acceso a los datos, se usa el HKHealthStore.GetAuthorizationStatus(), pasando HKQuantityTypeIdentifierKey.HeartRate.To confirm whether the app has access to the data, the HKHealthStore.GetAuthorizationStatus() is used, passing in HKQuantityTypeIdentifierKey.HeartRate. En función del estado devuelto, la aplicación habilita o deshabilita la capacidad de escribir datos.Based on the status returned, the app enables or disables the ability to enter data. No hay ninguna experiencia de usuario estándar para tratar con una denegación de acceso y hay muchas opciones posibles.There is no standard user experience for dealing with a denial of access and there are many possible options. En la aplicación de ejemplo, el estado se establece en un HeartRateModel objeto singleton que, a su vez, genera eventos relevantes.In the example app, the status is set on a HeartRateModel singleton object that, in turn, raises relevant events.

Modelo, vista y controladorModel, View, and Controller

Para revisar el HeartRateModel objeto singleton, abra el archivo HeartRateModel.cs:To review the HeartRateModel singleton object, open the HeartRateModel.cs file:

using System;
using HealthKit;
using Foundation;

namespace HKWork
{
        public class GenericEventArgs<T> : EventArgs
        {
                public T Value { get; protected set; }
                public DateTime Time { get; protected set; }

                public GenericEventArgs (T value)
                {
                        this.Value = value;
                        Time = DateTime.Now;
                }
        }

        public delegate void GenericEventHandler<T> (object sender,GenericEventArgs<T> args);

        public sealed class HeartRateModel : NSObject
        {
                private static volatile HeartRateModel singleton;
                private static object syncRoot = new Object ();

                private HeartRateModel ()
                {
                }

                public static HeartRateModel Instance {
                        get {
                                //Double-check lazy initialization
                                if (singleton == null) {
                                        lock (syncRoot) {
                                                if (singleton == null) {
                                                        singleton = new HeartRateModel ();
                                                }
                                        }
                                }

                                return singleton;
                        }
                }

                private bool enabled = false;

                public event GenericEventHandler<bool> EnabledChanged;
                public event GenericEventHandler<String> ErrorMessageChanged;
                public event GenericEventHandler<Double> HeartRateStored;

                public bool Enabled { 
                        get { return enabled; }
                        set {
                                if (enabled != value) {
                                        enabled = value;
                                        InvokeOnMainThread(() => EnabledChanged (this, new GenericEventArgs<bool>(value)));
                                }
                        }
                }

                public void PermissionsError(string msg)
                {
                        Enabled = false;
                        InvokeOnMainThread(() => ErrorMessageChanged (this, new GenericEventArgs<string>(msg)));
                }

                //Converts its argument into a strongly-typed quantity representing the value in beats-per-minute
                public HKQuantity HeartRateInBeatsPerMinute(ushort beatsPerMinute)
                {
                        var heartRateUnitType = HKUnit.Count.UnitDividedBy (HKUnit.Minute);
                        var quantity = HKQuantity.FromQuantity (heartRateUnitType, beatsPerMinute);

                        return quantity;
                }
                        
                public void StoreHeartRate(HKQuantity quantity)
                {
                        var bpm = HKUnit.Count.UnitDividedBy (HKUnit.Minute);
                        //Confirm that the value passed in is of a valid type (can be converted to beats-per-minute)
                        if (! quantity.IsCompatible(bpm))
                        {
                                InvokeOnMainThread(() => ErrorMessageChanged(this, new GenericEventArgs<string> ("Units must be compatible with BPM")));
                        }

                        var heartRateId = HKQuantityTypeIdentifierKey.HeartRate;
                        var heartRateQuantityType = HKQuantityType.GetQuantityType (heartRateId);
                        var heartRateSample = HKQuantitySample.FromType (heartRateQuantityType, quantity, new NSDate (), new NSDate (), new HKMetadata());

                        using (var healthKitStore = new HKHealthStore ()) {
                                healthKitStore.SaveObject (heartRateSample, (success, error) => {
                                        InvokeOnMainThread (() => {
                                                if (success) {
                                                        HeartRateStored(this, new GenericEventArgs<Double>(quantity.GetDoubleValue(bpm)));
                                                } else {
                                                        ErrorMessageChanged(this, new GenericEventArgs<string>("Save failed"));
                                                }
                                                if (error != null) {
                                                        //If there's some kind of error, disable 
                                                        Enabled = false;
                                                        ErrorMessageChanged (this, new GenericEventArgs<string>(error.ToString()));
                                                }
                                        });
                                });
                        }
                }
        }
}

La primera sección es código reutilizable para crear eventos y controladores genéricos.The first section is boilerplate code for creating generic events and handlers. La parte inicial de la clase HeartRateModel también es reutilizable para crear un objeto singleton seguro para subprocesos.The initial portion of the HeartRateModel class is also boilerplate for creating a thread-safe singleton object.

A continuación, HeartRateModel expone 3 eventos:Then, HeartRateModel exposes 3 events:

  • EnabledChanged: indica que se ha habilitado o deshabilitado el almacenamiento de la tasa de corazón (tenga en cuenta que el almacenamiento está deshabilitado inicialmente).EnabledChanged - Indicates that heart rate storage has been enabled or disabled (note that storage is initially disabled).
  • ErrorMessageChanged: para esta aplicación de ejemplo, tenemos un modelo de control de errores muy simple: una cadena con el último error.ErrorMessageChanged - For this sample app, we have a very simple error-handling model: a string with the last error .
  • HeartRateStored: se genera cuando se almacena una tarifa cardíaca en la base de datos del kit de mantenimiento.HeartRateStored - Raised when a heart rate is stored in the Health Kit database.

Tenga en cuenta que cada vez que se activan estos eventos, se realiza a través de NSObject.InvokeOnMainThread(), lo que permite a los suscriptores actualizar la interfaz de usuario.Note that the whenever these events are fired, it is done via NSObject.InvokeOnMainThread(), which allows subscribers to update the UI. Como alternativa, los eventos podrían estar documentados como generados en subprocesos en segundo plano y la responsabilidad de garantizar la compatibilidad podría dejarse en sus controladores.Alternatively, the events could be documented as being raised on background threads and the responsibility of ensuring compatibility could be left to their handlers. Las consideraciones sobre los subprocesos son importantes en las aplicaciones del kit de mantenimiento porque muchas de las funciones, como la solicitud de permiso, son asincrónicas y ejecutan sus devoluciones de llamada en subprocesos no principales.Thread considerations are important in Health Kit applications because many of the functions, such as the permission request, are asynchronous and execute their callbacks on non-main threads.

El código específico del kit de mantenimiento en HeartRateModel está en las dos funciones HeartRateInBeatsPerMinute() y StoreHeartRate().The Heath Kit specific code in HeartRateModel is in the two functions HeartRateInBeatsPerMinute() and StoreHeartRate().

HeartRateInBeatsPerMinute() convierte su argumento en un HKQuantitydel kit de mantenimiento fuertemente tipado.HeartRateInBeatsPerMinute() converts its argument into a strongly-typed Health Kit HKQuantity. El tipo de la cantidad es el que especifica el HKQuantityTypeIdentifierKey.HeartRate y las unidades de la cantidad se HKUnit.Count dividen entre HKUnit.Minute (es decir, la unidad es de pulsaciones por minuto).The type of the quantity is that specified by the HKQuantityTypeIdentifierKey.HeartRate and the units of the quantity are HKUnit.Count divided by HKUnit.Minute (in other words, the unit is beats per minute).

La función StoreHeartRate() toma un HKQuantity (en la aplicación de ejemplo, uno creado por HeartRateInBeatsPerMinute()).The StoreHeartRate() function takes an HKQuantity (in the sample app, one created by HeartRateInBeatsPerMinute() ). Para validar sus datos, usa el método HKQuantity.IsCompatible(), que devuelve true si las unidades del objeto se pueden convertir en las unidades del argumento.To validate its data, it uses the HKQuantity.IsCompatible() method, which returns true if the object’s units can be converted into the units in the argument. Si la cantidad se creó con HeartRateInBeatsPerMinute() Esto devolverá obviamente true, pero también devolverá true si la cantidad se creó como, por ejemplo, las pulsaciones por hora.If the quantity was created with HeartRateInBeatsPerMinute() this will obviously return true, but it would also return true if the quantity were created as, for instance, Beats Per Hour. Normalmente, HKQuantity.IsCompatible() se pueden usar para validar la masa, la distancia y la energía que el usuario o un dispositivo pueden escribir o mostrarse en un sistema de medida (como unidades de datos imperial) pero que podrían estar almacenados en otro sistema (por ejemplo, unidades de métricas).More commonly, HKQuantity.IsCompatible() can be used to validate mass, distance, and energy which the user or a device might input or display in one system of measurement (such as Imperial units) but which might be stored in another system (such as metric units).

Una vez que se ha validado la compatibilidad de la cantidad, el Factory Method de HKQuantitySample.FromType() se usa para crear un objeto de heartRateSample fuertemente tipado.Once the compatibility of the quantity has been validated, the HKQuantitySample.FromType() factory method is used to create a strongly-typed heartRateSample object. HKSample objetos tienen una fecha de inicio y de finalización; en el caso de las lecturas instantáneas, estos valores deben ser los mismos que en el ejemplo.HKSample objects have a start and end date; for instantaneous readings, these values should be the same, as they are in the example. El ejemplo tampoco establece ningún dato de valor clave en su HKMetadata argumento, pero puede usar código como el código siguiente para especificar la ubicación del sensor:The sample also does not set any key-value data in its HKMetadata argument, but one could use code such as the following code to specify sensor location:

var hkm = new HKMetadata();
hkm.HeartRateSensorLocation = HKHeartRateSensorLocation.Chest;

Una vez creado el heartRateSample, el código crea una nueva conexión a la base de datos con el bloque using.Once the heartRateSample has been created, the code creates a new connection to the database with the using block. Dentro de ese bloque, el método HKHealthStore.SaveObject() intenta realizar la escritura asincrónica en la base de datos.Within that block, the HKHealthStore.SaveObject() method attempts the asynchronous write to the database. La llamada resultante a la expresión lambda desencadena eventos relevantes, ya sea HeartRateStored o ErrorMessageChanged.The resulting call to the lambda expression triggers relevant events, either HeartRateStored or ErrorMessageChanged.

Ahora que el modelo se ha programado, es el momento de ver cómo el controlador refleja el estado del modelo.Now that the model has been programmed, it’s time to see how the controller reflects the state of the model. Abra el archivo de HKWorkViewController.cs.Open up the HKWorkViewController.cs file. El constructor simplemente conecta el HeartRateModel singleton con los métodos de control de eventos (de nuevo, esto se puede hacer en línea con expresiones lambda, pero los métodos independientes hacen que la intención sea un poco más obvia):The constructor simply wires up the HeartRateModel singleton to event-handling methods (again, this could be done inline with lambda expressions, but separate methods make the intent a little more obvious):

public HKWorkViewController (IntPtr handle) : base (handle)
{
     HeartRateModel.Instance.EnabledChanged += OnEnabledChanged;
     HeartRateModel.Instance.ErrorMessageChanged += OnErrorMessageChanged;
     HeartRateModel.Instance.HeartRateStored += OnHeartBeatStored;
}

Estos son los controladores relevantes:Here are the relevant handlers:

void OnEnabledChanged (object sender, GenericEventArgs<bool> args)
{
        StoreData.Enabled = args.Value;
        PermissionsLabel.Text = args.Value ? "Ready to record" : "Not authorized to store data.";
        PermissionsLabel.SizeToFit ();
}

void OnErrorMessageChanged (object sender, GenericEventArgs<string> args)
{
        PermissionsLabel.Text = args.Value;
}

void OnHeartBeatStored (object sender, GenericEventArgs<double> args)
{
        PermissionsLabel.Text = String.Format ("Stored {0} BPM", args.Value);
}

Obviamente, en una aplicación con un solo controlador, sería posible evitar la creación de un objeto de modelo independiente y el uso de eventos para el flujo de control, pero el uso de objetos de modelo es más adecuado para las aplicaciones reales.Obviously, in an application with a single controller, it would be possible to avoid the creation of a separate model object and the use of events for control flow, but the use of model objects is more appropriate for real-world apps.

Ejecutar la aplicación de ejemploRunning The Sample App

El simulador de iOS no es compatible con el kit de mantenimiento.The iOS Simulator does not support Health Kit. La depuración debe realizarse en un dispositivo físico que ejecute iOS 8.Debugging must be done on a physical device running iOS 8.

Conecte un dispositivo de desarrollo de iOS 8 aprovisionado correctamente al sistema.Attach a properly-provisioned iOS 8 development device to your system. Selecciónelo como destino de implementación en Visual Studio para Mac y, en el menú, elija ejecutar > depurar.Select it as the deployment target in Visual Studio for Mac and from the menu choose Run > Debug.

Importante

Los errores relacionados con el aprovisionamiento se verán en este momento.Mistakes relating to provisioning will surface at this point. Para solucionar errores, revise la sección creación y aprovisionamiento de una aplicación del kit de mantenimiento anterior.To troubleshoot errors, review the Creating and Provisioning a Health Kit App section above. Los componentes son:The components are:

  • centro de desarrollo de iOS : ID. de aplicación explícito & el kit de mantenimiento habilitado.iOS Dev Center - Explicit App ID & Health Kit enabled Provisioning Profile.
  • Opciones de proyecto : identificador de lote (identificador de aplicación explícito) & Perfil de aprovisionamiento.Project Options - Bundle Identifier (explicit App ID) & Provisioning Profile.
  • Código fuente -derechos. plist & info. plistSource code - Entitlements.plist & Info.plist

Suponiendo que las aprovisionaciones se han establecido correctamente, se iniciará la aplicación.Assuming that provisions have been properly set, your application will start. Cuando alcance su método de OnActivated, solicitará la autorización del kit de mantenimiento.When it reaches its OnActivated method, it will request Health Kit authorization. La primera vez que lo encuentre el sistema operativo, se mostrará al usuario el siguiente cuadro de diálogo:The first time this is encountered by the operating system, your user will be presented with the following dialog:

Habilite la aplicación para actualizar los datos de la tarifa de corazón y la aplicación volverá a aparecer.Enable your app to update Heart Rate data and your app will reappear. La devolución de llamada de ReactToHealthCarePermissions se activará de forma asincrónica.The ReactToHealthCarePermissions callback will be activated asynchronously. Esto hará que el HeartRateModel’s propiedad Enabled cambie, lo que provocará el evento EnabledChanged, lo que hará que se ejecute el controlador de eventos HKPermissionsViewController.OnEnabledChanged(), lo que habilita el botón StoreData.This will cause the HeartRateModel’s Enabled property to change, which will raise the EnabledChanged event, which will cause the HKPermissionsViewController.OnEnabledChanged() event handler to run, which enables the StoreData button. En el diagrama siguiente se muestra la secuencia:The following diagram shows the sequence:

Presione el botón grabar .Press the Record button. Esto hará que se ejecute el controlador de StoreData_TouchUpInside(), que intentará analizar el valor del campo de texto heartRate, convertir en un HKQuantity a través de la función de HeartRateModel.HeartRateInBeatsPerMinute() descrita anteriormente y pasar esa cantidad a HeartRateModel.StoreHeartRate().This will cause the StoreData_TouchUpInside() handler to run, which will attempt to parse the value of the heartRate text field, convert into a HKQuantity via the previously discussed HeartRateModel.HeartRateInBeatsPerMinute() function and pass that quantity to HeartRateModel.StoreHeartRate(). Como se explicó anteriormente, esto intentará almacenar los datos y producirá una HeartRateStored o ErrorMessageChanged evento.As discussed previously, this will attempt to store the data and will raise either a HeartRateStored or ErrorMessageChanged event.

Haga doble clic en el botón Inicio del dispositivo y abra aplicación de mantenimiento.Double-click the Home button on your device and open Health app. Haga clic en la pestaña orígenes para ver la aplicación de ejemplo.Click the Sources tab and you will see the sample app listed. Elíjalo y no permitir permiso para actualizar los datos de la frecuencia cardíaca.Choose it and disallow permission to update heart rate data. Haga doble clic en el botón Inicio y vuelva a cambiar a la aplicación.Double-click the Home button and switch back to your app. Una vez más, se llamará a ReactToHealthCarePermissions(), pero esta vez, dado que se deniega el acceso, se deshabilitará el botón StoreData (tenga en cuenta que esto se produce de forma asincrónica y que el cambio en la interfaz de usuario puede estar visible para el usuario final).Once again, ReactToHealthCarePermissions() will be called, but this time, because access is denied, the StoreData button will become disabled (note that this occurs asynchronously and the change in the user interface may be visible to the end user).

Temas avanzadosAdvanced Topics

Leer datos de la base de datos del kit de mantenimiento es muy similar a escribir datos: uno especifica los tipos de datos a los que está intentando acceder, solicita autorización y, si se concede esa autorización, los datos están disponibles, con conversión automática a unidades compatibles de Medi.Reading data from the Health Kit database is very similar to writing data: one specifies the types of data one is trying to access, requests authorization, and if that authorization is granted, the data are available, with automatic conversion to compatible units of measure.

Hay una serie de funciones de consulta más sofisticadas que permiten consultas basadas en predicado y consultas que realizan actualizaciones cuando se actualizan los datos pertinentes.There are a number of more sophisticated query functions which allow predicate-based queries and queries that perform updates when relevant data is updated.

Los desarrolladores de aplicaciones del kit de mantenimiento deben revisar la sección del kit de estado de las directrices de revisiónde la aplicación de Apple.Developers of Health Kit applications should review the Health Kit section of Apple’s App Review Guidelines.

Una vez que se entienden los modelos de seguridad y tipo del sistema, el almacenamiento y la lectura de los datos en la base de datos del kit de mantenimiento Compartido son bastante sencillos.Once the security and type-system models are understood, storing and reading data in the shared Health Kit database is quite straightforward. Muchas de las funciones del kit de mantenimiento funcionan de forma asincrónica y los desarrolladores de aplicaciones deben escribir sus programas adecuadamente.Many of the functions within Health Kit operate asynchronously and application developers must write their programs appropriately.

En el momento de redactar este artículo, no hay ningún equivalente al kit de mantenimiento en Android o Windows Phone.As of the writing of this article, there is currently no equivalent to Health Kit in Android or Windows Phone.

ResumenSummary

En este artículo hemos visto cómo Health kit permite a las aplicaciones almacenar, recuperar y compartir información relacionada con el estado, a la vez que proporciona una aplicación de estado estándar que permite al usuario tener acceso a los datos y controlarlos.In this article we've seen how Health Kit allows applications to store, retrieve, and share health related information, while also providing a standard Health app that allows the user access and control over this data.

También hemos visto cómo la privacidad, la seguridad y la integridad de los datos están invalidando los problemas relacionados con la información relacionada con el estado y las aplicaciones que usan el kit de mantenimiento deben tratar el aumento de la complejidad en los aspectos de la administración de aplicaciones (aprovisionamiento), codificación (tipo de kit de mantenimiento). sistema) y experiencia del usuario (control de usuario de permisos a través de cuadros de diálogo del sistema y de la aplicación de estado).We have also seen how privacy, security, and data integrity are overriding concerns for health-related information and apps using Health Kit must deal with the increase in complexity in application management aspects (provisioning), coding (Health Kit’s type system), and user experience (user control of permissions via system dialogs and Health app).

Por último, hemos echado un vistazo a una implementación sencilla del kit de mantenimiento que usa la aplicación de ejemplo incluida que escribe los datos de latido en el almacén del kit de mantenimiento y tiene un diseño compatible con el asincrónico.Finally, we've taking a look at a simple implementation of Health Kit using the included sample app that writes heartbeat data to the Health Kit store and has an asynchronous-aware design.