Site menu Desenvolvendo para iCloud

Desenvolvendo para iCloud

Há um bom tempo, os aplicativos-calculadoras que ofereço para Android podem salvar e recarregar versões da memória da calculadora. Curiosamente, a primeira versão deste recurso foi colaborada por um usuário.

No Android, é muito fácil implementar esse tipo de coisa: basta salvar os dados no cartão de memória. Ali, qualquer aplicativo pode criar pastas e gravar qualquer coisa. É terra-de-ninguém! Salvar a memória da calculadora no "SD Card" viabiliza inclusive o compartilhamento com outras pessoas, mas o usuário teria de transferir os arquivos por conta própria, seja copiando para o PC, seja transplantando o cartão de memória.

Nas versões para iOS o mesmo recurso demorou mais a aparecer, porque não existe algo equivalente ao "SD Card". Um aplicativo pode até gravar arquivos, mas só podem ser reutilizados pelo mesmo app no mesmo aparelho. Nem mesmo as preferências do app são salvas pelo iTunes durante a sincronização "normal"; é preciso fazer um backup explícito para preservá-las, coisa que quase ninguém se lembra de fazer.

No meu caso, salvar as memórias junto com as preferências do app iOS deixava a descoberto alguns casos de uso:

Então finalmente dei uma olhada no iCloud, para sanar estas deficiências.

Do ponto de vista "mercadológico" o iCloud é equivalente a Google Drive, Dropbox, etc. Já do ponto de vista do desenvolvedor, o iCloud é muito mais integrado ao sistema operacional iOS.

O iCloud oferece nada menos que quatro modalidades de salvamento de dados na nuvem, com diferentes níveis de complexidade e flexibilidade.

Key-value

A modalidade mais básica, que eu adotei para a calculadora, é a key-value (chave e valor). A API é muito semelhante ao armazenamento de preferências, que por sua vez funciona como um dicionário ou matriz associativa. A semelhança é propositada: é feita sob medida para um app salvar preferências na nuvem.

O compartilhamento de informações ocorre por app e por usuário. Um mesmo app instalado em vários dispositivos sob uma mesma conta enxergam um mesmo dicionário. Nesta modalidade, não é possível trocar dados entre apps diferentes, nem entre usuários diferentes.

Usar key-value não poderia ser mais simples: basta gravar as preferências compartilháveis no dicionário defaultStore, que está sempre disponível, mesmo que a Internet esteja fora ou mesmo que o usuário não tenha feito login no iCloud. Ainda assim, o app deve continuar salvando as preferências da forma convencional (NSUserDefaults) em paralelo, pois não é garantido que o defaultStore contenha dados assim que o app inicia.

Quando outro dispositivo modifica o key-value, o app recebe uma notificação, e seu software deve tomar conta do "merge", ou seja, integrar a mudança às preferências locais, de forma que não crie conflitos.

Documents

Esta modalidade, que não utilizei pessoalmente, atende a casos de uso tipo Evernote, onde o usuário tem acesso a seus documentos (planilhas, textos, desenhos, enfim, tudo aquilo que tipicamente chamamos de "arquivos" no PC) em todos os dispositivos sob uma mesma conta.

A API é mais complexa pois ela lida com mais situações: documento novo, renomeado, apagado, modificado, etc. Cada dispositivo mantém uma cópia local dos documentos, o que permite a edição offline.

A resolução de conflitos é primariamente baseada na versão do documento inteiro, então esta modalidade não viabiliza edição simultânea.

Core Data

Também não utilizei ainda esta modalidade. Aqui, o recurso Core Data, que lida com árvores de objetos persistentes, é estendido para a nuvem. Como é de se esperar, apenas os "deltas" (mudanças em objetos individuais) ocupam largura de banda.

Esta seria a resposta para aplicativos com "dados vivos", e cobre o caso da edição simultânea em múltiplos dispositivos atrelados a uma mesma conta. Mas também é a modalidade mais complexa de interagir com a nuvem.

Infelizmente, o Core Data + iCloud não seria útil no caso de edição simultânea por múltiplos usuários (leia-se: múltiplas contas diferentes). De qualquer forma o próprio Core Data fornece ganchos para serializar mudanças, e outro serviço qualquer poderia então ser utilizado para conectar os usuários.

CloudKit

Esta é a modalidade mais nova, lançada com o iOS 8. Aqui, o aplicativo pode armazenar e consultar registros na nuvem. Registros são dicionários tipados; o schema de cada tipo de registro tem de ser cadastrado num setor específico do site developer.apple.com.

Definir o schema poderia ser uma chatice, mas o site acima permite defini-lo a partir de registros de amostra que seu aplicativo já salvou na nuvem durante os testes. Ou seja, basta formalizar o que você já tinha especificado informalmente no código-fonte.

Cheguei a implementar o salvamento das memórias da calculadora usando CloudKit, mas acabei abandonando em favor do key-value, porque o CloudKit só funciona quando a Internet está disponível. Para completar minha implementação, teria de salvar offline e agendar a transferência postergada... preferi evitar essas complicações.

Cada aplicativo pode possuir diversos containers (geralmente basta um) e cada container tem um banco de dados público e outro privado. Mesmo o banco privado não está disponível offline (meu erro foi ter pressuposto que estaria). Por outro lado, diferentes aplicativos podem acessar um mesmo container, basta que exista a permissão (entitlement) para acessá-lo.

O grande "tchan" do CloudKit é a visibilidade do banco público por todos os usuários, mesmo os que não tenham feito login no iCloud! (É por isso que o schema tem de ser cadastrado na Apple.) Isto viabilizaria, por exemplo, que um usuário mandasse para outro a memória da calculadora, de forma transparente. É possível que eu volte a usar CloudKit um dia, em paralelo com key-value, por conta dessa possibilidade.

Conclusão

A existência de tantas modalidades de "cloudificação" de um app iOS é um pouco confusa num primeiro momento. Tanto que eu optei por uma, e no meio do caminho mudei para outra. Porém, cada uma delas é muito bem-feita e reafirma a bem-sucedida filosofia de "jardim murado" da Apple.