CloudKit no Xamarin.iOS
A estrutura do CloudKit agiliza o desenvolvimento de aplicativos que acessam o iCloud. Isso inclui a recuperação de dados de aplicativos e direitos de ativos, além de ser capaz de armazenar informações de aplicativos com segurança. Este kit oferece aos usuários uma camada de anonimato, permitindo o acesso a aplicativos com seus IDs do iCloud sem compartilhar informações pessoais.
Os desenvolvedores podem se concentrar em seus aplicativos do lado do cliente e permitir que o iCloud elimine a necessidade de escrever lógica de aplicativo do lado do servidor. O CloudKit fornece autenticação, bancos de dados privados e públicos, dados estruturados e serviços de armazenamento de ativos.
Importante
A Apple fornece ferramentas para ajudar os desenvolvedores a lidar adequadamente com o GDPR (Regulamento Geral sobre a Proteção de Dados) da União Europeia.
Requisitos
O seguinte é necessário para concluir as etapas apresentadas neste artigo:
- Xcode e o SDK do iOS – As APIs Xcode e iOS 8 da Apple precisam ser instaladas e configuradas no computador do desenvolvedor.
- Visual Studio para Mac – A versão mais recente do Visual Studio para Mac deve ser instalada e configurada no dispositivo do usuário.
- Dispositivo iOS 8 – Um dispositivo iOS que executa a versão mais recente do iOS 8 para teste.
O que é CloudKit?
O CloudKit é uma forma de dar ao desenvolvedor acesso aos Servidores iCloud. Ele fornece a base para o iCloud Drive e a Fototeca do iCloud. O CloudKit é compatível com dispositivos macOS e iOS.
O CloudKit usa a infraestrutura da Conta do iCloud. Se houver um usuário conectado a uma conta do iCloud no dispositivo, o CloudKit usará sua ID para identificar o usuário. Se nenhuma conta estiver disponível, o acesso somente leitura limitado será fornecido.
O CloudKit suporta o conceito de bancos de dados públicos e privados. Os bancos de dados públicos fornecem uma "sopa" de todos os dados aos quais o usuário tem acesso. Os bancos de dados privados destinam-se a armazenar os dados privados vinculados a um usuário específico.
O CloudKit suporta dados estruturados e em massa. Ele é capaz de lidar com grandes transferências de arquivos perfeitamente. O CloudKit se encarrega de transferir com eficiência arquivos grandes de e para os Servidores iCloud em segundo plano, liberando o desenvolvedor para se concentrar em outras tarefas.
Observação
É importante notar que o CloudKit é uma tecnologia de transporte. Não fornece nenhuma persistência; ele só permite que um aplicativo envie e receba informações dos servidores de forma eficiente.
No momento em que este artigo foi escrito, a Apple está inicialmente fornecendo o CloudKit gratuitamente com um alto limite de largura de banda e capacidade de armazenamento. Para projetos maiores ou aplicativos com uma grande base de usuários, a Apple deu a entender que uma escala de preços acessível será fornecida.
Habilitando o CloudKit em um aplicativo Xamarin
Antes que um aplicativo Xamarin possa utilizar a estrutura do CloudKit, o aplicativo deve ser provisionado corretamente, conforme detalhado nos guias Trabalhando com recursos e Trabalhando com direitos .
Para acessar o CloudKit, o arquivo Entitlements.plist deve incluir permissões Habilitar iCloud, armazenamento de valor de chave e CloudKit .
Aplicativo de exemplo
O aplicativo de exemplo demonstra como usar o CloudKit com o Xamarin. As etapas abaixo mostram como configurar o exemplo – ele requer configurações adicionais além do que é necessário apenas para o CloudKit:
- Abra o projeto no Visual Studio para Mac ou Visual Studio.
- No Gerenciador de Soluções, abra o arquivo Info.plist e verifique se o Identificador de Pacote corresponde ao que foi definido na ID do Aplicativo criada como parte da configuração de provisionamento.
- Role para baixo até a parte inferior do arquivo Info.plist e selecione Modos de plano de fundo habilitados, Atualizações de local e Notificações remotas.
- Clique com o botão direito do mouse no projeto iOS na solução e selecione Opções.
- Selecione Assinatura de pacote do iOS, selecione a Identidade do desenvolvedor e o perfil de provisionamento criado acima.
- Certifique-se de que o Entitlements.plist inclua Ativar iCloud, armazenamento de valor de chave e CloudKit.
- Verifique se o Ubiquity Container existe para o aplicativo. Exemplo:
iCloud.com.your-company.CloudKitAtlas
- Salve as alterações no arquivo.
Com essas configurações em vigor, o aplicativo de exemplo agora está pronto para acessar as APIs do CloudKit Framework, bem como serviços de plano de fundo, localização e notificação.
Visão geral da API do CloudKit
Antes de implementar o CloudKit em um aplicativo Xamarin iOS, este artigo abordará os fundamentos do CloudKit Framework, que incluirá os seguintes tópicos:
- Containers – Silos isolados de comunicações do iCloud.
- Bancos de dados – Públicos e privados estão disponíveis para o aplicativo.
- Registros – O mecanismo no qual os dados estruturados são movidos de e para o CloudKit.
- Zonas de Registro – São grupos de Registros.
- Identificadores de registro – são totalmente normalizados e representam o local específico do registro.
- Referência – Fornece relações pai-filho entre Registros relacionados em um determinado Banco de Dados.
- Ativos – Permite que arquivos de dados grandes e não estruturados sejam carregados no iCloud e associados a um determinado Registro.
Contêineres
Um determinado aplicativo em execução em um dispositivo iOS está sempre sendo executado ao lado de outros aplicativos e serviços nesse dispositivo. No dispositivo cliente, o aplicativo será isolado ou em área restrita de alguma forma. Em alguns casos, essa é uma área restrita literal e, em outros, o aplicativo está simplesmente sendo executado em seu próprio espaço de memória.
O conceito de pegar um aplicativo cliente e executá-lo separado de outros clientes é muito poderoso e oferece as seguintes vantagens:
- Segurança – Um aplicativo não pode interferir com outros aplicativos cliente ou com o próprio sistema operacional.
- Estabilidade – Se o aplicativo cliente falhar, ele não poderá retirar outros aplicativos do sistema operacional.
- Privacidade – Cada aplicativo cliente tem acesso limitado às informações pessoais armazenadas no dispositivo.
O CloudKit foi projetado para fornecer as mesmas vantagens listadas acima e aplicá-las ao trabalho com informações baseadas em nuvem:
Assim como o aplicativo é um dos muitos em execução no dispositivo, as comunicações do aplicativo com o iCloud também são uma de muitas. Cada um desses diferentes silos de comunicação são chamados de Containers.
Os contêineres são expostos no CloudKit Framework por meio da CKContainer
classe. Por padrão, um aplicativo conversa com um contêiner e esse contêiner segrega os dados desse aplicativo. Isso significa que vários aplicativos podem armazenar informações na mesma conta do iCloud, mas essas informações nunca serão misturadas.
A conteinerização de dados do iCloud também permite que o CloudKit encapsulasse informações do usuário. Dessa forma, o aplicativo terá algum acesso limitado à conta do iCloud e às informações do usuário armazenadas dentro, tudo isso enquanto ainda protege a privacidade e a segurança do usuário.
Os contêineres são totalmente gerenciados pelo desenvolvedor do aplicativo através do portal WWDR. O namespace do contêiner é global em todos os desenvolvedores da Apple, portanto, o contêiner não deve ser exclusivo apenas para os aplicativos de um determinado desenvolvedor, mas para todos os desenvolvedores e aplicativos da Apple.
A Apple sugere o uso da notação DNS reversa ao criar o namespace para contêineres de aplicativos. Exemplo: iCloud.com.company-name.application-name
Embora os contêineres sejam, por padrão, vinculados um a um a um determinado aplicativo, eles podem ser compartilhados entre aplicativos. Assim, vários aplicativos podem ser coordenados em um único contêiner. Um único aplicativo também pode conversar com vários contêineres.
Bancos de dados
Uma das principais funções do CloudKit é levar o modelo de dados de um aplicativo e a replicação desse modelo até os servidores do iCloud. Algumas informações são destinadas ao usuário que as criou, outras informações são dados públicos que podem ser criados por um usuário para uso público (como uma revisão de restaurante) ou podem ser informações que o desenvolvedor publicou para o aplicativo. Em ambos os casos, o público não é apenas um único usuário, mas é uma comunidade de pessoas.
Dentro de um contêiner, em primeiro lugar, está o banco de dados público. É aqui que toda a informação pública vive e se mistura. Além disso, há vários bancos de dados privados individuais para cada usuário do aplicativo.
Ao ser executado em um dispositivo iOS, o aplicativo só terá acesso às informações do usuário do iCloud atualmente conectado. Assim, a visão do aplicativo do contêiner será a seguinte:
Ele só pode ver o banco de dados público e o banco de dados privado associado ao usuário do iCloud atualmente conectado.
Os bancos de dados são expostos no CloudKit Framework por meio da CKDatabase
classe. Cada aplicativo tem acesso a dois bancos de dados: o banco de dados público e o banco de dados privado.
O contêiner é o ponto de entrada inicial no CloudKit. O código a seguir pode ser usado para acessar o banco de dados público e privado do contêiner padrão do aplicativo:
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;
Aqui estão as diferenças entre os tipos de banco de dados:
Banco de Dados Público | Banco de Dados Privado | |
---|---|---|
Tipo de Dados | Dados Compartilhados | Dados do usuário atual |
Cota | contabilizado na cota do desenvolvedor | contabilizado na cota do usuário |
Permissões padrão | Legível para o mundo | Legível pelo usuário |
Permissões de edição | Funções do Painel do iCloud por meio de um nível de classe de registro | N/D |
Registros
Os contêineres contêm bancos de dados e, dentro dos bancos de dados, há registros. Os registros são o mecanismo no qual os dados estruturados são movidos de e para o CloudKit:
Os registros são expostos no CloudKit Framework por meio da CKRecord
classe, que encapsula pares chave-valor. Uma instância de um objeto em um aplicativo é equivalente a um CKRecord
no CloudKit. Além disso, cada CKRecord
um possui um tipo de registro, que é equivalente à classe de um objeto.
Os registros têm um esquema just-in-time, portanto, os dados são descritos ao CloudKit antes de serem entregues para processamento. A partir desse ponto, o CloudKit interpretará as informações e cuidará da logística de armazenamento e recuperação do registro.
A CKRecord
classe também oferece suporte a uma ampla gama de metadados. Por exemplo, um registro contém informações sobre quando ele foi criado e o usuário que o criou. Um registro também contém informações sobre quando ele foi modificado pela última vez e o usuário que o modificou.
Os registros contêm a noção de uma marca de alteração. Esta é uma versão anterior de uma revisão de um determinado registro. A tag Change é usada como uma maneira leve de determinar se o cliente e o servidor têm a mesma versão de um determinado registro.
Como dito acima, CKRecords
encapsular pares chave-valor e, como tal, os seguintes tipos de dados podem ser armazenados em um registro:
NSString
NSNumber
NSData
NSDate
CLLocation
CKReferences
CKAssets
Além dos tipos de valor único, um registro pode conter uma matriz homogênea de qualquer um dos tipos listados acima.
O código a seguir pode ser usado para criar um novo registro e armazená-lo em um banco de dados:
using CloudKit;
//...
private const string ReferenceItemRecordName = "ReferenceItems";
//...
var newRecord = new CKRecord (ReferenceItemRecordName);
newRecord ["name"] = (NSString)nameTextField.Text;
await CloudManager.SaveAsync (newRecord);
Zonas de registro
Os registros não existem sozinhos dentro de um determinado banco de dados – grupos de registros existem juntos dentro de uma Zona de Registro. As zonas de registro podem ser consideradas como tabelas em bancos de dados relacionais tradicionais:
Pode haver vários registros em uma determinada Zona de Registro e várias Zonas de Registro em um determinado banco de dados. Cada banco de dados contém uma zona de registro padrão:
É aqui que os registros são armazenados por padrão. Além disso, as zonas de registro personalizadas podem ser criadas. As Zonas de Registro representam a granularidade de base na qual as Confirmações Atômicas e o Controle de Alterações são feitos.
Identificadores de registro
Os identificadores de registro são representados como uma tupla, contendo um nome de registro fornecido pelo cliente e a zona na qual o registro existe. Os identificadores de registro têm as seguintes características:
- Eles são criados pelo aplicativo cliente.
- Eles são totalmente normalizados e representam o local específico do registro.
- Ao atribuir a ID exclusiva de um registro em um banco de dados externo ao nome do registro, eles podem ser usados para fazer a ponte entre bancos de dados locais que não estão armazenados no CloudKit.
Quando os desenvolvedores criam novos registros, eles podem optar por passar um Identificador de Registro. Se um Identificador de Registro não for especificado, um UUID será automaticamente criado e atribuído ao registro.
Quando os desenvolvedores criam novos Identificadores de Registro, eles podem optar por especificar a Zona de Registro à qual cada registro pertencerá. Se nenhum for especificado, a Zona de Registro Padrão será usada.
Os identificadores de registro são expostos no CloudKit Framework por meio da CKRecordID
classe. O código a seguir pode ser usado para criar um novo identificador de registro:
var recordID = new CKRecordID("My Record");
Referências
As referências fornecem relações entre registros relacionados em um determinado banco de dados:
No exemplo acima, os pais possuem filhos para que a criança seja um registro filho do registro pai. A Relação vai do registro filho para o registro pai e é chamada de Referência Posterior.
As referências são expostas no CloudKit Framework por meio da CKReference
classe. Eles são uma forma de permitir que o servidor do iCloud entenda a relação entre os registros.
As referências fornecem o mecanismo por trás das exclusões em cascata. Se um registro pai for excluído do banco de dados, todos os registros filho (conforme especificado em um Relacionamento) também serão excluídos automaticamente do banco de dados.
Observação
Dangling Pointers são uma possibilidade ao usar o CloudKit. Por exemplo, no momento em que o aplicativo tiver buscado uma lista de ponteiros de registro, selecionado um registro e, em seguida, solicitado o registro, o registro pode não existir mais no banco de dados. Um aplicativo deve ser codificado para lidar com essa situação normalmente.
Embora não seja obrigatório, as referências de retorno são preferidas ao trabalhar com o CloudKit Framework. A Apple ajustou o sistema para tornar este o tipo de referência mais eficiente.
Ao criar uma Referência, o desenvolvedor pode fornecer um registro que já está na memória ou criar uma referência a um Identificador de Registro. Se estiver usando um Identificador de Registro e a referência especificada não existir no banco de dados, um Ponteiro Flutuante será criado.
Veja a seguir um exemplo de criação de uma referência em relação a um registro conhecido:
var reference = new CKReference(newRecord, new CKReferenceAction());
Ativos
Os ativos permitem que um arquivo de dados grandes e não estruturados seja carregado no iCloud e associado a um determinado registro:
No cliente, é criado um CKRecord
que descreve o arquivo que será carregado no servidor do iCloud. A CKAsset
é criado para conter o arquivo e é vinculado ao registro que o descreve.
Quando o arquivo é carregado no servidor, o registro é colocado no banco de dados e o arquivo é copiado em um banco de dados especial de armazenamento em massa. Um link é criado entre o ponteiro do registro e o arquivo carregado.
Os ativos são expostos no CloudKit Framework por meio da CKAsset
classe e são usados para armazenar dados grandes e não estruturados. Como o desenvolvedor nunca quer ter dados grandes e não estruturados na memória, os ativos são implementados usando arquivos no disco.
Os ativos são de propriedade de registros, o que permite que os ativos sejam recuperados do iCloud usando o registro como um ponteiro. Dessa forma, o servidor pode coletar ativos quando o registro que possui o ativo é excluído.
Como CKAssets
são destinados a lidar com arquivos de dados grandes, a Apple projetou o CloudKit para carregar e baixar os ativos com eficiência.
O código a seguir pode ser usado para criar um ativo e associá-lo ao registro:
var fileUrl = new NSUrl("LargeFile.mov");
var asset = new CKAsset(fileUrl);
newRecord ["name"] = asset;
Agora cobrimos todos os objetos fundamentais dentro do CloudKit. Os contêineres são associados a aplicativos e contêm bancos de dados. Os bancos de dados contêm Registros que são agrupados em Zonas de Registro e apontados por Identificadores de Registro. As relações pai-filho são definidas entre Registros usando Referências. Finalmente, arquivos grandes podem ser carregados e associados a Registros usando Ativos.
API de conveniência do CloudKit
A Apple oferece dois conjuntos de APIs diferentes para trabalhar com o CloudKit:
- API operacional – Oferece todos os recursos do CloudKit. Para aplicativos mais complexos, essa API fornece controle refinado sobre o CloudKit.
- API de conveniência – Oferece um subconjunto comum e pré-configurado de recursos do CloudKit. Ele fornece uma solução conveniente e de fácil acesso para incluir a funcionalidade do CloudKit em um aplicativo iOS.
A API de conveniência é geralmente a melhor escolha para a maioria dos aplicativos iOS e a Apple sugere começar com ela. O restante desta seção abordará os seguintes tópicos da API de conveniência:
- Salvando um registro.
- Buscando um recorde.
- Atualizando um registro.
Código de configuração comum
Antes de começar a usar a API de conveniência do CloudKit, é necessário algum código de configuração padrão. Comece modificando o arquivo do AppDelegate.cs
aplicativo e faça com que ele tenha a seguinte aparência:
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");
}
}
}
O código acima expõe os bancos de dados públicos e privados do CloudKit como atalhos para torná-los mais fáceis de trabalhar no restante do aplicativo.
Em seguida, adicione o seguinte código a qualquer exibição ou contêiner de exibição que usará o CloudKit:
using CloudKit;
//...
public AppDelegate ThisApp {
get { return (AppDelegate)UIApplication.SharedApplication.Delegate; }
}
Isso adiciona um atalho para acessar os AppDelegate
atalhos de banco de dados público e privado criados acima.
Com esse código em vigor, vamos dar uma olhada na implementação da API de conveniência do CloudKit em um aplicativo Xamarin iOS 8.
Salvando um registro
Usando o padrão apresentado acima ao discutir Registros, o código a seguir criará um novo registro e usará a API de conveniência para salvá-lo no banco de dados público:
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) {
...
}
});
Três coisas a observar sobre o código acima:
- Ao chamar o
SaveRecord
PublicDatabase
método do , o desenvolvedor não precisa especificar como os dados são enviados, em qual Zona eles estão sendo gravados, etc. A API de conveniência está cuidando de todos esses detalhes. - A chamada é assíncrona e fornece uma rotina de retorno de chamada quando a chamada é concluída, com êxito ou falha. Se a chamada falhar, uma mensagem de erro será fornecida.
- O CloudKit não fornece armazenamento/persistência local; é apenas um meio de transferência. Assim, quando uma solicitação é feita para salvar um registro, ele é imediatamente enviado para os servidores do iCloud.
Observação
Devido à natureza "com perdas" das comunicações de rede móvel, onde as conexões são constantemente interrompidas ou interrompidas, uma das primeiras considerações que o desenvolvedor deve fazer ao trabalhar com o CloudKit é o tratamento de erros.
Buscando um disco
Com um registro criado e armazenado com êxito no servidor do iCloud, use o seguinte código para recuperar o 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) {
...
}
});
Assim como ao salvar o Registro, o código acima é assíncrono, simples e requer grande tratamento de erros.
Atualizando um registro
Depois que um Registro for obtido nos servidores do iCloud, o código a seguir poderá ser usado para modificar o Registro e salvar as alterações de volta no banco de dados:
// 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) {
...
}
});
}
});
O FetchRecord
método do PublicDatabase
retorna a CKRecord
se a chamada foi bem-sucedida. Em seguida, o aplicativo modifica o registro e chama SaveRecord
novamente para gravar as alterações de volta no banco de dados.
Esta seção mostrou o ciclo típico que um aplicativo usará ao trabalhar com a API de conveniência do CloudKit. O aplicativo salvará Registros no iCloud, recuperará esses registros do iCloud, modificará os Registros e salvará essas alterações de volta no iCloud.
Projetando para escalabilidade
Até agora, este artigo analisou o armazenamento e a recuperação de todo o modelo de objeto de um aplicativo dos servidores do iCloud, sempre que ele for trabalhado. Embora essa abordagem funcione bem com uma pequena quantidade de dados e uma base de usuários muito pequena, ela não é bem dimensionada quando a quantidade de informações e/ou a base de usuários aumenta.
Big data, dispositivo minúsculo
Quanto mais popular um aplicativo se torna, mais dados no banco de dados e menos viável é ter um cache de todos esses dados no dispositivo. As seguintes técnicas podem ser usadas para resolver esse problema:
- Mantenha os grandes dados na nuvem – O CloudKit foi projetado para lidar com grandes dados de forma eficiente.
- O cliente deve exibir apenas uma fatia desses dados – Reduza o mínimo de dados necessários para lidar com qualquer tarefa em um determinado momento.
- As visualizações do cliente podem mudar – Como cada usuário tem preferências diferentes, a fatia de dados que está sendo exibida pode mudar de usuário para usuário e a exibição individual do usuário de qualquer fatia específica pode ser diferente.
- O cliente usa consultas para focar o ponto de vista – as consultas permitem que o usuário exiba um pequeno subconjunto de um conjunto de dados maior que existe na nuvem.
Consultas
Como dito acima, as consultas permitem que o desenvolvedor selecione um pequeno subconjunto do conjunto de dados maior que existe na nuvem. As consultas são expostas no CloudKit Framework por meio da CKQuery
classe.
Uma consulta combina três coisas diferentes: um Tipo de Registro ( RecordType
), um Predicado ( NSPredicate
) e, opcionalmente, um Descritor de Classificação ( NSSortDescriptors
). O CloudKit suporta a maior parte do NSPredicate
.
Predicados suportados
O CloudKit oferece suporte aos seguintes tipos de NSPredicates
ao trabalhar com consultas:
Registros correspondentes em que o nome é igual a um valor armazenado em uma variável:
NSPredicate.FromFormat(string.Format("name = '{0}'", recordName))
Permite que a correspondência seja baseada em um valor de chave dinâmica, para que a chave não precise ser conhecida em tempo de compilação:
NSPredicate.FromFormat(string.Format("{0} = '{1}'", key, value))
Registros correspondentes em que o valor do Registro é maior que o valor determinado:
NSPredicate.FromFormat(string.Format("start > {0}", (NSDate)date))
Registros correspondentes em que a localização do Record está a menos de 100 metros do local determinado:
var location = new CLLocation(37.783,-122.404); var predicate = NSPredicate.FromFormat(string.Format("distanceToLocation:fromLocation(Location,{0}) < 100", location));
O CloudKit suporta uma pesquisa tokenizada. Essa chamada criará dois tokens, um para
after
e outro parasession
. Ele retornará um Registro que contém esses dois tokens:NSPredicate.FromFormat(string.Format("ALL tokenize({0}, 'Cdl') IN allTokens", "after session"))
O CloudKit oferece suporte a predicados compostos unidos usando o
AND
operador.NSPredicate.FromFormat(string.Format("start > {0} AND name = '{1}'", (NSDate)date, recordName))
Criando consultas
O código a seguir pode ser usado para criar um CKQuery
aplicativo Xamarin iOS 8:
var recordName = "MyRec";
var predicate = NSPredicate.FromFormat(string.Format("name = '{0}'", recordName));
var query = new CKQuery("CloudRecords", predicate);
Primeiro, ele cria um Predicado para selecionar apenas registros que correspondem a um determinado nome. Em seguida, ele cria uma consulta que selecionará Registros do Tipo de Registro fornecido que correspondem ao Predicado.
Executando uma consulta
Depois que uma consulta tiver sido criada, use o código a seguir para executar a consulta e processar os registros retornados:
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];
}
}
});
O código acima pega a consulta criada acima e a executa no Banco de Dados Público. Como nenhuma zona de registro é especificada, todas as zonas são pesquisadas. Se nenhum erro ocorreu, uma matriz de será retornada CKRecords
correspondente aos parâmetros da consulta.
A maneira de pensar sobre Consultas é que elas são enquetes e são ótimas para fatiar grandes conjuntos de dados. As consultas, no entanto, não são adequadas para grandes conjuntos de dados estáticos devido aos seguintes motivos:
- Eles são ruins para a vida útil da bateria do dispositivo.
- Eles são ruins para o tráfego de rede.
- Eles são ruins para a experiência do usuário porque as informações que eles veem são limitadas pela frequência com que o aplicativo está sondando o banco de dados. Os usuários de hoje esperam notificações por push quando algo muda.
Assinaturas
Ao lidar com grandes conjuntos de dados estáticos, a consulta não deve ser executada no dispositivo cliente, ela deve ser executada no servidor em nome do cliente. A consulta deve ser executada em segundo plano e deve ser executada após cada registro salvo, seja pelo dispositivo atual ou por outro dispositivo tocando no mesmo banco de dados.
Finalmente, uma notificação por push deve ser enviada a cada dispositivo conectado ao banco de dados quando a consulta do lado do servidor for executada.
As assinaturas são expostas no CloudKit Framework por meio da CKSubscription
classe. Eles combinam um Tipo de Registro ( RecordType
), um Predicado ( NSPredicate
) e uma Notificação por Push da Apple ( Push
).
Observação
Os pushes do CloudKit são ligeiramente aumentados, pois contêm uma carga útil contendo informações específicas do CloudKit, como o que causou o envio de push.
Como funcionam as assinaturas
Antes de implementar a assinatura no código C#, vamos dar uma rápida visão geral de como as assinaturas funcionam:
O gráfico acima mostra o processo típico de assinatura da seguinte maneira:
- O dispositivo cliente cria uma nova Assinatura contendo o conjunto de condições que acionará a assinatura e uma Notificação por Push que será enviada quando o gatilho ocorrer.
- A Assinatura é enviada para o Banco de Dados onde é adicionada à coleção de assinaturas existentes.
- Um segundo dispositivo cria um novo Registro e salva esse registro no Banco de Dados.
- O Banco de Dados pesquisa em sua lista de Assinaturas para ver se o novo Registro corresponde a alguma de suas condições.
- Se uma correspondência for encontrada, a Notificação por Push será enviada ao dispositivo que registrou a Assinatura com informações sobre o Registro que fez com que ela fosse acionada.
Com esse conhecimento, vamos analisar a criação de assinaturas em um aplicativo Xamarin iOS 8.
Criando assinaturas
O código a seguir pode ser usado para criar uma assinatura:
// 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;
Primeiro, ele cria um Predicado que fornece a condição para acionar a Assinatura. Em seguida, ele cria a assinatura em um Tipo de Registro específico e define a opção de quando o gatilho é testado. Finalmente, ele define o tipo de notificação que ocorrerá quando a Assinatura for acionada e anexará a Assinatura.
Salvando assinaturas
Com a assinatura criada, o código a seguir a salvará no banco de dados:
// Save the subscription to the database
ThisApp.PublicDatabase.SaveSubscription(subscription, (s, err) => {
// Was there an error?
if (err != null) {
}
});
Usando a API de conveniência, a chamada é assíncrona, simples e fornece fácil tratamento de erros.
Manipulando notificações por push
Se o desenvolvedor já usou as Notificações por Push da Apple (APS), o processo de lidar com as Notificações geradas pelo CloudKit deve ser familiar.
No , substitua AppDelegate.cs
a ReceivedRemoteNotification
classe da seguinte maneira:
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;
}
}
O código acima pede ao CloudKit para analisar o userInfo em uma notificação do CloudKit. Em seguida, são extraídas informações sobre o alerta. Finalmente, o tipo de notificação é testado e a notificação é tratada de acordo.
Esta seção mostrou como responder ao problema de Big Data, Tiny Device apresentado acima usando Consultas e Assinaturas. O aplicativo deixará seus grandes dados na nuvem e usará essas tecnologias para fornecer exibições desse conjunto de dados.
Contas de usuário do CloudKit
Como observado no início deste artigo, o CloudKit foi criado sobre a infraestrutura existente do iCloud. A seção a seguir abordará, em detalhes, como as contas são expostas a um desenvolvedor usando a API do CloudKit.
Autenticação
Ao lidar com contas de usuário, a primeira consideração é a autenticação. O CloudKit suporta autenticação através do utilizador do iCloud atualmente ligado no dispositivo. A autenticação ocorre nos bastidores e é tratada pelo iOS. Dessa forma, os desenvolvedores nunca precisam se preocupar com os detalhes da implementação da autenticação. Eles só testam para ver se um usuário está conectado.
Informações da conta de usuário
O CloudKit fornece as seguintes informações de usuário para o desenvolvedor:
- Identidade – uma forma de identificar exclusivamente o usuário.
- Metadados – A capacidade de salvar e recuperar informações sobre os usuários.
- Privacidade – Todas as informações são tratadas em uma mansão consciente da privacidade. Nada é exposto a menos que o usuário tenha concordado com isso.
- Descoberta – Dá aos usuários a capacidade de descobrir seus amigos que estão usando o mesmo aplicativo.
A seguir, analisaremos esses tópicos em detalhes.
Identidade
Como dito acima, o CloudKit fornece uma maneira para o aplicativo identificar exclusivamente um determinado usuário:
Há um aplicativo cliente em execução nos dispositivos de um usuário e todos os bancos de dados privados do usuário específicos dentro do contêiner do CloudKit. O aplicativo cliente será vinculado a um desses usuários específicos. Isso se baseia no usuário que está conectado ao iCloud localmente no dispositivo.
Como isso vem do iCloud, há um rico armazenamento de informações do usuário. E como o iCloud está realmente hospedando o Container, ele pode correlacionar os usuários. No gráfico acima, o usuário cuja conta user@icloud.com
do iCloud está vinculada ao cliente atual.
Em uma base de Contêiner por Contêiner, um ID de Usuário exclusivo gerado aleatoriamente é criado e associado à conta do iCloud (endereço de e-mail) do usuário. Esse ID de usuário é retornado ao aplicativo e pode ser usado da maneira que o desenvolvedor achar melhor.
Observação
Aplicativos diferentes em execução no mesmo dispositivo para o mesmo usuário do iCloud terão IDs de usuário diferentes porque estão conectados a contêineres diferentes do CloudKit.
O código a seguir obtém o ID de usuário do CloudKit para o usuário do iCloud conectado no dispositivo no momento:
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;
}
});
O código acima está solicitando que o contêiner do CloudKit forneça o ID do usuário conectado no momento. Como essas informações são provenientes do Servidor iCloud, a chamada é assíncrona e o tratamento de erros é necessário.
Metadados
Cada usuário no CloudKit tem metadados específicos que os descrevem. Esses metadados são representados como um registro do CloudKit:
Procurando dentro do Banco de Dados Privado um usuário específico de um Contêiner, há um Registro que define esse usuário. Há muitos registros de usuário dentro do banco de dados público, um para cada usuário do contêiner. Um deles terá uma ID de registro que corresponda à ID de registro do usuário conectado no momento.
Os registros de usuário no banco de dados público são legíveis mundialmente. Eles são tratados, em sua maioria, como um Record comum e têm um tipo de CKRecordTypeUserRecord
. Esses registros são reservados pelo sistema e não estão disponíveis para consultas.
Use o código a seguir para acessar um registro de usuário:
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;
}
});
O código acima está solicitando que o Banco de Dados Público retorne o Registro de Usuário para o ID do usuário que acessamos acima. Como essas informações são provenientes do Servidor iCloud, a chamada é assíncrona e o tratamento de erros é necessário.
Privacidade
O CloudKit foi projetado, por padrão, para proteger a privacidade do usuário conectado no momento. Nenhuma informação de identificação pessoal sobre o usuário é exposta por padrão. Há alguns casos em que o aplicativo exigirá informações limitadas sobre o usuário.
Nesses casos, o aplicativo pode solicitar que o usuário divulgue essas informações. Uma caixa de diálogo será apresentada ao usuário solicitando que ele opte por expor as informações de sua conta.
Descoberta
Supondo que o usuário tenha optado por permitir o acesso limitado do aplicativo às suas informações de conta de usuário, eles podem ser descobertos por outros usuários do aplicativo:
O aplicativo cliente está falando com um contêiner e o contêiner está falando com o iCloud para acessar as informações do usuário. O usuário pode fornecer um endereço de e-mail e a Descoberta pode ser usada para obter informações sobre o usuário. Opcionalmente, o ID do usuário também pode ser usado para descobrir informações sobre o usuário.
O CloudKit também fornece uma maneira de descobrir informações sobre qualquer usuário que possa ser amigo do usuário atualmente conectado ao iCloud consultando todo o Catálogo de Endereços. O Processo do CloudKit irá puxar o Catálogo de Contatos do usuário e usar os endereços de e-mail para ver se ele pode encontrar outros usuários do aplicativo que correspondam a esses endereços.
Isso permite que o aplicativo aproveite o Catálogo de Contatos do usuário sem fornecer acesso a ele ou pedir que o usuário aprove o acesso aos contatos. Em nenhum momento as informações de contato são disponibilizadas para o aplicativo, apenas o Processo CloudKit tem acesso.
Para recapitular, há três tipos diferentes de entradas disponíveis para a Descoberta do Usuário:
- ID de registro de usuário – A descoberta pode ser feita em relação ao ID de usuário do usuário do CloudKit conectado no momento.
- Endereço de e-mail do usuário – O usuário pode fornecer um endereço de e-mail e ele pode ser usado para descoberta.
- Catálogo de contatos – O catálogo de endereços do usuário pode ser usado para descobrir usuários do aplicativo que têm o mesmo endereço de e-mail listado em seus contatos.
A Descoberta do Usuário retornará as seguintes informações:
- ID do Registro do Usuário - O ID exclusivo de um usuário no Banco de Dados Público.
- Nome e Sobrenome - Conforme armazenado no Banco de Dados Público.
Essas informações só serão retornadas para usuários que optaram pelo Discovery.
O código a seguir descobrirá informações sobre o usuário atualmente conectado ao iCloud no 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 o código a seguir para consultar todos os usuários no catálogo de contatos:
// 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];
}
}
});
Nesta seção, abordamos as quatro principais áreas de acesso à conta de um usuário que o CloudKit pode fornecer a um aplicativo. Desde a obtenção da Identidade e Metadados do usuário, até as políticas de Privacidade incorporadas ao CloudKit e, finalmente, a capacidade de descobrir outros usuários do aplicativo.
Os ambientes de desenvolvimento e produção
O CloudKit fornece ambientes de Desenvolvimento e Produção separados para os tipos de registro e dados de um aplicativo. O Ambiente de Desenvolvimento é um ambiente mais flexível que está disponível apenas para membros de uma equipe de desenvolvimento. Quando um aplicativo adiciona um novo campo a um registro e salva esse registro no Ambiente de Desenvolvimento, o servidor atualiza as informações do esquema automaticamente.
O desenvolvedor pode usar esse recurso para fazer alterações em um esquema durante o desenvolvimento, o que economiza tempo. Uma ressalva é que, depois que um campo é adicionado a um registro, o tipo de dados associado a esse campo não pode ser alterado programaticamente. Para alterar o tipo de um campo, o desenvolvedor deve excluir o campo no CloudKit Dashboard e adicioná-lo novamente com o novo tipo.
Antes de implantar o aplicativo, o desenvolvedor pode migrar seu esquema e dados para o ambiente de produção usando o CloudKit Dashboard. Ao executar no ambiente de produção, o servidor impede que um aplicativo altere o esquema programaticamente. O desenvolvedor ainda pode fazer alterações com o CloudKit Dashboard , mas as tentativas de adicionar campos a um registro no Ambiente de Produção resultam em erros.
Observação
O Simulador iOS funciona apenas com o Ambiente de Desenvolvimento. Quando o desenvolvedor estiver pronto para testar um aplicativo em um ambiente de produção, um dispositivo iOS físico será necessário.
Enviando um aplicativo habilitado para CloudKit
Antes de enviar um aplicativo que usa o CloudKit, ele precisará ser configurado para o ambiente do CloudKit de produção ou o aplicativo será rejeitado pela Apple.
Faça o seguinte:
No Visual Studio for Ma, compile o aplicativo para Release>iOS Device:
No menu Compilar , selecione Arquivar:
O arquivo será criado e exibido no Visual Studio para Mac:
Inicie o Xcode.
No menu Janela , selecione Organizador:
Selecione o arquivo do aplicativo e clique no botão Exportar...
Selecione um método para exportação e clique no botão Avançar :
Selecione a Equipe de Desenvolvimento na lista suspensa e clique no botão Escolher :
Selecione Produção na lista suspensa e clique no botão Avançar :
Revise a configuração e clique no botão Exportar :
Escolha um local para gerar o arquivo de aplicativo
.ipa
resultante.
O processo é semelhante para enviar o aplicativo diretamente para o iTunes Connect, basta clicar no botão Enviar... em vez do botão Exportar... depois de selecionar um Arquivo morto na janela Organizador.
Quando usar o CloudKit
Como vimos neste artigo, o CloudKit fornece uma maneira fácil para um aplicativo armazenar e recuperar informações dos servidores do iCloud. Dito isso, o CloudKit não torna obsoleta ou deprecia nenhuma das ferramentas ou estruturas existentes.
Casos de uso
Os casos de uso a seguir devem ajudar o desenvolvedor a decidir quando usar uma estrutura ou tecnologia específica do iCloud:
- iCloud Key-Value Store – Mantém uma pequena quantidade de dados atualizada de forma assíncrona e é ótimo para trabalhar com preferências de aplicativos. No entanto, ele é limitado por uma quantidade muito pequena de informações.
- iCloud Drive – Criado sobre as APIs de Documentos do iCloud existentes e fornece uma API simples para sincronizar dados não estruturados do sistema de arquivos. Ele fornece um cache offline completo no Mac OS X e é ótimo para aplicativos centrados em documentos.
- iCloud Core Data – Permite que os dados sejam replicados entre todos os dispositivos do usuário. Os dados são de usuário único e ótimos para manter dados privados e estruturados em sincronia.
- CloudKit – Fornece dados públicos tanto em estrutura quanto em massa e é capaz de lidar com grandes conjuntos de dados e grandes arquivos não estruturados. Ele está vinculado à conta do iCloud do usuário e fornece transferência de dados direcionada ao cliente.
Tendo esses casos de uso em mente, o desenvolvedor deve escolher a tecnologia correta do iCloud para fornecer a funcionalidade de aplicativo necessária atual e fornecer boa escalabilidade para crescimento futuro.
Resumo
Este artigo abordou uma rápida introdução à API do CloudKit. Ele mostrou como provisionar e configurar um aplicativo Xamarin iOS para usar o CloudKit. Ele cobriu os recursos da API de conveniência do CloudKit. Ele mostrou como projetar um aplicativo habilitado para CloudKit para escalabilidade usando consultas e assinaturas. E, finalmente, mostrou as informações da Conta de Usuário que são expostas a um aplicativo pelo CloudKit.