Compartir a través de


CloudKit en Xamarin.iOS

El marco de CloudKit agiliza el desarrollo de aplicaciones que acceden a iCloud. Esto incluye la recuperación de los datos de la aplicación y los derechos de recursos, así como la capacidad de almacenar de forma segura la información de la aplicación. Este kit proporciona a los usuarios una capa de anonimato al permitir el acceso a las aplicaciones con sus identificadores de iCloud sin compartir información personal.

Los desarrolladores pueden centrarse en sus aplicaciones del lado cliente y permitir que iCloud elimine la necesidad de escribir lógica de aplicación del lado servidor. CloudKit proporciona autenticación, bases de datos privadas y públicas, y servicios de almacenamiento de recursos y datos estructurados.

Importante

Apple proporciona herramientas para ayudar a los desarrolladores a tratar correctamente el Reglamento general de protección de datos (RGPD) de la Unión Europea.

Requisitos

Se requiere lo siguiente para completar los pasos presentados en este artículo:

  • Xcode y el SDK de iOS: las API de Xcode e iOS 8 de Apple deben instalarse y configurarse en el equipo del desarrollador.
  • Visual Studio para Mac: la versión más reciente de Visual Studio para Mac debe instalarse y configurarse en el dispositivo de usuario.
  • Dispositivo con iOS 8: un dispositivo iOS que ejecuta la versión más reciente de iOS 8 para las pruebas.

¿Qué es CloudKit?

CloudKit es una manera de conceder al desarrollador acceso a los servidores de iCloud. Proporciona la base tanto para iCloud Drive como para la Biblioteca de fotos de iCloud. CloudKit es compatible con dispositivos macOS e iOS.

Cómo CloudKit es compatible con dispositivos macOS e iOS

CloudKit usa la infraestructura de la cuenta de iCloud. Si un usuario ha iniciado sesión en una cuenta de iCloud en el dispositivo, CloudKit usará su identificador para identificar al usuario. Si no hay ninguna cuenta disponible, se proporcionará acceso limitado de solo lectura.

CloudKit admite el concepto de bases de datos públicas y privadas. Las bases de datos públicas proporcionan una "sopa" de todos los datos a los que tiene acceso el usuario. Las bases de datos privadas están diseñadas para almacenar los datos privados enlazados a un usuario específico.

CloudKit admite datos estructurados y masivos. Es capaz de controlar transferencias de archivos grandes sin problemas. CloudKit se encarga de transferir archivos grandes de forma eficaz hacia y desde los servidores de iCloud en segundo plano, liberando al desarrollador para centrarse en otras tareas.

Nota:

Es importante tener en cuenta que CloudKit es una tecnología de transporte. No proporciona persistencia; solo permite que una aplicación envíe y reciba información de los servidores de forma eficaz.

A partir de este artículo, Apple inicialmente proporciona CloudKit de forma gratuita con un límite alto en el ancho de banda y la capacidad de almacenamiento. En el caso de proyectos o aplicaciones más grandes con una base de usuarios grande, Apple ha sugerencia de que se proporcionará una escala de precios asequible.

Habilitación de CloudKit en una aplicación de Xamarin

Antes de que una aplicación de Xamarin pueda utilizar el marco de CloudKit, la aplicación debe aprovisionarse correctamente como se detalla en las guías Trabajar con capacidades y Trabajar con derechos.

Para acceder a CloudKit, el archivo Entitlements.plist debe incluir Habilitar iCloud, Almacenamiento de clave-valory permisos de CloudKit.

Aplicación de ejemplo

En la aplicación de ejemplo se muestra cómo usar CloudKit con Xamarin. Los pasos a continuación muestran cómo configurar la muestra; requiere configuraciones adicionales más allá de las que se requieren solo para CloudKit:

  1. Abra el proyecto en Visual Studio para Mac o Visual Studio.
  2. En el Explorador de soluciones, abra el archivo Info.plist y asegúrese de que el Identificador de agrupación coincide con el definido en el Identificador de aplicación creado como parte de la configuración de aprovisionamiento.
  3. Desplácese hacia abajo hasta la parte inferior del archivo Info.plist y seleccione Modos de fondo habilitados, Actualizaciones de ubicación y Notificaciones remotas.
  4. Haga clic con el botón derecho en el proyecto de iOS en la solución y seleccione Opciones.
  5. Seleccione Firma de paquetes de iOS, seleccione la Identidad de desarrollador y el Perfil de aprovisionamiento creado anteriormente.
  6. Asegúrese de que Entitlements.plist incluye Habilitar iCloud, Almacenamiento de clave-valory CloudKit.
  7. Asegúrese de que el contenedor de Ubiquity existe para la aplicación. Ejemplo: iCloud.com.your-company.CloudKitAtlas
  8. Guarde los cambios en el archivo.

Con esta configuración en su lugar, la aplicación de ejemplo ya está lista para acceder a las API de CloudKit Framework, así como a los servicios de notificaciones, ubicación y segundo plano.

Introducción a la API de CloudKit

Antes de implementar CloudKit en una aplicación de Xamarin iOS, este artículo trata los aspectos básicos de CloudKit Framework, que incluirá los temas siguientes:

  1. Contenedores: silos aislados de comunicaciones de iCloud.
  2. Bases de datos: pública y privada están disponibles para la aplicación.
  3. Registros: el mecanismo en el que se mueven los datos estructurados hacia y desde CloudKit.
  4. Zonas de registros: son grupos de registros.
  5. Identificadores de registro: están totalmente normalizados y representan la ubicación específica del registro.
  6. Referencia: proporcionar relaciones de elementos primarios y secundarios entre registros relacionados dentro de una base de datos determinada.
  7. Activos: permite cargar datos grandes y no estructurados en iCloud y asociarlos a un registro determinado.

Contenedores

Una aplicación determinada que se ejecuta en un dispositivo iOS siempre se ejecuta junto con otras aplicaciones y servicios en ese dispositivo. En el dispositivo cliente, la aplicación estará aislada o protegida de alguna manera. En algunos casos, se trata de un espacio aislado literal y, en otros, la aplicación simplemente se ejecuta en su propio espacio de memoria.

El concepto de tomar una aplicación cliente y ejecutarla separada de otros clientes es muy eficaz y proporciona las siguientes ventajas:

  1. Seguridad: una aplicación no puede interferir con otras aplicaciones cliente o el propio sistema operativo.
  2. Estabilidad: si la aplicación cliente se bloquea, no puede sacar otras aplicaciones del sistema operativo.
  3. Privacidad: cada aplicación cliente tiene acceso limitado a la información personal almacenada en el dispositivo.

CloudKit se diseñó para proporcionar las mismas ventajas que las anteriores y aplicarlas a trabajar con información basada en la nube:

Las aplicaciones de CloudKit se comunican mediante contenedores

Al igual que la aplicación que se ejecuta uno de varios en el dispositivo, por lo que es la comunicación de la aplicación con iCloud uno de varios. Cada uno de estos silos de comunicación diferentes se denomina Contenedores.

Los contenedores se exponen en CloudKit Framework a través de la clase CKContainer. De forma predeterminada, una aplicación se comunica con un contenedor y este contenedor separa los datos de esa aplicación. Esto significa que varias aplicaciones pueden almacenar información en la misma cuenta de iCloud, pero esta información nunca se mezclará.

La contenedorización de datos de iCloud también permite a CloudKit encapsular información del usuario. De este modo, la aplicación tendrá acceso limitado a la cuenta de iCloud y a la información del usuario almacenada en todo, a la vez que protege la privacidad y la seguridad del usuario.

El desarrollador de la aplicación administra completamente los contenedores a través del portal de WWDR. El espacio de nombres del contenedor es global en todos los desarrolladores de Apple, por lo que el contenedor no solo debe ser único para las aplicaciones de un desarrollador determinado, sino para todos los desarrolladores y aplicaciones de Apple.

Apple sugiere el uso de notación DNS inversa al crear el espacio de nombres para contenedores de aplicaciones. Ejemplo: iCloud.com.company-name.application-name

Aunque los contenedores son, de forma predeterminada, enlazados uno a uno a una aplicación determinada, se pueden compartir entre aplicaciones. Por lo tanto, varias aplicaciones pueden coordinarse en un único contenedor. Una sola aplicación también puede comunicarse con varios contenedores.

Bases de datos

Una de las funciones principales de CloudKit es tomar el modelo de datos y la replicación de una aplicación hasta los servidores de iCloud. Cierta información está pensada para el usuario que la creó, otra información es datos públicos que un usuario podría crear para su uso público (como una revisión de restaurante) o podría ser información que el desarrollador ha publicado para la aplicación. En cualquier caso, la audiencia no es solo un solo usuario, sino que es una comunidad de personas.

Diagrama de contenedor de CloudKit

Dentro de un contenedor, en primer lugar es la base de datos pública. Aquí es donde toda la información pública vive y combina. Además, hay varias bases de datos privadas individuales para cada usuario de la aplicación.

Cuando se ejecuta en un dispositivo iOS, la aplicación solo tendrá acceso a la información del usuario de iCloud que ha iniciado sesión actualmente. Por lo tanto, la vista de la aplicación del contenedor será la siguiente:

Vista de aplicaciones del contenedor

Solo puede ver la base de datos pública y la base de datos privada asociada al usuario de iCloud que ha iniciado sesión actualmente.

Las bases de datos se exponen en CloudKit Framework a través de la clase CKDatabase. Cada aplicación tiene acceso a dos bases de datos: la base de datos pública y la privada.

El contenedor es el punto de entrada inicial en CloudKit. El código siguiente se puede usar para acceder a la base de datos pública y privada desde el contenedor predeterminado de la aplicación:

using CloudKit;
//...

public CKDatabase PublicDatabase { get; set; }
public CKDatabase PrivateDatabase { get; set; }
//...

// Get the default public and private databases for
// the application
PublicDatabase = CKContainer.DefaultContainer.PublicCloudDatabase;
PrivateDatabase = CKContainer.DefaultContainer.PrivateCloudDatabase;

Estas son las diferencias entre los tipos de base de datos:

Base de datos pública Base de datos privada
Tipo de datos Datos compartidos Datos del usuario actual
Cuota Se tiene en cuenta en la cuota del desarrollador Se tiene en cuenta en la cuota del usuario
Permisos predeterminados Legible en todo el mundo Legible por el usuario
Permisos de edición Roles de panel de iCloud a través de un nivel de clase de registro N/D

Registros

Los contenedores contienen bases de datos y dentro de las bases de datos son registros. Los registros son el mecanismo en el que los datos estructurados se mueven hacia y desde CloudKit:

Los contenedores contienen bases de datos y dentro de estas están los registros

Los registros se exponen en CloudKit Framework a través de la clase CKRecord, que encapsula pares clave-valor. Una instancia de un objeto en una aplicación es equivalente a un CKRecord en CloudKit. Además, cada CKRecord posee un tipo de registro, que es equivalente a la clase de un objeto.

Los registros tienen un esquema Just-In-Time, por lo que los datos se describen en CloudKit antes de entregarse para su procesamiento. Desde ese momento, CloudKit interpretará la información y controlará la logística de almacenar y recuperar el registro.

La clase CKRecord también admite una amplia gama de metadatos. Por ejemplo, un registro contiene información sobre cuándo se creó y el usuario que lo creó. Un registro también contiene información sobre cuándo se modificó por última vez y el usuario que lo modificó.

Los registros contienen la noción de una etiqueta de cambio. Se trata de una versión anterior de una revisión de un registro determinado. La etiqueta de cambio se utiliza como una forma sencilla de determinar si el cliente y el servidor tienen la misma versión de un registro determinado.

Como se indicó anteriormente, CKRecords envuelve pares clave-valor y, como tal, los siguientes tipos de datos se pueden almacenar en un registro:

  1. NSString
  2. NSNumber
  3. NSData
  4. NSDate
  5. CLLocation
  6. CKReferences
  7. CKAssets

Además de los tipos de valor único, un registro puede contener una matriz homogéneo de cualquiera de los tipos enumerados anteriormente.

El código siguiente se puede usar para crear un nuevo registro y almacenarlo en una base de datos:

using CloudKit;
//...

private const string ReferenceItemRecordName = "ReferenceItems";
//...

var newRecord = new CKRecord (ReferenceItemRecordName);
newRecord ["name"] = (NSString)nameTextField.Text;
await CloudManager.SaveAsync (newRecord);

Zonas de registro

Los registros no existen por sí mismos dentro de una base de datos determinada: los grupos de registros existen juntos dentro de una zona de registros. Las Zonas de registro se pueden considerar como Tablas en bases de datos relacionales tradicionales:

Los grupos de registros coexisten dentro de una zona de registros

Puede haber varios registros dentro de una zona de registros determinada y varias zonas de registro dentro de una base de datos determinada. Cada base de datos contiene una zona de registro predeterminada:

Cada base de datos contiene una zona de registro predeterminada y una zona predeterminada

Aquí es donde los registros se almacenan de forma predeterminada. Además, se pueden crear zonas de registro personalizadas. Las zonas de registro representan la granularidad base en la que se realizan confirmaciones atómicas y Change Tracking.

Identificadores de registro

Los identificadores de registro se representan como una tupla, que contiene un nombre de registro proporcionado por el cliente y la zona en la que existe el registro. Los identificadores de registro tienen las siguientes características:

  • La aplicación cliente las crea.
  • Se normalizan completamente y representan la ubicación específica del registro.
  • Al asignar el identificador único de un registro en una base de datos externa al nombre del registro, se pueden usar para puentear las bases de datos locales que no están almacenadas en CloudKit.

Cuando los desarrolladores crean nuevos registros, pueden optar por pasar un identificador de registro. Si no se especifica un identificador de registro, se creará automáticamente un UUID y se asignará al registro.

Cuando los desarrolladores crean nuevos identificadores de registro, pueden elegir especificar la zona de registro a la que pertenecerá cada registro. Si no se especifica ninguno, se usará la zona de registro predeterminada.

Los identificadores de registro se exponen en CloudKit Framework a través de la clase CKRecordID. El código siguiente se puede usar para crear un nuevo identificador de registro:

var recordID =  new CKRecordID("My Record");

Referencias

Las referencias proporcionan relaciones entre registros relacionados dentro de una base de datos determinada:

Las referencias proporcionan relaciones entre registros relacionados dentro de una base de datos determinada

En el ejemplo anterior, los padres poseen hijos para que el niño sea un registro secundario del registro primario. La relación pasa del registro secundario al registro primario y se conoce como Referencia inversa.

Las referencias se exponen en CloudKit Framework a través de la clase CKReference. Son una manera de permitir que el servidor de iCloud comprenda la relación entre registros.

Las referencias proporcionan el mecanismo detrás de eliminaciones en cascada. Si se elimina un registro primario de la base de datos, los registros secundarios (tal como se especifican en una relación) también se eliminarán de la base de datos.

Nota:

Los punteros pendientes son una posibilidad al usar CloudKit. Por ejemplo, cuando la aplicación ha capturado una lista de punteros de registro, seleccionó un registro y, a continuación, solicitó el registro, es posible que el registro ya no exista en la base de datos. Una aplicación debe codificarse para controlar esta situación correctamente.

Aunque no es necesario, se prefieren las referencias inversas al trabajar con CloudKit Framework. Apple ha ajustado el sistema para que este sea el tipo de referencia más eficaz.

Al crear una referencia, el desarrollador puede proporcionar un registro que ya está en memoria o crear una referencia a un identificador de registro. Si se usa un identificador de registro y la referencia especificada no existía en la base de datos, se crearía un puntero pendiente.

A continuación se muestra un ejemplo de creación de una referencia en un registro conocido:

var reference = new CKReference(newRecord, new CKReferenceAction());

Activos

Los recursos permiten cargar un archivo de datos grandes y no estructurados en iCloud y asociarlos a un registro determinado:

Los recursos permiten cargar archivos de gran cantidad de datos no estructurados en iCloud y asociarlos a registros determinados

En el cliente, se crea un CKRecord que describe el archivo que se va a cargar en el servidor de iCloud. Se crea un CKAsset para contener el archivo y está vinculado al registro que lo describe.

Cuando el archivo se carga en el servidor, el registro se coloca en la base de datos y el archivo se copia en una base de datos de almacenamiento masiva especial. Se crea un vínculo entre el puntero de registro y el archivo cargado.

Los recursos se exponen en CloudKit Framework a través de la clase CKAsset y se usan para almacenar datos grandes y no estructurados. Dado que el desarrollador nunca quiere tener datos grandes y no estructurados en memoria, los recursos se implementan mediante archivos en disco.

Los recursos son propiedad de los registros, lo que permite que los recursos se recuperen de iCloud mediante el registro como puntero. De este modo, el servidor puede recopilar elementos no utilizados cuando se elimina el registro que posee el recurso.

Dado que CKAssets están diseñados para controlar archivos de datos de gran tamaño, Apple diseñó CloudKit para cargar y descargar de forma eficaz los recursos.

El código siguiente se puede usar para crear un recurso y asociarlo con el registro:

var fileUrl = new NSUrl("LargeFile.mov");
var asset = new CKAsset(fileUrl);
newRecord ["name"] = asset;

Ahora hemos tratado todos los objetos fundamentales de CloudKit. Los contenedores están asociados a las aplicaciones y contienen bases de datos. Las bases de datos contienen registros que se agrupan en Zonas de registro y a las que apuntan los identificadores de registro. Las relaciones de elementos primarios y secundarios se definen entre registros mediante referencias. Por último, los archivos grandes se pueden cargar y asociar a registros mediante recursos.

API de conveniencia de CloudKit

Apple ofrece dos conjuntos de API diferentes para trabajar con CloudKit:

  • API operativa: ofrece todas las características únicas de CloudKit. Para aplicaciones más complejas, esta API proporciona un control específico sobre CloudKit.
  • API de conveniencia: ofrece un subconjunto común y preconfigurado de funciones de CloudKit. Proporciona una solución cómoda y fácil de acceder para incluir la funcionalidad de CloudKit en una aplicación iOS.

La API de conveniencia suele ser la mejor opción para la mayoría de las aplicaciones de iOS y Apple sugiere empezar con ella. En el resto de esta sección se tratarán los siguientes temas de la API de conveniencia:

  • Guardando un registro.
  • Capturando un registro.
  • Actualizando un registro.

Código de instalación común

Antes de comenzar con la API de conveniencia de CloudKit, se requiere algún código de configuración estándar. Para empezar, modifique el archivo AppDelegate.cs de la aplicación y haga que tenga un aspecto similar al siguiente:

using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
using CloudKit;

namespace CloudKitAtlas
{
    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        public override UIWindow Window { get; set;}
        public CKDatabase PublicDatabase { get; set; }
        public CKDatabase PrivateDatabase { get; set; }

        public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
        {
            application.RegisterForRemoteNotifications ();

            // Get the default public and private databases for
            // the application
            PublicDatabase = CKContainer.DefaultContainer.PublicCloudDatabase;
            PrivateDatabase = CKContainer.DefaultContainer.PrivateCloudDatabase;

            return true;
        }

        public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
        {
            Console.WriteLine ("Registered for Push notifications with token: {0}", deviceToken);
        }

        public override void FailedToRegisterForRemoteNotifications (UIApplication application, NSError error)
        {
            Console.WriteLine ("Push subscription failed");
        }

        public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
        {
            Console.WriteLine ("Push received");
        }
    }
}

El código anterior expone las bases de datos públicas y privadas de CloudKit como accesos directos para facilitar su trabajo en el resto de la aplicación.

A continuación, agregue el código siguiente a cualquier vista o contenedor de vistas que vaya a usar CloudKit:

using CloudKit;
//...

public AppDelegate ThisApp {
    get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
}

Esto agrega un acceso directo para acceder a AppDelegate y a los accesos directos de base de datos públicos y privados creados anteriormente.

Con este código implementado, echemos un vistazo a la implementación de la API de conveniencia de CloudKit en una aplicación de Xamarin iOS 8.

Guardando un registro

Utilizando el patrón presentado anteriormente cuando se habla de Registros, el siguiente código creará un nuevo registro y utilizará la API Convenience para guardarlo en la base de datos pública:

private const string ReferenceItemRecordName = "ReferenceItems";
...

// Create a new record
var newRecord = new CKRecord (ReferenceItemRecordName);
newRecord ["name"] = (NSString)nameTextField.Text;

// Save it to the database
ThisApp.PublicDatabase.SaveRecord(newRecord, (record, err) => {
    // Was there an error?
    if (err != null) {
        ...
    }
});

Tres cosas que se deben tener en cuenta sobre el código anterior:

  1. Al llamar al método SaveRecord del PublicDatabase, el desarrollador no tiene que especificar cómo se envían los datos, en qué zona se está escribiendo, etc. La API de conveniencia se encarga de todos esos detalles.
  2. La llamada es asincrónica y proporciona una rutina de devolución de llamada cuando se completa la llamada, ya sea con éxito o error. Si se produce un error en la llamada, se proporcionará un mensaje de error.
  3. CloudKit no proporciona almacenamiento local ni persistencia; es solo un medio de transferencia. Por lo tanto, cuando se realiza una solicitud para guardar un registro, se envía inmediatamente a los servidores de iCloud.

Nota:

Debido a la naturaleza de "pérdida" de las comunicaciones de red móvil, donde las conexiones se quitan o interrumpen constantemente, una de las primeras consideraciones que debe tener el desarrollador al trabajar con CloudKit es el control de errores.

Captura de un registro

Con un registro creado y almacenado correctamente en el servidor iCloud, use el código siguiente para recuperar el registro:

// Create a record ID and fetch the record from the database
var recordID = new CKRecordID("MyRecordName");
ThisApp.PublicDatabase.FetchRecord(recordID, (record, err) => {
    // Was there an error?
    if (err != null) {
        ...
    }
});

Al igual que al guardar el registro, el código anterior es asincrónico, sencillo y requiere un gran control de errores.

Actualizar un registro

Después de capturar un registro desde los servidores de iCloud, se puede usar el código siguiente para modificar el registro y guardar los cambios en la base de datos:

// Create a record ID and fetch the record from the database
var recordID = new CKRecordID("MyRecordName");
ThisApp.PublicDatabase.FetchRecord(recordID, (record, err) => {
    // Was there an error?
    if (err != null) {

    } else {
        // Modify the record
        record["name"] = (NSString)"New Name";

        // Save changes to database
        ThisApp.PublicDatabase.SaveRecord(record, (r, e) => {
            // Was there an error?
            if (e != null) {
                 ...
            }
        });
    }
});

El método FetchRecord del PublicDatabase devuelve un CKRecord si la llamada se realizó correctamente. A continuación, la aplicación modifica el registro y llama a SaveRecord de nuevo para volver a escribir los cambios en la base de datos.

Esta sección ha mostrado el ciclo típico que utilizará una aplicación cuando trabaje con la API de conveniencia de CloudKit. La aplicación guardará Registros en iCloud, recuperará esos registros de iCloud, modificará los registros y guardará esos cambios en iCloud.

Diseño para escalabilidad

Hasta ahora, este artículo ha examinado el almacenamiento y la recuperación del modelo de objetos completo de una aplicación desde los servidores de iCloud, cada vez que se va a trabajar con él. Aunque este enfoque funciona bien con una pequeña cantidad de datos y una base de usuarios muy pequeña, no se escala bien cuando aumenta la cantidad de información o la base de usuarios.

Macrodatos, dispositivo diminuto

Cuanto más popular sea una aplicación, más datos de la base de datos y menos factible es tener una memoria caché de esos datos completos en el dispositivo. Las técnicas siguientes se pueden usar para resolver este problema:

  • Mantener los datos grandes en Cloud: CloudKit se diseñó para administrar datos de gran tamaño de forma eficaz.
  • El cliente solo debe ver un segmento de esos datos: reduzca el mínimo de datos necesarios para realizar cualquier tarea en un momento dado.
  • Las vistas de cliente pueden cambiar: dado que cada usuario tiene preferencias diferentes, el segmento de datos que se muestra puede cambiar de usuario a usuario y la vista individual del usuario de cualquier segmento determinado puede ser diferente.
  • El cliente usa consultas para centrar el punto de vista: las consultas permiten al usuario ver un pequeño subconjunto de un conjunto de datos mayor que existe en la nube.

Consultas

Como se indicó anteriormente, las consultas permiten al desarrollador seleccionar un pequeño subconjunto del conjunto de datos más grande que existe en la nube. Las consultas se exponen en CloudKit Framework a través de la clase CKQuery.

Una consulta combina tres cosas diferentes: un tipo de registro ( RecordType), un predicado ( NSPredicate) y, opcionalmente, un descriptor de ordenación ( NSSortDescriptors). CloudKit admite la mayoría de NSPredicate.

Predicados admitidos

CloudKit admite los siguientes tipos de NSPredicates al trabajar con consultas:

  1. Registros coincidentes donde el nombre es igual a un valor almacenado en una variable:

    NSPredicate.FromFormat(string.Format("name = '{0}'", recordName))
    
  2. Permite que la coincidencia se base en un valor de clave dinámica, de modo que la clave no tenga que conocerse en tiempo de compilación:

    NSPredicate.FromFormat(string.Format("{0} = '{1}'", key, value))
    
  3. Registros coincidentes en los que el valor del registro es mayor que el valor especificado:

    NSPredicate.FromFormat(string.Format("start > {0}", (NSDate)date))
    
  4. Registros coincidentes donde la ubicación del registro está a menos de 100 metros de la ubicación especificada:

    var location = new CLLocation(37.783,-122.404);
    var predicate = NSPredicate.FromFormat(string.Format("distanceToLocation:fromLocation(Location,{0}) < 100", location));
    
  5. CloudKit admite una búsqueda con tokens. Esta llamada creará dos tokens, uno para after y otro para session. Devolverá un registro que contiene esos dos tokens:

    NSPredicate.FromFormat(string.Format("ALL tokenize({0}, 'Cdl') IN allTokens", "after session"))
    
  6. CloudKit admite predicados compuestos unidos mediante el operador AND.

    NSPredicate.FromFormat(string.Format("start > {0} AND name = '{1}'", (NSDate)date, recordName))
    

Crear consultas

El código siguiente se puede usar para crear un CKQuery en una aplicación de Xamarin iOS 8:

var recordName = "MyRec";
var predicate = NSPredicate.FromFormat(string.Format("name = '{0}'", recordName));
var query = new CKQuery("CloudRecords", predicate);

En primer lugar, crea un predicado para seleccionar solo los registros que coinciden con un nombre determinado. A continuación, crea una consulta que seleccionará Registros del tipo de registro especificado que coincida con el predicado.

Realizar una consulta

Una vez creada una consulta, use el código siguiente para realizar la consulta y procesar los registros devueltos:

var recordName = "MyRec";
var predicate = NSPredicate.FromFormat(string.Format("name = {0}", recordName));
var query = new CKQuery("CloudRecords", predicate);

ThisApp.PublicDatabase.PerformQuery(query, CKRecordZone.DefaultRecordZone().ZoneId, (NSArray results, NSError err) => {
    // Was there an error?
    if (err != null) {
       ...
    } else {
        // Process the returned records
        for(nint i = 0; i < results.Count; ++i) {
            var record = (CKRecord)results[i];
        }
    }
});

El código anterior toma la consulta creada anteriormente y la ejecuta en la base de datos pública. Puesto que no se especifica ninguna zona de registro, se buscan todas las zonas. Si no se produjo ningún error, se devolverá una matriz de CKRecords que coincida con los parámetros de la consulta.

La manera de pensar en Consultas es que son sondeos y son excelentes para segmentar a través de grandes conjuntos de datos. Sin embargo, las consultas no son adecuadas para conjuntos de datos grandes y principalmente estáticos debido a las siguientes razones:

  • Son malos para la duración de la batería del dispositivo.
  • Son malos para el tráfico de red.
  • Son incorrectos para la experiencia del usuario porque la información que ve está limitada por la frecuencia con la que la aplicación sondea la base de datos. En la actualidad, los usuarios esperan notificaciones push cuando cambia algo.

Suscripciones

Cuando se trabaja con conjuntos de datos grandes y principalmente estáticos, la consulta no debe realizarse en el dispositivo cliente, debe ejecutarse en el servidor en nombre del cliente. La consulta debe ejecutarse en segundo plano y debe ejecutarse después de guardar cada registro único, ya sea por el dispositivo actual u otro dispositivo que toque la misma base de datos.

Por último, se debe enviar una notificación push a todos los dispositivos conectados a la base de datos cuando se ejecuta la consulta del lado servidor.

Las suscripciones se exponen en CloudKit Framework a través de la clase CKSubscription. Combinan un tipo de registro ( RecordType), un predicado ( NSPredicate) y una notificación push de Apple ( Push).

Nota:

Las inserciones de CloudKit se aumentan ligeramente, ya que contienen una carga que contiene información específica de CloudKit, como lo que provocó que se produzca la inserción.

Funcionamiento de las suscripciones

Antes de implementar la suscripción en código de C#, veamos una visión general rápida de cómo funcionan las suscripciones:

Información general sobre cómo funcionan las suscripciones

En el gráfico anterior se muestra el proceso de suscripción típico de la siguiente manera:

  1. El dispositivo cliente crea una nueva suscripción que contiene el conjunto de condiciones que desencadenará la suscripción y una notificación push que se enviará cuando se produzca el desencadenador.
  2. La suscripción se envía a la base de datos donde se agrega a la colección de suscripciones existentes.
  3. Un segundo dispositivo crea un nuevo registro y guarda ese registro en la base de datos.
  4. La base de datos busca en su lista de suscripciones para ver si el nuevo registro coincide con cualquiera de sus condiciones.
  5. Si se encuentra una coincidencia, la notificación push se envía al dispositivo que registró la suscripción con información sobre el registro que provocó que se desencadenara.

Con este conocimiento en su lugar, echemos un vistazo a la creación de suscripciones en una aplicación de Xamarin iOS 8.

Crear suscripciones

El código siguiente se puede usar para crear una suscripción:

// Create a new subscription
DateTime date;
var predicate = NSPredicate.FromFormat(string.Format("start > {0}", (NSDate)date));
var subscription = new CKSubscription("RecordType", predicate, CKSubscriptionOptions.FiresOnRecordCreation);

// Describe the type of notification
var notificationInfo = new CKNotificationInfo();
notificationInfo.AlertLocalizationKey = "LOCAL_NOTIFICATION_KEY";
notificationInfo.SoundName = "ping.aiff";
notificationInfo.ShouldBadge = true;

// Attach the notification info to the subscription
subscription.NotificationInfo = notificationInfo;

En primer lugar, crea un predicado que proporciona la condición para desencadenar la suscripción. A continuación, crea la suscripción en un tipo de registro específico y establece la opción de cuando se prueba el desencadenador. Por último, define el tipo de notificación que se producirá cuando se desencadene la suscripción y la adjunte a la suscripción.

Guardar suscripciones

Con la suscripción creada, el código siguiente lo guardará en la base de datos:

// Save the subscription to the database
ThisApp.PublicDatabase.SaveSubscription(subscription, (s, err) => {
    // Was there an error?
    if (err != null) {

    }
});

Con la API de conveniencia, la llamada es asincrónica, sencilla y proporciona un fácil control de errores.

Control de las notificaciones push

Si el desarrollador ha usado previamente notificaciones push de Apple (APS), el proceso de tratar con las notificaciones generadas por CloudKit debe ser familiar.

En AppDelegate.cs, invalide la clase ReceivedRemoteNotification de la siguiente manera:

public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
{
    // Parse the notification into a CloudKit Notification
    var notification = CKNotification.FromRemoteNotificationDictionary (userInfo);

    // Get the body of the message
    var alertBody = notification.AlertBody;

    // Was this a query?
    if (notification.NotificationType == CKNotificationType.Query) {
        // Yes, convert to a query notification and get the record ID
        var query = notification as CKQueryNotification;
        var recordID = query.RecordId;
    }
}

El código anterior pide a CloudKit que analice userInfo en una notificación de CloudKit. A continuación, se extrae información sobre la alerta. Por último, el tipo de notificación se prueba y la notificación se controla en consecuencia.

En esta sección se muestra cómo responder al problema de macrodatos, pequeño dispositivo presentado anteriormente mediante consultas y suscripciones. La aplicación dejará sus grandes datos en la nube y usará estas tecnologías para proporcionar vistas a este conjunto de datos.

Cuentas de usuario de CloudKit

Como se indicó al principio de este artículo, CloudKit se basa en la infraestructura de iCloud existente. En la sección siguiente se trata, en detalle, cómo se exponen las cuentas a un desarrollador mediante la API de CloudKit.

Autenticación

Al tratar con cuentas de usuario, la primera consideración es la autenticación. CloudKit admite la autenticación a través del usuario de iCloud que ha iniciado sesión actualmente en el dispositivo. La autenticación se realiza en segundo plano y se controla mediante iOS. De este modo, los desarrolladores nunca tienen que preocuparse por los detalles de la implementación de la autenticación. Solo comprueban si un usuario ha iniciado sesión.

Información de la cuenta de usuario

CloudKit proporciona la siguiente información de usuario al desarrollador:

  • Identidad: una manera de identificar de forma única al usuario.
  • Metadatos: la capacidad de guardar y recuperar información sobre los usuarios.
  • Privacidad: toda la información se controla en una mano consciente de la privacidad. No se expone nada a menos que el usuario lo haya aceptado.
  • Detección: proporciona a los usuarios la capacidad de detectar a sus amigos que usan la misma aplicación.

A continuación, veremos estos temas con detalle.

identidad

Como se indicó anteriormente, CloudKit proporciona una manera de que la aplicación identifique de forma única a un usuario determinado:

Identificación única de usuarios determinados

Hay una aplicación cliente que se ejecuta en los dispositivos de un usuario y todas las bases de datos privadas de usuario específicas dentro del contenedor de CloudKit. La aplicación cliente se vinculará a uno de esos usuarios específicos. Esto se basa en el usuario que ha iniciado sesión en iCloud localmente en el dispositivo.

Dado que esto proviene de iCloud, hay un amplio almacén de respaldo de información de usuario. Y dado que iCloud hospeda realmente el contenedor, puede correlacionar a los usuarios. En el gráfico anterior, el usuario cuya cuenta de iCloud user@icloud.com está vinculada al cliente actual.

En un contenedor por contenedor, se crea un identificador de usuario único generado aleatoriamente y se asocia a la cuenta de iCloud del usuario (dirección de correo electrónico). Este identificador de usuario se devuelve a la aplicación y se puede usar de cualquier manera que el desarrollador vea adecuado.

Nota:

Las diferentes aplicaciones que se ejecutan en el mismo dispositivo para el mismo usuario de iCloud tendrán identificadores de usuario diferentes porque están conectados a contenedores de CloudKit diferentes.

El código siguiente obtiene el identificador de usuario de CloudKit para el usuario de iCloud que ha iniciado sesión actualmente en el dispositivo:

public CKRecordID UserID { get; set; }
...

// Get the CloudKit User ID
CKContainer.DefaultContainer.FetchUserRecordId ((recordID, err) => {
    // Was there an error?
    if (err!=null) {
        Console.WriteLine("Error: {0}", err.LocalizedDescription);
    } else {
        // Save user ID
        UserID = recordID;
    }
});

El código anterior solicita al contenedor de CloudKit que proporcione el identificador del usuario que ha iniciado sesión actualmente. Dado que esta información procede del servidor iCloud, se requiere la llamada a asincrónica y se requiere el control de errores.

Metadatos

Cada usuario de CloudKit tiene metadatos específicos que los describen. Estos metadatos se representan como un registro de CloudKit:

Cada usuario de CloudKit tiene metadatos específicos que los describen

Al buscar dentro de la base de datos privada para un usuario específico de un contenedor hay un registro que define ese usuario. Hay muchos registros de usuario dentro de la base de datos pública, uno para cada usuario del contenedor. Uno de estos tendrá un identificador de registro que coincida con el identificador de registro del usuario que ha iniciado sesión actualmente.

Los registros de usuario de la base de datos pública son legibles en el mundo. Se tratan, en su mayor parte, como un Registro ordinario y tienen un tipo de CKRecordTypeUserRecord. Estos registros están reservados por el sistema y no están disponibles para las consultas.

Use el código siguiente para acceder a un registro de usuario:

public CKRecord UserRecord { get; set; }
...

// Get the user's record
PublicDatabase.FetchRecord(UserID, (record ,er) => {
    //was there an error?
    if (er != null) {
        Console.WriteLine("Error: {0}", er.LocalizedDescription);
    } else {
        // Save the user record
        UserRecord = record;
    }
});

El código anterior solicita a la base de datos pública que devuelva el registro de usuario para el usuario al que se ha accedido anteriormente. Dado que esta información procede del servidor iCloud, se requiere la llamada a asincrónica y se requiere el control de errores.

Privacidad

CloudKit se diseñó de forma predeterminada para proteger la privacidad del usuario que ha iniciado sesión actualmente. De forma predeterminada, no se expone información personal sobre el usuario. Hay algunos casos en los que la aplicación requerirá información limitada sobre el usuario.

En estos casos, la aplicación puede solicitar que el usuario revele esta información. Se presentará un cuadro de diálogo al usuario que le pedirá que opte por exponer la información de su cuenta.

Detección

Suponiendo que el usuario ha optado por permitir que la aplicación tenga acceso limitado a la información de su cuenta de usuario, puede ser reconocible para otros usuarios de la aplicación:

Un usuario puede ser reconocible para otros usuarios de la aplicación

La aplicación cliente está hablando con un contenedor y el contenedor está hablando con iCloud para acceder a la información del usuario. El usuario puede proporcionar una dirección de correo electrónico y la detección se puede usar para obtener información sobre el usuario. Opcionalmente, el identificador de usuario también se puede usar para detectar información sobre el usuario.

CloudKit también proporciona una manera de descubrir información sobre cualquier usuario que pueda ser amigo del usuario que ha iniciado sesión actualmente en iCloud consultando toda la libreta de direcciones. El proceso de CloudKit extraerá la libreta de contactos del usuario y usará las direcciones de correo electrónico para ver si puede encontrar el de otro usuario de la aplicación que coincida con esas direcciones.

Esto permite que la aplicación aproveche la libreta de contactos del usuario sin proporcionar acceso a ella ni pedir al usuario que apruebe el acceso a los contactos. En ningún momento se pone a disposición de la aplicación la información de contacto, solo el proceso de CloudKit tiene acceso.

Para volver a resumir, hay tres tipos diferentes de entradas disponibles para la detección de usuarios:

  • Id. de registro de usuario: la detección se puede realizar con el identificador de usuario del usuario que ha iniciado sesión actualmente en CloudKit.
  • Dirección de correo electrónico de usuario: el usuario puede proporcionar una dirección de correo electrónico y se puede usar para la detección.
  • Libreta de contactos: la libreta de direcciones del usuario se puede usar para detectar usuarios de la aplicación que tienen la misma dirección de correo electrónico que se muestra en sus contactos.

La detección de usuarios devolverá la siguiente información:

  • Id. de registro de usuario: el identificador único de un usuario en la base de datos pública.
  • Nombre y apellidos: como se almacena en la base de datos pública.

Esta información solo se devolverá para los usuarios que hayan optado por la detección.

El código siguiente detectará información sobre el usuario que ha iniciado sesión actualmente en iCloud en el dispositivo:

public CKDiscoveredUserInfo UserInfo { get; set; }
//...

// Get the user's metadata
CKContainer.DefaultContainer.DiscoverUserInfo(UserID, (info, e) => {
    // Was there an error?
    if (e != null) {
        Console.WriteLine("Error: {0}", e.LocalizedDescription);
    } else {
        // Save the user info
        UserInfo = info;
    }
});

Use el código siguiente para consultar a todos los usuarios del Libro de contactos:

// Ask CloudKit for all of the user's friends information
CKContainer.DefaultContainer.DiscoverAllContactUserInfos((info, er) => {
    // Was there an error
    if (er != null) {
        Console.WriteLine("Error: {0}", er.LocalizedDescription);
    } else {
        // Process all returned records
        for(int i = 0; i < info.Count(); ++i) {
            // Grab a user
            var userInfo = info[i];
        }
    }
});

En esta sección hemos tratado las cuatro áreas principales de acceso a la cuenta de un usuario que CloudKit puede proporcionar a una aplicación. Desde la obtención de la identidad y los metadatos del usuario hasta las directivas de privacidad integradas en CloudKit y, por último, la capacidad de detectar otros usuarios de la aplicación.

Los entornos de desarrollo y producción

CloudKit proporciona entornos de desarrollo y producción independientes para los tipos y datos de registros de una aplicación. El entorno de desarrollo es un entorno más flexible que solo está disponible para los miembros de un equipo de desarrollo. Cuando una aplicación agrega un nuevo campo a un registro y guarda ese registro en el entorno de desarrollo, el servidor actualiza automáticamente la información de esquema.

El desarrollador puede usar esta característica para realizar cambios en un esquema durante el desarrollo, lo que ahorra tiempo. Una advertencia es que después de agregar un campo a un registro, el tipo de datos asociado a ese campo no se puede cambiar mediante programación. Para cambiar un tipo de campo’, el desarrollador debe eliminar el campo en Panel de CloudKit y agregarlo de nuevo con el nuevo tipo.

Antes de implementar la aplicación, el desarrollador puede migrar su esquema y datos al entorno de producción mediante el Panel de CloudKit. Cuando se ejecuta en el entorno de producción, el servidor impide que una aplicación cambie el esquema mediante programación. El desarrollador todavía puede realizar cambios con el Panel de CloudKit, pero intenta agregar campos a un registro en el entorno de producción produce errores.

Nota:

El simulador de iOS solo funciona con el Entorno de desarrollo. Cuando el desarrollador esté listo para probar una aplicación en un Entorno de producción, se requiere un dispositivo iOS físico.

Envío de una aplicación habilitada para CloudKit

Antes de enviar una aplicación que use CloudKit, deberá configurarse para que tenga como destino el Entorno de CloudKit de producción o Apple rechazará la aplicación.

Haga lo siguiente:

  1. En Visual Studio para Ma, compile la aplicación para Versión>Dispositivo iOS:

    Compile la aplicación para su lanzamiento

  2. En el menú Compilar, elija Archivar:

    Seleccione Archivo

  3. El archivo se creará y se mostrará en Visual Studio para Mac:

    El archivo se creará y se mostrará

  4. Inicie Xcode.

  5. Desde el menú Ventana, seleccione Organizador:

    Seleccione Organizador

  6. Seleccione el archivo de la aplicación y haga clic en el botón Exportar...:

    El archivo de la aplicación

  7. Seleccione un método para exportar y haga clic en el botón Siguiente:

    Selección de un método para exportar

  8. Seleccione el Equipo de desarrollo en la lista desplegable y haga clic en el botón Elegir:

    Seleccione el Equipo de desarrollo de la lista desplegable

  9. Seleccione Producción en la lista desplegable y haga clic en el botón Siguiente:

    Seleccione Producción en la lista desplegable

  10. Revise la configuración y haga clic en el botón Exportar:

    Revise la configuración

  11. Elija una ubicación para generar el archivo de aplicación .ipa resultante.

El proceso es similar para enviar la aplicación directamente a iTunes Connect, simplemente haga clic en el botón Enviar... en lugar de exportar... después de seleccionar un archivo en la ventana Organizador.

Cuándo usar CloudKit

Como hemos visto en este artículo, CloudKit proporciona una manera fácil de almacenar y recuperar información de los servidores de iCloud. Dicho esto, CloudKit no está obsoleto ni deja de usar ninguna de las herramientas o marcos existentes.

Casos de uso

Los siguientes casos de uso deben ayudar al desarrollador a decidir cuándo usar un marco o tecnología específicos de iCloud:

  • Almacén de clave-valor de iCloud: mantiene de forma asincrónica una pequeña cantidad de datos actualizada y es excelente para trabajar con preferencias de aplicación. Sin embargo, está restringido para una cantidad muy pequeña de información.
  • iCloud Drive: se basa en las API de documentos de iCloud existentes y proporciona una API sencilla para sincronizar datos no estructurados desde el sistema de archivos. Proporciona una caché sin conexión completa en Mac OS X y es excelente para aplicaciones centradas en documentos.
  • Datos principales de iCloud: permite replicar los datos entre todos los dispositivos del usuario. Los datos son de un solo usuario y son excelentes para mantener sincronizados los datos privados y estructurados.
  • CloudKit : proporciona datos públicos tanto de estructura como masivos y es capaz de controlar archivos grandes y grandes no estructurados. Está vinculado a la cuenta de iCloud del usuario y proporciona la transferencia de datos dirigida por el cliente.

Teniendo en cuenta estos casos de uso, el desarrollador debe elegir la tecnología correcta de iCloud para proporcionar la funcionalidad de aplicación necesaria actual y proporcionar una buena escalabilidad para el crecimiento futuro.

Resumen

Este artículo ha cubierto una introducción rápida a la API de CloudKit. Se ha mostrado cómo aprovisionar y configurar una aplicación de Xamarin iOS para usar CloudKit. Ha cubierto las características de la API de conveniencia de CloudKit. Se muestra cómo diseñar una aplicación habilitada para CloudKit para escalabilidad mediante consultas y suscripciones. Y, por último, ha mostrado la información de la cuenta de usuario que se expone a una aplicación de CloudKit.