Ativar sincronização offline com aplicações móveis iOS

Descrição Geral

Este tutorial abrange a sincronização offline com a funcionalidade de Aplicações Móveis de Serviço de Aplicações do Azure para iOS. Com a sincronização offline os utilizadores finais podem interagir com uma aplicação móvel para visualizar, adicionar ou modificar dados, mesmo quando não têm ligação à rede. As alterações são armazenadas numa base de dados local. Depois de o dispositivo voltar a estar online, as alterações são sincronizadas com a extremidade traseira remota.

Se esta é a sua primeira experiência com aplicações móveis, deve primeiro completar o tutorial Criar uma Aplicação iOS. Se não utilizar o projeto de servidor de arranque rápido descarregado, tem de adicionar os pacotes de extensão de acesso a dados ao seu projeto. Para obter mais informações sobre pacotes de extensão do servidor, consulte Work with the .NET backend server SDK for Azure Mobile Apps.

Para saber mais sobre a funcionalidade de sincronização offline, consulte Offline Data Sync em Aplicações Móveis.

Reveja o código de sincronização do cliente

O projeto de cliente que descarregou para o tutorial da Aplicação iOS já contém código que suporta a sincronização offline utilizando uma base de dados baseada em Dados Core local. Esta secção resume o que já está incluído no código tutorial. Para uma visão geral conceptual da funcionalidade, consulte Offline Data Sync em Aplicações Móveis.

Utilizando a funcionalidade de sincronização de dados offline das Aplicações Móveis, os utilizadores finais podem interagir com uma base de dados local mesmo quando a rede está inacessível. Para utilizar estas funcionalidades na sua aplicação, inicializa o contexto sincronizado e MSClient faz referência a uma loja local. Em seguida, refere a sua tabela através da interface MSSyncTable .

No QSTodoService.m (Objective-C) ou ToDoTableViewController.swift (Swift), note que o tipo de sincronização do membro é MSSyncTable. A sincronização offline utiliza esta interface de tabela sincronizada em vez de MSTable. Quando uma tabela de sincronização é utilizada, todas as operações vão para a loja local e são sincronizadas apenas com a extremidade traseira remota com operações explícitas de impulso e puxar.

Para obter uma referência a uma tabela de sincronização, utilize o método syncTableWithName em MSClient. Para remover a funcionalidade de sincronização offline, utilize o tableWithName .

Antes de qualquer funcionação de mesa, a loja local deve ser inicializada. Aqui está o código relevante:

  • Objetivo C. No método QSTodoService.init :

    MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
    self.client.syncContext = [[MSSyncContext alloc] initWithDelegate:nil dataSource:store callback:nil];
    
  • O Swift. No método ToDoTableViewController.viewDidLoad :

    let client = MSClient(applicationURLString: "http:// ...") // URI of the Mobile App
    let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!
    self.store = MSCoreDataStore(managedObjectContext: managedObjectContext)
    client.syncContext = MSSyncContext(delegate: nil, dataSource: self.store, callback: nil)
    

    Este método cria uma loja local utilizando a MSCoreDataStore interface, que o Mobile Apps SDK fornece. Em alternativa, pode fornecer uma loja local diferente implementando o MSSyncContextDataSource protocolo. Além disso, o primeiro parâmetro do MSSyncContext é usado para especificar um manipulador de conflitos. Porque nós passamos nil, temos o padrão de conflito, que falha em qualquer conflito.

Agora, vamos executar a operação de sincronização real, e obter dados da parte traseira remota:

  • Objetivo C. syncData primeiro empurra novas alterações e, em seguida, chama pullData para obter dados da extremidade traseira remota. Por sua vez, o método pullData obtém novos dados que correspondem a uma consulta:

    -(void)syncData:(QSCompletionBlock)completion
    {
         // Push all changes in the sync context, and then pull new data.
         [self.client.syncContext pushWithCompletion:^(NSError *error) {
             [self logErrorIfNotNil:error];
             [self pullData:completion];
         }];
    }
    
    -(void)pullData:(QSCompletionBlock)completion
    {
         MSQuery *query = [self.syncTable query];
    
         // Pulls data from the remote server into the local table.
         // We're pulling all items and filtering in the view.
         // Query ID is used for incremental sync.
         [self.syncTable pullWithQuery:query queryId:@"allTodoItems" completion:^(NSError *error) {
             [self logErrorIfNotNil:error];
    
             // Lets the caller know that we have finished.
             if (completion != nil) {
                 dispatch_async(dispatch_get_main_queue(), completion);
             }
         }];
    }
    
  • Rápido:

    func onRefresh(sender: UIRefreshControl!) {
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    
        self.table!.pullWithQuery(self.table?.query(), queryId: "AllRecords") {
            (error) -> Void in
    
            UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    
            if error != nil {
                // A real application would handle various errors like network conditions,
                // server conflicts, etc. via the MSSyncContextDelegate
                print("Error: \(error!.description)")
    
                // We will discard our changes and keep the server's copy for simplicity
                if let opErrors = error!.userInfo[MSErrorPushResultKey] as? Array<MSTableOperationError> {
                    for opError in opErrors {
                        print("Attempted operation to item \(opError.itemId)")
                        if (opError.operation == .Insert || opError.operation == .Delete) {
                            print("Insert/Delete, failed discarding changes")
                            opError.cancelOperationAndDiscardItemWithCompletion(nil)
                        } else {
                            print("Update failed, reverting to server's copy")
                            opError.cancelOperationAndUpdateItem(opError.serverItem!, completion: nil)
                        }
                    }
                }
            }
            self.refreshControl?.endRefreshing()
        }
    }
    

Na versão Objective-C, em syncData, chamamos pela primeira vez pushWithCompletion no contexto de sincronização. Este método é um membro ( MSSyncContext e não a própria tabela de sincronização) porque empurra mudanças em todas as tabelas. Apenas os registos que tenham sido modificados localmente (através de operações cud) são enviados para o servidor. Em seguida, o helper pullData é chamado, que chama MSSyncTable.pullWithQuery para recuperar dados remotos e armazená-los na base de dados local.

Na versão Swift, como a operação push não era estritamente necessária, não há nenhuma chamada para empurrar ComCompletion. Se houver alterações pendentes no contexto de sincronização para a tabela que está a fazer uma operação de impulso, puxe sempre emitindo um empurrão primeiro. No entanto, se tiver mais do que uma tabela de sincronização, o melhor é chamar explicitamente o impulso para garantir que tudo é consistente entre tabelas relacionadas.

Tanto nas versões Objective-C como Swift, pode utilizar o método pullWithQuery para especificar uma consulta para filtrar os registos que pretende obter. Neste exemplo, a consulta recupera todos os registos na tabela remota TodoItem .

O segundo parâmetro de pullWithQuery é um ID de consulta que é usado para sincronização incremental. A sincronização incremental só recupera registos que foram modificados desde a última sincronização, utilizando o carimbo temporal do UpdatedAt registo (chamado updatedAt na loja local.) O ID de consulta deve ser uma cadeia descritiva única para cada consulta lógica na sua aplicação. Para excluir a sincronização incremental, passe nil como ID de consulta. Esta abordagem pode ser potencialmente ineficiente, pois recupera todos os registos em cada operação de puxar.

A aplicação Objective-C sincroniza quando modifica ou adiciona dados, quando um utilizador executa o gesto de atualização e no lançamento.

A aplicação Swift sincroniza quando o utilizador executa o gesto de atualização e no lançamento.

Como a aplicação sincroniza sempre que os dados são modificados (Objective-C) ou sempre que a aplicação começa (Objective-C e Swift), a aplicação assume que o utilizador está online. Numa secção posterior, irá atualizar a aplicação para que os utilizadores possam editar mesmo quando estiverem offline.

Reveja o modelo de Dados Fundamentais

Quando utilizar a loja offline de Dados Core, deve definir tabelas e campos específicos no seu modelo de dados. A aplicação da amostra já inclui um modelo de dados com o formato certo. Nesta secção, caminhamos por estas mesas para mostrar como são usadas.

Open QSDataModel.xcdatamodeld. Quatro tabelas são definidas-- três que são usadas pelo SDK e uma que é usada para os itens a fazer em si:

  • MS_TableOperations: Rastreia os itens que precisam de ser sincronizados com o servidor.
  • MS_TableOperationErrors: Rastreia quaisquer erros que ocorram durante a sincronização offline.
  • MS_TableConfig: Rastreia a última hora atualizada para a última operação de sincronização para todas as operações de pull.
  • TodoItem: Armazena os itens a fazer. As colunas do sistema criadasAt, atualizadas eversão são propriedades opcionais do sistema.

Nota

O Mobile Apps SDK reserva nomes de colunas que começam com "``". Não utilize este prefixo com nada além de colunas do sistema. Caso contrário, os nomes das colunas são modificados quando utilizar a extremidade traseira remota.

Quando utilizar a função de sincronização offline, defina as três tabelas do sistema e a tabela de dados.

Tabelas do sistema

MS_TableOperations

atributos de tabela MS_TableOperations

Atributo Tipo
ID Inteiro 64
itemId String
propriedades Dados Binários
table String
tableKind Inteiro 16

MS_TableOperationErrors

MS_TableOperationErrors atributos de tabela

Atributo Tipo
ID String
operationId Inteiro 64
propriedades Dados Binários
tableKind Inteiro 16

MS_TableConfig

Atributo Tipo
ID String
key String
teclaType Inteiro 64
table String
valor String

Tabela de dados

TodoItem

Atributo Tipo Nota
ID Corda, marcada necessária Chave primária na loja remota
completar Booleano Campo de artigos a fazer
texto String Campo de artigos a fazer
criadoAt Date (opcional) Mapas para criar Propriedade do sistemaAt
atualizadoAt Date (opcional) Mapas para propriedade do sistema atualizadoAt
versão String (opcional) Usado para detetar conflitos, mapas para versão

Alterar o comportamento sincronizado da app

Nesta secção, modifica a aplicação para que não se sincroniza no início da aplicação ou quando insere e atualize itens. Só sincroniza quando o botão de gesto de atualização é executado.

Objetivo C:

  1. Em QSTodoListViewController.m, altere o método viewDidLoad para remover a chamada no [self refresh] final do método. Agora os dados não estão sincronizados com o servidor no início da aplicação. Em vez disso, está sincronizado com o conteúdo da loja local.

  2. No QSTodoService.m, modifique a definição de modo addItem a não sincronizar após a inserção do artigo. Retire o self syncData bloco e substitua-o pelo seguinte:

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. Modifique a definição de completeItem como mencionado anteriormente. Retire o bloco e substitua-o pelo self syncData seguinte:

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    

Rápido:

Em viewDidLoad, no ToDoTableViewController.swift, comente as duas linhas mostradas aqui, para parar de sincronizar no início da aplicação. No momento desta escrita, a aplicação Swift Todo não atualiza o serviço quando alguém adiciona ou completa um item. Atualiza o serviço apenas no início da aplicação.

self.refreshControl?.beginRefreshing()
self.onRefresh(self.refreshControl)

Testar a aplicação

Nesta secção, você se conecta a um URL inválido para simular um cenário offline. Quando adicionas itens de dados, eles são mantidos na loja local de Dados core, mas eles não estão sincronizados com a aplicação móvel back end.

  1. Altere o URL da aplicação móvel no QSTodoService.m para um URL inválido e volte a executar a aplicação:

    Objetivo C. No QSTodoService.m:

    self.client = [MSClient clientWithApplicationURLString:@"https://sitename.azurewebsites.net.fail"];
    

    O Swift. No ToDoTableViewController.swift:

    let client = MSClient(applicationURLString: "https://sitename.azurewebsites.net.fail")
    
  2. Adicione alguns itens a fazer. Saia do simulador (ou feche à força a aplicação) e, em seguida, reinicie-a. Verifique se as alterações persistem.

  3. Veja o conteúdo da tabela todoItem remota:

    • Para um Node.js back end, vá ao portal do Azure e, na sua aplicação móvel de volta, clique em Easy Tables>TodoItem.
    • Para uma extremidade traseira .NET, utilize uma ferramenta SQL, como SQL Server Management Studio, ou um cliente REST, como o Fiddler ou o Carteiro.
  4. Verifique se os novos itens não foram sincronizados com o servidor.

  5. Altere o URL de volta para o correto no QSTodoService.m e volte a fazer a aplicação.

  6. Execute o gesto de atualização puxando para baixo a lista de itens.
    É apresentado um spinner de progresso.

  7. Consulte novamente os dados do TodoItem . Os novos itens de trabalho alterados e alterados devem agora ser apresentados.

Resumo

Para suportar a funcionalidade de sincronização offline, utilizamos a MSSyncTable interface e iniciaisizamos MSClient.syncContext com uma loja local. Neste caso, a loja local era uma base de dados baseada em dados core.

Quando utilizar uma loja local de Dados Core, deve definir várias tabelas com as propriedades corretas do sistema.

As operações normais de criação, leitura, atualização e eliminação (CRUD) para aplicações móveis funcionam como se a aplicação ainda estivesse conectada, mas todas as operações ocorrem contra a loja local.

Quando sincronizamos a loja local com o servidor, usamos o método MSSyncTable.pullWithQuery .

Recursos adicionais