CloudKit in Xamarin.iOS

Il framework CloudKit semplifica lo sviluppo di applicazioni che accedono a iCloud. Sono inclusi il recupero dei dati dell'applicazione e dei diritti di asset, nonché la possibilità di archiviare in modo sicuro le informazioni dell'applicazione. Questo kit offre agli utenti un livello di anonimato consentendo l'accesso alle applicazioni con gli ID iCloud senza condividere informazioni personali.

Gli sviluppatori possono concentrarsi sulle applicazioni lato client e consentire a iCloud di eliminare la necessità di scrivere la logica dell'applicazione lato server. CloudKit fornisce l'autenticazione, i database privati e pubblici e i servizi di archiviazione di asset e dati strutturati.

Importante

Apple fornisce strumenti per aiutare gli sviluppatori a gestire correttamente il Regolamento generale sulla protezione dei dati (GDPR) dell'Unione Europea.

Requisiti

Per completare i passaggi presentati in questo articolo, è necessario quanto segue:

  • Xcode e iOS SDK : le API Xcode e iOS 8 di Apple devono essere installate e configurate nel computer dello sviluppatore.
  • Visual Studio per Mac: la versione più recente di Visual Studio per Mac deve essere installata e configurata nel dispositivo utente.
  • Dispositivo iOS 8: un dispositivo iOS che esegue la versione più recente di iOS 8 per i test.

Che cos'è CloudKit?

CloudKit è un modo per concedere allo sviluppatore l'accesso ai server iCloud. Fornisce le basi sia per iCloud Drive che per iCloud Photo Library. CloudKit è supportato nei dispositivi macOS e iOS.

How CloudKit is supported on both macOS and iOS devices

CloudKit usa l'infrastruttura dell'account iCloud. Se nel dispositivo è presente un utente connesso a un account iCloud, CloudKit userà il proprio ID per identificare l'utente. Se non è disponibile alcun account, verrà fornito un accesso di sola lettura limitato.

CloudKit supporta sia il concetto di database pubblici che privati. I database pubblici forniscono una "zuppa" di tutti i dati a cui l'utente ha accesso. I database privati devono archiviare i dati privati associati a un utente specifico.

CloudKit supporta dati strutturati e in blocco. È in grado di gestire facilmente trasferimenti di file di grandi dimensioni. CloudKit si occupa del trasferimento efficiente di file di grandi dimensioni da e verso i Server iCloud in background, consentendo allo sviluppatore di concentrarsi su altre attività.

Nota

È importante notare che CloudKit è una tecnologia di trasporto. Non fornisce alcuna persistenza; consente solo a un'applicazione di inviare e ricevere informazioni dai server in modo efficiente.

A partire da questo articolo, Apple fornisce inizialmente CloudKit gratuitamente con un limite elevato sia sulla larghezza di banda che sulla capacità di archiviazione. Per progetti o applicazioni di grandi dimensioni con una base di utenti di grandi dimensioni, Apple ha indicato che verrà fornita una scalabilità dei prezzi conveniente.

Abilitazione di CloudKit in un'applicazione Xamarin

Prima che un'applicazione Xamarin possa usare il framework CloudKit, è necessario eseguire correttamente il provisioning dell'applicazione come descritto nelle guide Uso delle funzionalità e Uso dei diritti.

Per accedere a CloudKit, il file Entitlements.plist deve includere le autorizzazioni Abilita iCloud, Archiviazione chiave-valore e CloudKit .

Esempio di app

L'esempio CloudKitAtlas illustra come usare CloudKit con Xamarin. La procedura seguente illustra come configurare l'esempio: richiede impostazioni aggiuntive oltre a quanto richiesto solo per CloudKit:

  1. Aprire il progetto in Visual Studio per Mac o Visual Studio.
  2. Nella Esplora soluzioni aprire il file Info.plist e verificare che l'identificatore bundle corrisponda a quello definito nell'ID app creato come parte della configurazione del provisioning.
  3. Scorrere verso il basso fino alla fine del file Info.plist e selezionare Modalità di sfondo abilitate, Percorso Aggiornamenti e Notifiche remote.
  4. Fare clic con il pulsante destro del mouse sul progetto iOS nella soluzione e scegliere Opzioni.
  5. Selezionare Firma bundle iOS, selezionare l'identità dello sviluppatore e il profilo di provisioning creati in precedenza.
  6. Verificare che Entitlements.plist includa Enable iCloud, Key-value storage e CloudKit.
  7. Verificare che il contenitore Ubiquity esista per l'applicazione. Esempio: iCloud.com.your-company.CloudKitAtlas
  8. Salvare le modifiche apportate al file.

Con queste impostazioni, l'app di esempio è ora pronta per accedere alle API CloudKit Framework, nonché ai servizi di background, posizione e notifica.

Panoramica dell'API CloudKit

Prima di implementare CloudKit in un'applicazione Xamarin iOS, questo articolo illustra i concetti fondamentali di CloudKit Framework, che includerà gli argomenti seguenti:

  1. Contenitori : silo isolato delle comunicazioni iCloud.
  2. Database : pubblici e privati sono disponibili per l'applicazione.
  3. Record : meccanismo in cui i dati strutturati vengono spostati da e verso CloudKit.
  4. Zone di record: sono gruppi di record.
  5. Identificatori di record: sono completamente normalizzati e rappresentano la posizione specifica del record.
  6. Riferimento : specificare relazioni padre-figlio tra record correlati all'interno di un determinato database.
  7. Asset : consente il caricamento di dati non strutturati di grandi dimensioni in iCloud e associati a un determinato record.

Contenitori

Una determinata applicazione in esecuzione in un dispositivo iOS viene sempre eseguita insieme ad altre applicazioni e servizi su tale dispositivo. Nel dispositivo client, l'applicazione sarà in qualche modo silo o in modalità sandbox. In alcuni casi, si tratta di una sandbox letterale e, in altri, l'applicazione è semplicemente in esecuzione nello spazio di memoria.

Il concetto di acquisizione di un'applicazione client e l'esecuzione separati da altri client è molto potente e offre i vantaggi seguenti:

  1. Sicurezza : un'applicazione non può interferire con altre app client o il sistema operativo stesso.
  2. Stabilità : se l'applicazione client si arresta in modo anomalo, non può escludere altre app del sistema operativo.
  3. Privacy : ogni applicazione client ha accesso limitato alle informazioni personali archiviate all'interno del dispositivo.

CloudKit è stato progettato per offrire gli stessi vantaggi elencati in precedenza e applicarli all'uso delle informazioni basate sul cloud:

CloudKit apps communicate using containers

Proprio come l'applicazione è uno-di-molti in esecuzione sul dispositivo, quindi è la comunicazione dell'applicazione con iCloud uno-of-molti. Ognuno di questi diversi silo di comunicazione è denominato Contenitori.

I contenitori vengono esposti in CloudKit Framework tramite la CKContainer classe . Per impostazione predefinita, un'applicazione comunica con un contenitore e questo contenitore separa i dati per tale applicazione. Ciò significa che diverse applicazioni possono archiviare informazioni nello stesso account iCloud, ma queste informazioni non verranno mai interminate.

La containerizzazione dei dati iCloud consente anche a CloudKit di incapsulare le informazioni utente. In questo modo, l'applicazione avrà un accesso limitato all'account iCloud e le informazioni utente archiviate all'interno, tutto pur proteggendo la privacy e la sicurezza dell'utente.

I contenitori sono completamente gestiti dallo sviluppatore dell'applicazione tramite il portale WWDR. Lo spazio dei nomi del contenitore è globale in tutti gli sviluppatori Apple, pertanto il contenitore non deve essere univoco solo per le applicazioni di uno sviluppatore specifico, ma per tutti gli sviluppatori e le applicazioni Apple.

Apple suggerisce di usare la notazione DNS inversa durante la creazione dello spazio dei nomi per i contenitori dell'applicazione. Esempio: iCloud.com.company-name.application-name

Anche se i contenitori sono, per impostazione predefinita, associati uno a uno a una determinata applicazione, possono essere condivisi tra le applicazioni. Quindi più applicazioni possono coordinarsi su un singolo contenitore. Una singola applicazione può anche comunicare con più contenitori.

Database

Una delle funzioni principali di CloudKit consiste nell'accettare il modello di dati di un'applicazione e la replica che modellano fino ai server iCloud. Alcune informazioni sono destinate all'utente che l'ha creata, altre informazioni sono dati pubblici che possono essere creati da un utente per uso pubblico (ad esempio una revisione del ristorante) o potrebbero essere informazioni pubblicate dallo sviluppatore per l'applicazione. In entrambi i casi, il pubblico non è solo un singolo utente, ma è una comunità di persone.

CloudKit Container Diagram

All'interno di un contenitore, prima di tutto è il database pubblico. Questa è la posizione in cui tutte le informazioni pubbliche vivono e co-mingle. Sono inoltre disponibili diversi database privati per ogni utente dell'applicazione.

Quando si esegue in un dispositivo iOS, l'applicazione avrà accesso solo alle informazioni per l'utente iCloud attualmente connesso. Di conseguenza, la visualizzazione del contenitore dell'applicazione sarà la seguente:

The applications view of the container

Può visualizzare solo il database pubblico e il database privato associato all'utente iCloud attualmente connesso.

I database vengono esposti in CloudKit Framework tramite la CKDatabase classe . Ogni applicazione ha accesso a due database: il database pubblico e quello privato.

Il contenitore è il punto di ingresso iniziale in CloudKit. Il codice seguente può essere usato per accedere al database pubblico e privato dal contenitore predefinito dell'applicazione:

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;

Ecco le differenze tra i tipi di database:

Database pubblico Database privato
Tipo di dati Dati condivisi Dati dell'utente corrente
Quota Account per nella quota dello sviluppatore Account per nella quota dell'utente
Autorizzazioni predefinite Leggibile a livello globale Leggibile dall'utente
Modifica delle autorizzazioni Ruoli del dashboard iCloud tramite un livello di classe record N/D

Record

I contenitori contengono database e all'interno dei database sono record. I record sono il meccanismo in cui i dati strutturati vengono spostati da e verso CloudKit:

Containers hold databases, and inside databases are records

I record vengono esposti in CloudKit Framework tramite la classe , che esegue il CKRecord wrapping delle coppie chiave-valore. Un'istanza di un oggetto in un'applicazione equivale a un CKRecord oggetto in CloudKit. Inoltre, ognuno CKRecord possiede un tipo di record, equivalente alla classe di un oggetto .

I record hanno uno schema JUST-In-Time, quindi i dati vengono descritti in CloudKit prima di essere passati per l'elaborazione. Da questo punto CloudKit interpreterà le informazioni e gestirà la logistica dell'archiviazione e del recupero del record.

La CKRecord classe supporta anche un'ampia gamma di metadati. Ad esempio, un record contiene informazioni su quando è stato creato e l'utente che lo ha creato. Un record contiene anche informazioni sull'ultima modifica e sull'utente che l'ha modificata.

I record contengono il concetto di tag di modifica. Si tratta di una versione precedente di una revisione di un determinato record. Il tag di modifica viene usato come modo leggero per determinare se il client e il server hanno la stessa versione di un determinato record.

Come indicato in precedenza, CKRecords eseguire il wrapping di coppie chiave-valore e, di conseguenza, i tipi di dati seguenti possono essere archiviati in un record:

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

Oltre ai tipi a valore singolo, un record può contenere una matrice omogenea di uno dei tipi elencati in precedenza.

Il codice seguente può essere usato per creare un nuovo record e archiviarlo in un database:

using CloudKit;
//...

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

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

Registrare le zone

I record non esistono da soli all'interno di un determinato database. I gruppi di record esistono insieme all'interno di una zona record. Le zone di record possono essere considerate tabelle in database relazionali tradizionali:

Groups of records exist together inside a Record Zone

Possono essere presenti più record all'interno di una determinata zona di record e più zone di record all'interno di un determinato database. Ogni database contiene una zona record predefinita:

Every database contains a Default Record Zone and Custom Zone

In questo caso, i record vengono archiviati per impostazione predefinita. È inoltre possibile creare zone di record personalizzate. Le zone di record rappresentano la granularità di base in cui vengono eseguiti i commit atomici e le Rilevamento modifiche.

Identificatori di record

Gli identificatori di record sono rappresentati come tupla, contenente sia un nome record fornito dal client che la zona in cui è presente il record. Gli identificatori di record presentano le caratteristiche seguenti:

  • Vengono creati dall'applicazione client.
  • Sono completamente normalizzati e rappresentano la posizione specifica del record.
  • Assegnando l'ID univoco di un record in un database esterno al nome del record, possono essere usati per collegare i database locali non archiviati in CloudKit.

Quando gli sviluppatori creano nuovi record, possono scegliere di passare un identificatore di record. Se non viene specificato un identificatore di record, verrà creato e assegnato automaticamente un UUID al record.

Quando gli sviluppatori creano nuovi identificatori di record, possono scegliere di specificare la zona record a cui appartiene ogni record. Se non viene specificato alcun valore, verrà utilizzata l'area record predefinita.

Gli identificatori di record vengono esposti in CloudKit Framework tramite la CKRecordID classe . Per creare un nuovo identificatore di record, è possibile usare il codice seguente:

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

Riferimenti

I riferimenti forniscono relazioni tra record correlati all'interno di un determinato database:

References provide relationships between related Records within a given Database

Nell'esempio precedente, Parents own Children in modo che Child sia un record figlio del record padre. La relazione passa dal record figlio al record padre e viene definita riferimento indietro.

I riferimenti vengono esposti in CloudKit Framework tramite la CKReference classe . Sono un modo per consentire al server iCloud di comprendere la relazione tra i record.

I riferimenti forniscono il meccanismo dietro le eliminazioni a catena. Se un record padre viene eliminato dal database, tutti i record figlio (come specificato in una relazione) verranno eliminati automaticamente anche dal database.

Nota

I puntatori dangling sono una possibilità quando si usa CloudKit. Ad esempio, quando l'applicazione ha recuperato un elenco di puntatori di record, ha selezionato un record e quindi richiesto il record, il record potrebbe non esistere più nel database. Un'applicazione deve essere codificata per gestire correttamente questa situazione.

Anche se non è necessario, i riferimenti indietro sono preferiti quando si usa CloudKit Framework. Apple ha ottimizzato il sistema per rendere questo il tipo di riferimento più efficiente.

Quando si crea un riferimento, lo sviluppatore può fornire un record già in memoria o creare un riferimento a un identificatore di record. Se si usa un identificatore di record e il riferimento specificato non esiste nel database, verrà creato un puntatore dangling.

Di seguito è riportato un esempio di creazione di un riferimento su un record noto:

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

Asset

Gli asset consentono il caricamento di un file di dati non strutturati di grandi dimensioni in iCloud e associati a un determinato record:

Assets allow for a file of large, unstructured data to be uploaded to iCloud and associated with a given Record

Nel client viene creato un oggetto CKRecord che descrive il file che verrà caricato nel server iCloud. Viene CKAsset creato un oggetto per contenere il file ed è collegato al record che lo descrive.

Quando il file viene caricato nel server, il record viene inserito nel database e il file viene copiato in un database di Archiviazione bulk speciale. Viene creato un collegamento tra il puntatore del record e il file caricato.

Gli asset vengono esposti in CloudKit Framework tramite la CKAsset classe e vengono usati per archiviare dati di grandi dimensioni non strutturati. Poiché lo sviluppatore non vuole mai avere dati di grandi dimensioni non strutturati in memoria, gli asset vengono implementati usando i file su disco.

Gli asset sono di proprietà dei record, che consente di recuperare gli asset da iCloud usando il record come puntatore. In questo modo il server può eseguire Garbage Collect Assets quando il record proprietario dell'asset viene eliminato.

Poiché CKAssets sono progettati per gestire file di dati di grandi dimensioni, Apple ha progettato CloudKit per caricare e scaricare in modo efficiente gli asset.

Il codice seguente può essere usato per creare un asset e associarlo al record:

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

A questo punto sono stati trattati tutti gli oggetti fondamentali all'interno di CloudKit. I contenitori sono associati alle applicazioni e contengono database. I database contengono record raggruppati in zone record e a cui puntano gli identificatori di record. Le relazioni padre-figlio vengono definite tra record che usano riferimenti. Infine, i file di grandi dimensioni possono essere caricati e associati ai record usando asset.

CloudKit Convenience API

Apple offre due set di API diversi per l'uso di CloudKit:

  • API operativa: offre ogni singola funzionalità di CloudKit. Per applicazioni più complesse, questa API offre un controllo granulare su CloudKit.
  • API di praticità: offre un subset comune preconfigurato di funzionalità di CloudKit. Offre una soluzione di accesso semplice e conveniente per includere la funzionalità CloudKit in un'applicazione iOS.

L'API Convenience è in genere la scelta migliore per la maggior parte delle applicazioni iOS e Apple suggerisce di iniziare con esso. Nella parte restante di questa sezione verranno illustrati gli argomenti dell'API Convenience seguenti:

  • Salvataggio di un record.
  • Recupero di un record.
  • Aggiornamento di un record.

Codice di installazione comune

Prima di iniziare a usare l'API CloudKit Convenience, è necessario un codice di installazione standard. Per iniziare, modificare il file dell'applicazione AppDelegate.cs e renderlo simile al seguente:

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");
        }
    }
}

Il codice precedente espone i database CloudKit pubblici e privati come collegamenti per semplificarne l'uso nel resto dell'applicazione.

Aggiungere quindi il codice seguente a qualsiasi visualizzazione o contenitore di visualizzazione che verrà usato CloudKit:

using CloudKit;
//...

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

Viene aggiunto un collegamento per accedere ai collegamenti di AppDelegate database pubblici e privati creati in precedenza.

Con questo codice, si esaminerà ora l'implementazione dell'API Convenience CloudKit in un'applicazione Xamarin iOS 8.

Salvataggio di un record

Usando il modello presentato in precedenza durante la discussione dei record, il codice seguente creerà un nuovo record e userà l'API Convenience per salvarlo nel database pubblico:

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) {
        ...
    }
});

Tre aspetti da notare sul codice precedente:

  1. Chiamando il SaveRecord metodo di PublicDatabase, lo sviluppatore non deve specificare la modalità di invio dei dati, l'area in cui viene scritto e così via. L'API Convenience si occupa di tutti questi dettagli.
  2. La chiamata è asincrona e fornisce una routine di callback al termine della chiamata, con esito positivo o negativo. Se la chiamata non riesce, verrà fornito un messaggio di errore.
  3. CloudKit non fornisce archiviazione/persistenza locale; è solo un mezzo di trasferimento. Quindi, quando viene effettuata una richiesta di salvataggio di un record, viene immediatamente inviata ai server iCloud.

Nota

A causa della natura "perdita" delle comunicazioni di rete mobile, in cui le connessioni vengono continuamente eliminate o interrotte, una delle prime considerazioni che lo sviluppatore deve fare quando si lavora con CloudKit è la gestione degli errori.

Recupero di un record

Con un record creato e archiviato correttamente nel server iCloud, usare il codice seguente per recuperare il record:

// 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) {
        ...
    }
});

Come nel salvataggio del record, il codice precedente è asincrono, semplice e richiede un'ottima gestione degli errori.

Aggiornamento di un record

Dopo che un record è stato recuperato dai server iCloud, è possibile usare il codice seguente per modificare il record e salvare le modifiche nel database:

// 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) {
                 ...
            }
        });
    }
});

Il FetchRecord metodo dell'oggetto PublicDatabase restituisce un oggetto CKRecord se la chiamata ha avuto esito positivo. L'applicazione modifica quindi l'oggetto Record e chiama SaveRecord di nuovo per scrivere nuovamente le modifiche nel database.

Questa sezione ha illustrato il ciclo tipico che un'applicazione userà quando si usa l'API Convenience CloudKit. L'applicazione salverà i record in iCloud, recupererà i record da iCloud, modificherà i record e salverà le modifiche in iCloud.

Progettazione per la scalabilità

Finora questo articolo ha esaminato l'archiviazione e il recupero dell'intero modello a oggetti di un'applicazione dai server iCloud, ogni volta che verrà usato. Anche se questo approccio funziona bene con una piccola quantità di dati e una base utente molto piccola, non viene ridimensionata correttamente quando aumenta la quantità di informazioni e/o la base utente.

Big Data, piccolo dispositivo

Più popolare diventa un'applicazione, più dati nel database e meno fattibile è avere una cache di tutti i dati nel dispositivo. Per risolvere questo problema, è possibile usare le tecniche seguenti:

  • Mantenere i dati di grandi dimensioni nel cloud : CloudKit è stato progettato per gestire in modo efficiente dati di grandi dimensioni.
  • Il client deve visualizzare solo una sezione di tali dati : ridurre al minimo i dati necessari per gestire qualsiasi attività in un determinato momento.
  • Le visualizzazioni client possono cambiare : poiché ogni utente ha preferenze diverse, la sezione di dati visualizzata può cambiare da utente a utente e la singola visualizzazione dell'utente di una determinata sezione può essere diversa.
  • Il client usa query per concentrarsi sul punto di vista : le query consentono all'utente di visualizzare un piccolo subset di un set di dati più grande presente all'interno del cloud.

Query

Come indicato in precedenza, le query consentono allo sviluppatore di selezionare un piccolo subset del set di dati più grande esistente nel cloud. Le query vengono esposte in CloudKit Framework tramite la CKQuery classe .

Una query combina tre elementi diversi: un tipo di record ( RecordType), un predicato ( NSPredicate) e, facoltativamente, un descrittore di ordinamento ( NSSortDescriptors). CloudKit supporta la maggior parte di NSPredicate.

Predicati supportati

CloudKit supporta i tipi seguenti di NSPredicates quando si lavora con le query:

  1. Record corrispondenti in cui il nome è uguale a un valore archiviato in una variabile:

    NSPredicate.FromFormat(string.Format("name = '{0}'", recordName))
    
  2. Consente la corrispondenza in base a un valore di chiave dinamica, in modo che la chiave non deve essere nota in fase di compilazione:

    NSPredicate.FromFormat(string.Format("{0} = '{1}'", key, value))
    
  3. Record corrispondenti in cui il valore del record è maggiore del valore specificato:

    NSPredicate.FromFormat(string.Format("start > {0}", (NSDate)date))
    
  4. Record corrispondenti in cui la posizione del record si trova entro 100 metri dalla posizione specificata:

    var location = new CLLocation(37.783,-122.404);
    var predicate = NSPredicate.FromFormat(string.Format("distanceToLocation:fromLocation(Location,{0}) < 100", location));
    
  5. CloudKit supporta una ricerca con token. Questa chiamata creerà due token, uno per after e un altro per session. Restituisce un record che contiene i due token seguenti:

    NSPredicate.FromFormat(string.Format("ALL tokenize({0}, 'Cdl') IN allTokens", "after session"))
    
  6. CloudKit supporta predicati composti uniti usando l'operatore AND .

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

Creazione di query

Il codice seguente può essere usato per creare un in CKQuery un'applicazione Xamarin iOS 8:

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

Prima di tutto, crea un predicato per selezionare solo i record che corrispondono a un determinato nome. Crea quindi una query che selezionerà i record del tipo di record specificato che corrispondono al predicato.

Esecuzione di una query

Dopo aver creato una query, usare il codice seguente per eseguire la query ed elaborare i record restituiti:

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];
        }
    }
});

Il codice precedente accetta la query creata in precedenza e la esegue sul database pubblico. Poiché non viene specificata alcuna zona record, viene eseguita la ricerca di tutte le zone. Se non si verificano errori, verrà restituita una matrice di CKRecords corrispondenti ai parametri della query.

Il modo in cui considerare le query è che sono sondaggi e sono ideali per il sezionamento tramite set di dati di grandi dimensioni. Le query, tuttavia, non sono adatte per set di dati di grandi dimensioni, principalmente statici a causa dei motivi seguenti:

  • Sono male per la durata della batteria del dispositivo.
  • Sono male per il traffico di rete.
  • L'esperienza utente non è valida perché le informazioni visualizzate sono limitate dalla frequenza con cui l'applicazione esegue il polling del database. Gli utenti di oggi si aspettano notifiche push quando cambia qualcosa.

Sottoscrizioni

Quando si gestiscono set di dati statici di grandi dimensioni, la query non deve essere eseguita nel dispositivo client, deve essere eseguita sul server per conto del client. La query deve essere eseguita in background e deve essere eseguita dopo il salvataggio di ogni singolo record, indipendentemente dal dispositivo corrente o da un altro dispositivo che tocca lo stesso database.

Infine, una notifica push deve essere inviata a ogni dispositivo collegato al database quando viene eseguita la query sul lato server.

Le sottoscrizioni vengono esposte in CloudKit Framework tramite la CKSubscription classe . Combinano un tipo di record ( RecordType), un predicato ( NSPredicate) e una notifica push Apple ( Push).

Nota

I push di CloudKit sono leggermente aumentati perché contengono un payload contenente informazioni specifiche di CloudKit, ad esempio ciò che ha causato l'esecuzione del push.

Funzionamento delle sottoscrizioni

Prima di implementare la sottoscrizione nel codice C#, si esaminerà rapidamente il funzionamento delle sottoscrizioni:

An overview of how subscriptions work

Il grafico precedente mostra il processo di sottoscrizione tipico come segue:

  1. Il dispositivo client crea una nuova sottoscrizione contenente il set di condizioni che attiverà la sottoscrizione e una notifica push che verrà inviata quando si verifica il trigger.
  2. La sottoscrizione viene inviata al database in cui viene aggiunta alla raccolta di sottoscrizioni esistenti.
  3. Un secondo dispositivo crea un nuovo record e lo salva nel database.
  4. Il database cerca nell'elenco delle sottoscrizioni per verificare se il nuovo record corrisponde a una delle relative condizioni.
  5. Se viene trovata una corrispondenza, la notifica push viene inviata al dispositivo che ha registrato la sottoscrizione con informazioni sul record che ne ha causato l'attivazione.

Con queste informazioni, si esaminerà ora la creazione di sottoscrizioni in un'applicazione Xamarin iOS 8.

Creazione di sottoscrizioni

Per creare una sottoscrizione, è possibile usare il codice seguente:

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

Prima di tutto, crea un predicato che fornisce la condizione per attivare la sottoscrizione. Successivamente, crea la sottoscrizione in base a un tipo di record specifico e imposta l'opzione di quando il trigger viene testato. Definisce infine il tipo di notifica che si verificherà quando viene attivata la sottoscrizione e la associa alla sottoscrizione.

Salvataggio delle sottoscrizioni

Dopo aver creato la sottoscrizione, il codice seguente lo salverà nel database:

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

    }
});

Usando l'API Convenience, la chiamata è asincrona, semplice e offre una semplice gestione degli errori.

Gestione delle notifiche push

Se lo sviluppatore ha usato in precedenza Apple Push Notifications (piattaforma di strumenti analitici), il processo di gestione delle notifiche generate da CloudKit dovrebbe essere familiare.

In eseguire l'override AppDelegate.csdella ReceivedRemoteNotification classe come indicato di seguito:

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

Il codice precedente chiede a CloudKit di analizzare userInfo in una notifica CloudKit. Successivamente, vengono estratte informazioni sull'avviso. Infine, viene testato il tipo di notifica e la notifica viene gestita di conseguenza.

In questa sezione è stato illustrato come rispondere al problema di Big Data, Tiny Device presentato in precedenza usando query e sottoscrizioni. L'applicazione lascerà i dati di grandi dimensioni nel cloud e userà queste tecnologie per fornire visualizzazioni in questo set di dati.

Account utente CloudKit

Come indicato all'inizio di questo articolo, CloudKit si basa sull'infrastruttura iCloud esistente. La sezione seguente illustra in dettaglio il modo in cui gli account vengono esposti a uno sviluppatore usando l'API CloudKit.

Autenticazione

Quando si gestiscono gli account utente, la prima considerazione è l'autenticazione. CloudKit supporta l'autenticazione tramite l'utente iCloud attualmente connesso nel dispositivo. L'autenticazione avviene in background e viene gestita da iOS. In questo modo, gli sviluppatori non devono mai preoccuparsi dei dettagli dell'implementazione dell'autenticazione. Provano solo per verificare se un utente è connesso.

Informazioni sull'account utente

CloudKit fornisce le informazioni utente seguenti per lo sviluppatore:

  • Identità : un modo per identificare in modo univoco l'utente.
  • Metadati : possibilità di salvare e recuperare informazioni sugli utenti.
  • Privacy : tutte le informazioni vengono gestite in un maniero consapevole della privacy. Non viene esposto nulla a meno che l'utente non abbia accettato di farlo.
  • Individuazione : consente agli utenti di individuare i propri amici che usano la stessa applicazione.

Verranno ora esaminati in dettaglio questi argomenti.

Identità

Come indicato in precedenza, CloudKit consente all'applicazione di identificare in modo univoco un determinato utente:

Uniquely identifing a given user

Esiste un'applicazione client in esecuzione nei dispositivi di un utente e in tutti i database privati utente specifici all'interno del contenitore CloudKit. L'applicazione client verrà collegata a uno di questi utenti specifici. Questo si basa sull'utente connesso a iCloud in locale nel dispositivo.

Poiché questo proviene da iCloud, c'è un ricco archivio di informazioni utente. E poiché iCloud ospita effettivamente il contenitore, può correlare gli utenti. Nell'immagine precedente, l'utente il cui account user@icloud.com iCloud è collegato al client corrente.

In base a un contenitore, viene creato un ID utente univoco generato in modo casuale e associato all'account iCloud dell'utente (indirizzo di posta elettronica). Questo ID utente viene restituito all'applicazione e può essere usato in qualsiasi modo lo sviluppatore possa adattarsi.

Nota

Applicazioni diverse in esecuzione nello stesso dispositivo per lo stesso utente iCloud avranno ID utente diversi perché sono connessi a contenitori CloudKit diversi.

Il codice seguente ottiene l'ID utente CloudKit per l'utente iCloud attualmente connesso nel 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;
    }
});

Il codice precedente richiede al contenitore CloudKit di specificare l'ID dell'utente attualmente connesso. Poiché queste informazioni provengono dal server iCloud, la chiamata è asincrona e la gestione degli errori è necessaria.

Metadati UFX

Ogni utente in CloudKit ha metadati specifici che li descrivono. Questi metadati sono rappresentati come record CloudKit:

Each user in CloudKit has specific Metadata that describes them

Cercando all'interno del database privato un utente specifico di un contenitore è presente un record che definisce tale utente. Esistono molti record utente all'interno del database pubblico, uno per ogni utente del contenitore. Uno di questi includerà un ID record che corrisponde all'ID record dell'utente attualmente connesso.

I record utente nel database pubblico sono leggibili al mondo. Vengono trattati, per la maggior parte, come un record ordinario e hanno un tipo di CKRecordTypeUserRecord. Questi record sono riservati dal sistema e non sono disponibili per le query.

Usare il codice seguente per accedere a un record utente:

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;
    }
});

Il codice precedente richiede al database pubblico di restituire il record utente per l'utente a cui si è eseguito l'accesso in precedenza. Poiché queste informazioni provengono dal server iCloud, la chiamata è asincrona e la gestione degli errori è necessaria.

Riservatezza

CloudKit è stato progettato per impostazione predefinita per proteggere la privacy dell'utente attualmente connesso. Per impostazione predefinita, non vengono esposte informazioni personali sull'utente. In alcuni casi l'applicazione richiederà informazioni limitate sull'utente.

In questi casi, l'applicazione può richiedere all'utente di divulgare queste informazioni. Verrà visualizzata una finestra di dialogo all'utente che chiede di acconsentire esplicitamente all'esposizione delle informazioni sull'account.

Individuazione

Supponendo che l'utente abbia scelto di consentire all'applicazione l'accesso limitato alle informazioni sull'account utente, può essere individuabile ad altri utenti dell'applicazione:

A user can be discoverable to other users of the application

L'applicazione client sta parlando con un contenitore e il contenitore sta parlando di iCloud per accedere alle informazioni utente. L'utente può fornire un indirizzo di posta elettronica e l'individuazione può essere usata per ottenere informazioni sull'utente. Facoltativamente, l'ID utente può essere usato anche per individuare informazioni sull'utente.

CloudKit offre anche un modo per individuare informazioni su qualsiasi utente che potrebbe essere amico dell'utente attualmente connesso a iCloud eseguendo una query sull'intera Rubrica. Il processo CloudKit eseguirà il pull nella Rubrica dell'utente e userà gli indirizzi di posta elettronica per verificare se è in grado di trovare altri utenti dell'applicazione che corrispondono a tali indirizzi.

Ciò consente all'applicazione di sfruttare la Rubrica dell'utente senza fornire l'accesso o chiedere all'utente di approvare l'accesso ai contatti. In nessun momento sono le informazioni di contatto rese disponibili per l'applicazione, solo il processo CloudKit ha accesso.

Per riepilogare, esistono tre diversi tipi di input disponibili per l'individuazione utente:

  • ID record utente: l'individuazione può essere eseguita con l'ID utente dell'utente attualmente connesso a CloudKit.
  • Indirizzo di posta elettronica utente: l'utente può fornire un indirizzo di posta elettronica e può essere usato per l'individuazione.
  • Rubrica contatto: la rubrica dell'utente può essere usata per individuare gli utenti dell'applicazione con lo stesso indirizzo di posta elettronica indicato nei contatti.

L'individuazione utente restituirà le informazioni seguenti:

  • ID record utente: ID univoco di un utente nel database pubblico.
  • Nome e Cognome : come archiviato nel database pubblico.

Queste informazioni verranno restituite solo per gli utenti che hanno accodato esplicitamente l'individuazione.

Il codice seguente scoprirà le informazioni sull'utente attualmente connesso a iCloud nel 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;
    }
});

Usare il codice seguente per eseguire query su tutti gli utenti nella Rubrica:

// 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];
        }
    }
});

In questa sezione sono state illustrate le quattro aree principali di accesso all'account di un utente che CloudKit può fornire a un'applicazione. Dal recupero dell'identità e dei metadati dell'utente, ai criteri di privacy integrati in CloudKit e infine alla possibilità di individuare altri utenti dell'applicazione.

Ambienti di sviluppo e produzione

CloudKit offre ambienti di sviluppo e produzione separati per i tipi di record e i dati di un'applicazione. L'ambiente di sviluppo è un ambiente più flessibile disponibile solo per i membri di un team di sviluppo. Quando un'applicazione aggiunge un nuovo campo a un record e lo salva nell'ambiente di sviluppo, il server aggiorna automaticamente le informazioni sullo schema.

Lo sviluppatore può usare questa funzionalità per apportare modifiche a uno schema durante lo sviluppo, risparmiando tempo. Un'avvertenza è che dopo l'aggiunta di un campo a un record, il tipo di dati associato a tale campo non può essere modificato a livello di codice. Per modificare il tipo di un campo, lo sviluppatore deve eliminare il campo nel dashboard di CloudKit e aggiungerlo di nuovo con il nuovo tipo.

Prima di distribuire l'applicazione, lo sviluppatore può eseguire la migrazione dello schema e dei dati all'ambiente di produzione usando CloudKit Dashboard. Durante l'esecuzione nell'ambiente di produzione, il server impedisce a un'applicazione di modificare lo schema a livello di codice. Lo sviluppatore può comunque apportare modifiche al dashboard di CloudKit, ma tenta di aggiungere campi a un record nell'ambiente di produzione genera errori.

Nota

Il simulatore iOS funziona solo con l'ambiente di sviluppo. Quando lo sviluppatore è pronto per testare un'applicazione in un ambiente di produzione, è necessario un dispositivo iOS fisico.

Spedizione di un'app abilitata per CloudKit

Prima di spedire un'applicazione che usa CloudKit, sarà necessario configurarla per l'ambiente CloudKit di produzione o l'applicazione verrà rifiutata da Apple.

Effettua le operazioni seguenti:

  1. In Visual Studio per Ma compilare l'applicazione per il dispositivo iOS release>:

    Compile the application for Release

  2. Scegliere Archivia dal menu Compila:

    Select Archive

  3. L'archivio verrà creato e visualizzato in Visual Studio per Mac:

    The Archive will be created and displayed

  4. Avviare Xcode.

  5. Scegliere Libreria dal menu Finestra:

    Select Organizer

  6. Selezionare l'archivio dell'applicazione e fare clic sul pulsante Esporta:

    The application's archive

  7. Selezionare un metodo per l'esportazione e fare clic sul pulsante Avanti :

    Select a method for export

  8. Selezionare il team di sviluppo dall'elenco a discesa e fare clic sul pulsante Scegli :

    Select the Development Team from the dropdown list

  9. Selezionare Produzione dall'elenco a discesa e fare clic sul pulsante Avanti :

    Select Production from the dropdown list

  10. Esaminare l'impostazione e fare clic sul pulsante Esporta :

    Review the setting

  11. Scegliere un percorso per generare il file dell'applicazione .ipa risultante.

Il processo è simile per l'invio dell'applicazione direttamente a iTunes Connessione, basta fare clic sul pulsante Invia invece di Esporta... dopo aver selezionato un archivio nella finestra Libreria.

Quando usare CloudKit

Come abbiamo visto in questo articolo, CloudKit offre un modo semplice per archiviare e recuperare informazioni dai server iCloud. Detto questo, CloudKit non è obsoleto o non depreca alcuno degli strumenti o dei framework esistenti.

Utilizzare casi

I casi d'uso seguenti devono aiutare lo sviluppatore a decidere quando usare un framework o una tecnologia iCloud specifici:

  • iCloud Key-Value Store : mantiene in modo asincrono una piccola quantità di dati aggiornata ed è ideale per lavorare con le preferenze dell'applicazione. Tuttavia, è vincolato a una quantità molto piccola di informazioni.
  • iCloud Drive : basato sulle API documenti iCloud esistenti e offre una semplice API per sincronizzare i dati non strutturati dal file system. Offre una cache offline completa in Mac OS X ed è ideale per le applicazioni incentrate sui documenti.
  • iCloud Core Data : consente la replica dei dati tra tutti i dispositivi dell'utente. I dati sono un singolo utente e sono ideali per mantenere sincronizzati i dati privati e strutturati.
  • CloudKit : fornisce dati pubblici sia la struttura che la maggior parte delle operazioni bulk ed è in grado di gestire sia set di dati di grandi dimensioni che file non strutturati di grandi dimensioni. Associato all'account iCloud dell'utente e fornisce il trasferimento dei dati diretto dal client.

Tenendo presente questi casi d'uso, lo sviluppatore deve scegliere la tecnologia iCloud corretta per fornire sia la funzionalità dell'applicazione richiesta corrente che offrire una buona scalabilità per la crescita futura.

Riepilogo

Questo articolo ha illustrato un'introduzione rapida all'API CloudKit. Ha illustrato come effettuare il provisioning e configurare un'applicazione Xamarin iOS per l'uso di CloudKit. Ha trattato le funzionalità dell'API Convenience CloudKit. Illustra come progettare un'applicazione abilitata per CloudKit per la scalabilità usando query e sottoscrizioni. E infine ha mostrato le informazioni sull'account utente esposte a un'applicazione da CloudKit.