Skip to main content

Sincronizar alterações offline com a Sincronização móvel

Objetivos de aprendizagem

Após concluir esta unidade, você estará apto a:

  • Compreender os conceitos básicos da Sincronização móvel.
  • Usar a biblioteca da Sincronização móvel para sincronizar dados entre o dispositivo local do usuário e o servidor do Salesforce.

Como usar a Sincronização móvel para sincronizar alterações offline

A Sincronização móvel é uma biblioteca do Mobile SDK que trabalha com o SmartStore para garantir a integridade e a coerência dos registros do Salesforce. A Sincronização móvel permite que os clientes que usam aplicativos do Mobile SDK continuem a editar os registros do Salesforce localmente quando seus dispositivos móveis perdem a conectividade. Quando a conectividade é restaurada, o aplicativo do Mobile SDK usa a estrutura para sincronizar as mudanças locais no SmartStore com os respectivos registros no servidor Salesforce.

Sobre solicitações de rede

Todas as solicitações de dados nos aplicativos de Sincronização móvel são assíncronas. Os métodos de sincronização formatam a solicitação e a enviam à nuvem do Salesforce. Seu aplicativo recebe a resposta do servidor em um método de retorno de chamada, bloco de atualização ou promessa, consoante a plataforma. As respostas incluem um objeto de estado de sincronização que descreve as configurações e o status da operação de sincronização.

Os métodos de Sincronização móvel automatizam tarefas de rede comuns, como buscar metadados do sObject, buscar uma lista dos objetos usados mais recentemente e emitir consultas SOQL e SOSL. Seu aplicativo pode chamar métodos de gerenciador de sincronização a qualquer momento, mas eles obviamente só podem ter sucesso quando o dispositivo host estiver conectado à internet. Seu aplicativo determina o status de conexão do dispositivo.

Como configurar aplicativos para usar a Sincronização móvel

Os aplicativos do Mobile SDK usam um objeto central do SDK Manager para impor a inicialização do aplicativo e os protocolos de autenticação corretos. O gerente usado pelo seu aplicativo também determina o escopo das funções do SDK incluídas no aplicativo. Os aplicativos inicializam o objeto MobileSyncSDKManager durante a inicialização em bootstrap.

SDKs nativos Android e iOS implementam três objetos do Manager.

SalesforceSDKManager

Para os aplicativos mais básicos. Esses aplicativos não usam recursos offline do Mobile SDK.

SmartStoreSDKManager

Para aplicativos que usam o SmartStore, mas não a Sincronização móvel.

MobileSyncSDKManager

Para aplicativos que usam o SmartStore e a Sincronização móvel.

Quando você cria um aplicativo nativo com forcedroid ou forceios, esse aplicativo novo é automaticamente configurado para usar MobileSyncSDKManager. Esse gerenciador importa o SmartStore, a Sincronização móvel e todas as outras bibliotecas do Mobile SDK. 

Configuração de sincronização

Sempre que você está sincronizando por upload do SmartStore para o Salesforce ou por download do Salesforce para o SmartStore, está fornecendo detalhes de configuração de sincronização. Você pode configurar uma operação de sincronização no código ou em um arquivo de configuração JSON. De qualquer forma, no tempo de execução, o Mobile SDK retorna sua configuração para seu aplicativo como um objeto de estado de sincronização.

No nível mais básico, você fornece:

  • store — Indica se o repositório usado é um repositório global ou um repositório de usuário. Se você está usando um repositório nomeado, o nome dele também é especificado.
  • soup name — Nome do soup que é a origem de uma operação de sincronização por upload ou o destino de uma operação de sincronização por download. Esse soup é necessário para dar suporte a um campo de sequência de caracteres indexado chamado __local__.

Mais dois parâmetros definem o que a operação de sincronização faz:

  • target — Descreve os registros que estão sendo sincronizados. O destino é o valor central de configuração de qualquer operação de sincronização. Pense no destino como a descrição do escopo dos dados exigido pela sua operação.
  • options — Controla como a operação mescla os dados. Em algumas situações, você pode usar opções em vez de um destino a fim de fornecer uma lista de nomes de campo para sincronização.

O uso dos parâmetros target e options difere nas operações de sincronização por upload e por download, conforme descrito nas seções a seguir. Em alguns casos, um desses parâmetros pode ser opcional. Se você omitir o parâmetro target ou options opcional, a Sincronização móvel assumirá um valor padrão.

Depois que uma operação de sincronização é concluída, seu aplicativo recebe notificações assíncronas que permitem realizar tarefas de acompanhamento. Essas tarefas podem incluir o envio de notificações de eventos, o sucesso de registro em log ou o uso dos dados de outras maneiras que venham a melhorar seu aplicativo.

Sincronização por download – parâmetros Target e Options

  • target – especifica o tipo de sObject de origem e os campos que devem ser baixados para o soup. Você pode usar qualquer uma das seguintes sequências de caracteres:
    • Para consultas SOQL: {type:"soql", query:"<soql_query>"}
      Baixa os sObjects retornados pela consulta SOQL fornecida
    • Para consultas SOSL: {type:"sosl", query:"<sosl_query>"}
      Baixa os sObjects retornados pela consulta SOSL fornecida
    • Para consultas MRU: {type:"mru", sobjectType:"<sobject_type>", fieldlist:"<fields_to_fetch>"}
      Baixa os campos especificados dos sObjects usados mais recentemente do tipo de sObject especificado. O Mobile SDK envia a solicitação ao Salesforce, recebe a resposta e usa a configuração para preencher o soup.
  • options — (opcional) Mapear com a seguinte chave:
    • mergeMode— Para controlar como a Sincronização móvel mescla dados a soups locais, defina essa chave com um dos seguintes modos:
      Substituir
      (padrão) Substitui registros que foram modificados. Se você não especificar um modo de mesclagem, a Sincronização móvel substituirá os dados locais.
      Deixar se for alterado
      Preserva registros que foram modificados. Esse modo exige mais viagens de ida e volta ao servidor e, portanto, use-o com parcimônia.

Sincronização por upload – Parâmetros Target e Options

  • target – Mapear com uma ou todas as chaves abaixo:
    • createFieldlist – nomes de campos do soup, separados por vírgulas, cujos valores devem ser inseridos nos registros do Salesforce recém-criados. Pode conter campos bloqueados (somente leitura).
    • updateFieldlist – nomes de campos do soup, separados por vírgulas, que devem ser usados para atualizar campos editáveis nos registros do Salesforce existentes. Não pode conter campos bloqueados (somente leitura).
  • O parâmetro target não é exigido em alguns métodos de sincronização por upload. Nesses casos, use a chave fieldlist em options para especificar os campos que serão sincronizados.
  • options – Mapear com uma ou mais chaves abaixo:
    • fieldlist – lista dos nomes de campo do soup, separados por vírgulas, que você está enviando ao servidor. Você pode usar essa chave em vez das listas de campos do parâmetro target ou com o createFieldList do seu destino. Não deixe sua operação de sincronização por upload tentar atualizar campos somente leitura no servidor.
    • mergeMode — Para controlar como a Sincronização móvel mescla dados locais à organização do Salesforce, defina essa chave com um dos seguintes modos:
      Substituir
      (Configuração padrão) Substitui os registros do servidor que foram modificados.
      Deixar se for alterado
      Preserva registros de servidores que foram modificados. Esse modo exige mais viagens de ida e volta ao servidor e, portanto, use-o com parcimônia.

Parâmetro Store

Aplicativos híbridos e React Native indicam o repositório que estão usando através do parâmetro storeConfig opcional. Esse parâmetro se aplica a operações de sincronização por upload e por download. Você pode especificá-lo de duas maneiras diferentes.

Como mapa dos seguintes pares chave-valor:

  • isGlobalStore – (opcional) um booleano que indica se você está usando um repositório global (true) ou de usuário (false). O valor padrão é false.
  • storeName – (opcional) nome do repositório. O valor padrão é o nome do repositório padrão.

Por exemplo:

{"isGlobalStore" :false, "storeName" :"MyStore"}

Como booleano:

Em vez disso, você pode transmitir um simples valor booleano. Nesse caso, o Mobile SDK atribui o valor à chave isGlobalStore.

Se você omitir o parâmetro store, a Sincronização móvel realizará operações no repositório do usuário atual.

Como usar sincronizações nomeadas e arquivos de configuração de sincronização

Os métodos padrão de sincronização por upload e por download exigem que você transmita cada parâmetro de sincronização como um argumento diferente. O Mobile SDK fornece dois recursos que ajudam a organizar e a simplificar essas tarefas de sincronização. Esses recursos são os nomes de sincronização e os arquivos de configuração de sincronização, e eles trazem ótimos resultados com pouco esforço. Embora não seja obrigatório usar arquivos de configuração, nós os usamos em grande medida nesta trilha.

Para refazer uma sincronização, use o método reSync da plataforma. Os métodos de ressincronização usam um destes identificadores para procurar sua configuração:

  • Sync ID — Cada método de sincronização retorna uma ID de tempo de execução como parte de um objeto de estado. Você pode passar essa ID para reSync a fim de reexecutar uma sincronização já usada na sessão atual.
  • Sync name (Opcional) — Você pode nomear uma configuração de sincronização na memória quando a executa pela primeira vez ou pode importar o nome e sua configuração de sincronização de um arquivo JSON externo.

Nomes de sincronização

As operações de sincronização podem ser complicadas de se configurar e costumam ser reutilizadas com frequência. Os nomes de sincronização dão a você a conveniência de reexecutar suas sincronizações sem recodificá-las. Por exemplo, você pode usar nomes de sincronização para:

  • Configure operações de sincronização em um arquivo JSON externo em vez de no código
  • Reexecutar uma operação de sincronização usada anteriormente sem reconfigurá-la
  • Obter o status de uma operação de sincronização em andamento
  • Verificar a existência de uma configuração de sincronização
  • Excluir uma configuração de sincronização

Você pode criar sincronizações nomeadas com as APIs ou nos arquivos de configuração de sincronização. O Mobile SDK é compatível com sincronizações nomeadas em todas as plataformas para todos os tipos de aplicativo.

Sincronizar arquivos de configuração

Com arquivos de configuração de sincronização, você pode criar suas definições de sincronização por upload e download uma vez em um arquivo JSON e depois reimportá-las em todas as versões dos seus aplicativos. O Mobile SDK dá suporte a arquivos de configuração de sincronização em aplicativos nativos e híbridos. Vamos examinar a estrutura e as regras desses arquivos.

Nomes de arquivo

O Mobile SDK só é compatível com arquivos de configuração em repositórios globais padrão e repositórios de usuário padrão.

  • No caso do repositório global padrão, forneça um arquivo chamado globalsyncs.json.
  • No caso do repositório de usuário padrão, forneça um arquivo chamado usersyncs.json.

Locais de arquivo

Coloque seus arquivos de configuração nos locais a seguir.
iOS:

  • Aplicativos nativos e React Native: / no bundle Recursos
  • Aplicativos híbridos: /www no bundle Recursos

Android:

  • Aplicativos nativos e React Native: /res/raw
  • Aplicativos híbridos: /assets/www

Formato do arquivo

O formato do arquivo é o mesmo, independentemente do tipo de aplicativo ou da plataforma utilizada. Uma definição de sincronização requer cinco campos:

  • Sync name
  • Sync type
  • Nome do soup
  • Target
  • Opções

O arquivo de configuração a seguir define as operações de sincronização por download e por upload. As duas configurações usam os mesmos campos: Id, Name e LastModifiedDate. No entanto, observe duas regras importantes para a colocação dos valores:

  • A configuração de sincronização por download especifica os campos no membro “target” usando uma consulta SOQL, enquanto a sincronização por upload os especifica em “options” como uma lista.
  • A operação de sincronização por download especifica o modo de mesclagem em “options” e a sincronização por upload faz o mesmo em “merge_mode”.

Modos de mesclagem opostos, como “OVERWRITE” para a sincronização por download contra “LEAVE_IF_CHANGED” para a sincronização por upload, garantem uma única origem verdadeira. Nesse caso, eles permitem que os dados do servidor substituam os dados do soup, mas não o contrário.

{
  "syncs": [
    {
      "syncName": "sync1",
      "syncType": "syncDown",
      "soupName": "accounts",
      "target": {"type":"soql", "query":"SELECT Id, Name, LastModifiedDate 
        FROM Account"},
      "options": {"mergeMode":"OVERWRITE"} 
    },
    {
      "syncName": "sync2",
      "syncType": "syncUp",
      "soupName": "accounts",
      "target": {"createFieldlist":["Name"]},
      "options": {"fieldlist":["Id", "Name", "LastModifiedDate"],
      "mergeMode":"LEAVE_IF_CHANGED"}
    }
  ]
 }

Usar Sincronização móvel com porta-arquivos

Um porta-arquivos é um conjunto de consultas que juntas selecionam uma coleção coesa de registros relacionados, otimizados para o que você deseja. Use porta-arquivos para selecionar registros para a preparação de dados antes de tirar do ar e para outras finalidades gerais de carregamento de dados.

Configuração de sincronização

No aplicativo Explorer Template da Sincronização móvel, você pode atualizar o arquivo JSON da sincronização do usuário para configurar suas operações de sincronização nos dois sentidos. 

Na propriedade "target", especifique os seguintes valores.

Propriedades de destino

"type":"briefcase"

"infos": array of <BriefcaseObjectInfo> items

Uma matriz de objetos que descreve os sObjects e campos específicos a buscar, junto com o soup para incluí-los.

Propriedades de BriefcaseObjectInfo

"soupName": <string>

Nome do soup ou tabela para armazenar registros deste tipo de objeto durante a sincronização.

"sobjectType": <string>

Nome de um objeto do Salesforce a sincronizar.

"fieldlist": array of <string>

Lista de campos a sincronizar neste objeto.

"idFieldName": <string>

(Opcional) Nome de um campo personalizado de ID. Se fornecer "idFieldName", a Sincronização móvel usará o campo com o nome fornecido para obter o ID do registro. Por exemplo, se especificar "idFieldName":"AcmeId", a Sincronização móvel obterá o ID do registro do campo AcmeId em vez de obter do campo de ID padrão.

"modificationDateFieldName": <string>

(Opcional) Nome do campo que contém a data da última modificação do registro. Se fornecer modificationDateFieldName, a Sincronização móvel usará o campo com esse nome para calcular o valor maxTimestamp que startFetch usa para ressincronizar os registros. O nome do campo padrão é lastModifiedDate.

Obrigatório: “soupName”, “sobjectType”, “fieldlist”

Sincronização por download

Nota

Se sua organização usa porta-arquivos para usuários móveis, o destino de sincronização do porta-arquivos foi introduzido no Mobile SDK 10.1.

Vejamos um exemplo de arquivo do porta-arquivos configurado para sincronização por download. 

{
  "syncs": [
    {
      "syncName": "syncDownContacts", 
      "syncType": "syncDown",
      "soupName": "contacts",
      "target": {
        "type": "briefcase",      
        "infos": [
          {
            "sobjectType": "Account",
            "fieldlist": [
              "Name",
              "Description"
            ],
            "soupName": "accounts"
          },
          {
            "sobjectType": "Contact",
            "fieldlist": [
              “FistName”, "LastName", “Title”, “Email”
            ],
            "soupName": "contacts"
          }
        ]
      },
      "options": {
        "mergeMode": "OVERWRITE"
      }
    }
  ]
}

Para sincronizar por download, defina o “syncType” como “syncDown”. Isso ativa a operação de sincronização por download, que sincroniza os dados do servidor para o cliente. Nomeie sua operação de sincronização por download ao lado de “syncName”. Neste caso, foi nomeada como “syncDownContacts”

Ao lado de “soupName”, defina a tabela ou o soup que deseja atualizar na operação de sincronização por download. Neste caso, o soup a ser atualizado chama-se “contacts”.

Abaixo do “target”, defina o tipo como “briefcase”. Abaixo do objeto JSON “infos”, defina as entidades que deseja sincronizar, neste caso: “Account” e “Contact”. Para cada entidade, indique os campos que deseja sincronizar na “fieldlist”

Para cada entidade, indique a tabela correspondente que deseja atualizar no cliente ao lado de “soupName”.  

Em “options” (opções), defina a opção “mergeMode”, que nesse caso está definida como “OVERWRITE” (SUBSTITUIR). Caso dois usuários tentem atualizar o mesmo registro, esta opção dá a prioridade de substituir ao último usuário que o tenha atualizado.

Sincronização por upload

Agora, vejamos a configuração para sincronizar por upload.

{
“syncName: “syncUpContacts”,
“syncType”: “syncUp”,
“soupÑame”: “contacts”,
“target”: {
	“createFieldlist”: [
		“FirstName”, “LastName”, “Title”, “Email”
	]
},
“options”: {
	“fieldlist”: [
		“FirstName”, “LastName”, “Title”, “Email”
	],
	“mergeMode”: “LEAVE_IF_CHANGED”
}
}

Para usar a operação de sincronização por upload, configure a tabela desejada pelo “soupName”, que nesse caso é chamada “contacts”. Use “target” e “options” para indicar os campos que deseja sincronizar. O “mergeMode”, nesse caso, está definido como “LEAVE_IF_CHANGED”. Se qualquer registro do servidor tiver sido alterado desde a sincronização por download com esse cliente, ele deixa os registros do servidor e do cliente no estado atual.

Como usar a Sincronização móvel em aplicativos iOS nativos

Sincronização por download

Para baixar registros do Salesforce no seu soup do SmartStore, a Sincronização móvel oferece várias opções.

Você pode criar uma configuração de sincronização por download sem executá-la:

var syncState = syncManager.createSyncDown(target: target, options: options, 
    soupName: CONTACTS_SOUP, syncName: syncState.syncName)

Ou pode criar e executar uma operação de sincronização por download sem opções, mas saiba que isso substituirá as alterações feitas localmente:

var syncState = syncManager.syncDown(target:target, soupName:CONTACTS_SOUP, onUpdate:updateFunc)

Para ter mais controle, você pode criar e executar uma configuração de sincronização por download não nomeada que usa suas opções:

var syncState = syncManager.syncDown(target: target, options: options, 
    soupName: CONTACTS_SOUP, onUpdate:updateFunc)

Ou pode criar, nomear e executar uma configuração de sincronização por download:

var syncState = try syncManager.syncDown(target: target, options: options, 
    soupName: CONTACTS_SOUP, syncName: syncState.syncName, onUpdate:updateFunc)

A classe SyncTarget fornece métodos de fábrica para criar objetos de destino de uma sequência de caracteres de consulta SOQL, SOSL ou MRU. Especifique os objetos a serem baixados com uma sequência de caracteres de consulta SOQL ou SOSL. Se você usar um destino de consulta MRU, especifique somente uma lista de nomes de campo. O Mobile SDK relata o andamento da operação de sincronização pelo método de retorno de chamada ou bloco de atualização implementado.

No caso de iOS nativo, a opção mergeMOde pode ter um dos seguintes valores:

  • SFSyncStateMergeModeOverwrite – substituir registros locais modificados e perder todas as alterações feitas localmente.
  • SFSyncStateMergeModeLeaveIfChanged – preservar todas as alterações locais e todos os registros modificados localmente.
Nota

Se você usar o método syncDown(target:soupName:onUpdate:), que não usa um parâmetro options, o SmartSync pode substituir sObjects existentes no cache. Para preservar as alterações locais, sempre sincronize por upload antes de sincronizar por download.

Sincronização por upload

Durante a sincronização por upload, a Sincronização móvel replica registros de soup criados, atualizados e excluídos no servidor. O Mobile SDK fornece um destino padrão que você pode usar para não precisar defini-lo. O destino padrão é simples e direto: usando a API do Salesforce, ele simplesmente sincroniza os registros alterados do soup para o servidor.

Caso tenha um destino, você pode criar uma configuração de sincronização sem executá-la:

let syncState = syncManager.createSyncUp(target: target, options: options, 
    soupName: CONTACTS_SOUP, syncName: syncState.syncName)

Você pode utilizar o destino padrão com o seguinte método MobileSyncSyncManager:

let syncState = syncManager.syncUp(options: options, soupName: CONTACTS_SOUP, 
    onUpdate: updateFunc)

Se você tiver um destino de sincronização por upload personalizado, pode executá-lo chamando este método:

let syncState = syncManager.syncUp(target: target, options: options, 
    soupName: CONTACTS_SOUP, onUpdate: updateFunc)

Ou pode criar, nomear e executar uma operação de sincronização:

let syncState = 
    try syncManager.syncUp(target: target, options: options, 
        soupName: CONTACTS_SOUP, syncName: syncState.syncName, 
        onUpdate: updateFunc)

Ressincronização

Os métodos de ressincronização, que são importantes, mas muitas vezes ignorados, são versáteis e fáceis de codificar. Esses métodos executam configurações de sincronização que você definiu em outro lugar anteriormente. Apesar do nome, você pode usar esses métodos para executar uma sincronização nomeada pela primeira vez. Os método de ressincronização sincronizam somente registros que foram criados ou atualizados desde a última sincronização. Se a sincronização nunca foi executada, a ressincronização copia todos os registros, sejam novos ou alterados. Do contrário, ela realiza uma sincronização incremental.

Para usar os métodos de ressincronização, forneça uma ID de sincronização de uma operação anterior ou um nome de sincronização predefinido. Para executar uma sincronização nomeada existente:

var syncState = 
    try syncManager.reSync(named: syncState.syncName, onUpdate: updateFunc)

Se você armazenou em cache o valor SFSyncState.syncId retornado de uma operação de sincronização não nomeada anterior, pode usá-lo para executar essa sincronização novamente:

var syncState = 
    try syncManager.reSync(id: syncState.syncId, onUpdate: updateFunc)

Os métodos reSync dão suporte tanto a configurações de sincronização por upload quanto por download.

Exemplo

Os aplicativos nativos Swift criados por forceios usam um modelo que demonstra os recursos básicos do SmartStore e da Sincronização móvel. Esse modelo usa editores Combine para SmartStore e Sincronização móvel para simplificar seu código. Esses editores estão disponíveis no Mobile SDK como extensões para as classes SmartStore e MobileSync. Vamos dar uma olhada nessa implementação como realizada no projeto iOSNativeSwiftTemplate

Primeiro, crie um aplicativo para exploração.

  1. Em uma janela Terminal, crie um aplicativo com forceios.
    • Use native_swift para o tipo de aplicativo.
    • Para conveniência, nomeie o aplicativo offlineSwift.
  2. Quando o forceios terminar, abra o novo espaço de trabalho no Xcode.

No Xcode, confira os recursos offline na configuração.

  1. No Project Navigator (⌘1), expanda offlineSwift > offlineSwift > Arquivos de suporte. Aqui, você encontra os arquivos userstore.json e usersyncs.json. Se você abri-los no Editor, poderá ver que eles definem configurações básicas para acessar e sincronizar registros de conta.
  2. O modelo adiciona userstore.json e usersyncs.json ao pacote de aplicativos nas configurações de Fases de compilação do projeto. 
    1. No navegador do projeto Xcode, selecione o nó do projeto.
    2. Na janela do editor, selecione Build Phases (Criar etapas).
    3. Expanda Copy Bundle Resources (Copiar recursos do pacote). Observe que userstore.json e usersyncs.json estão listados, o que significa que eles são adicionados ao pacote de aplicativos quando o aplicativo é compilado.

Agora, vamos examinar o código.

  1. No Project Navigator, expanda offlineSwift > offlineSwift > Classes > SwiftUI.
  2. Em SceneDelegate.swift, o modelo adiciona uma função de configuraçãoRootViewController() que carrega as configurações offline na memória. Essa função é chamada intencionalmente apenas uma vez por sessão do usuário. É importante lembrar que você não pode chamar esses métodos de configuração mais de uma vez por sessão ou usá-los para carregar um conjunto diferente de configurações. 
    // Set up store based on config userstore.json
    MobileSyncSDKManager.shared.setupUserStoreFromDefaultConfig()
    // Set up syncs based on config usersyncs.json
    MobileSyncSDKManager.shared.setupUserSyncsFromDefaultConfig()
  3. No Project Navigator, expanda offlineSwift > offlineSwift > Classes > Modelos.
  4. Em AccountsListModel.swift, observe a primeira linha na classe AccountsListModel. Essa linha define uma matriz publicada vazia de objetos de conta. Os objetos SwiftUI no aplicativo assinam AccountsListModel para receber atualizações quando a matriz publicada é alterada.
    /**
    ViewModel for Account List
    */
    class AccountsListModel: ObservableObject {
      @Published var accounts: [Account] = []
      ...
  5. Encontre a função fetchAccounts().
    func fetchAccounts(){
      syncTaskCancellable = syncManager?.publisher(for: "syncDownAccounts")
        .receive(on: RunLoop.main)
        .sink(receiveCompletion: { _ in }, receiveValue: { _ in
          self.loadFromSmartStore()
      })
      self.loadFromSmartStore()
    }
    Aqui, o editor de Sincronização móvel pega uma operação de sincronização - "syncDownAccounts", definida em usersyncs.json-- e a ressincroniza. Em seguida, o editor copia os dados devolvidos em soups no repositório SmartStore padrão. QuandofetchAccounts() recebe a resposta do editor, ele chama loadFromSmartStore() para copiar assincronicamente os dados atualizados do SmartStore na matriz accounts publicada. Enquanto espera a resposta chegar, fetchAccounts() também chama loadFromSmartStore() para garantir que a matriz accounts estará atualizada com eventuais alterações locais. Vamos ver como loadFromSmartStore() realiza essas atualizações.
  6. A função loadFromSmartStore() usa o editor smartStore para emitir uma consulta Smart Sql e receber a resposta assíncrona. Se a resposta indicar sucesso, a função publica o conjunto de dados resultante no chamador. Aqui, o chamador copia a resposta analisada na matriz accounts no objeto AccountsListModel.  
    import MobileSync
    ...
    private func loadFromSmartStore() {
      storeTaskCancellable = self.store?.publisher(for: "select {Account:Name}, {Account:Industry}, {Account:Id} from {Account}")
      .receive(on: RunLoop.main)
      .tryMap {
        $0.map { (row) -> Account in
          let r = row as! [String?]
          return Account(id: r[2] ?? "", name: r[0] ?? "", industry: r[1] ?? "Unknown Industry" )
        }
      }
      .catch { error -> Just<[Account]> in
        print(error)
        return Just([Account]())
      }
      .assign(to: \AccountsListModel.accounts, on:self)
    } 

Quando a matriz accounts é preenchida, o aplicativo pode prosseguir com sua lógica primária, que, nesse caso, é: 

  • Exibir as contas consultadas e seus detalhes
  • Para qualquer conta que o cliente selecionar, consulta e, em seguida, exibe os contatos e seus detalhes

Como usar a Sincronização móvel em aplicativos Android nativos

Sincronização por download

Para baixar sObjects do servidor para o soup local da Sincronização móvel, use um dos métodos SyncManager a seguir.

Você pode criar uma configuração de sincronização por download sem executá-la:

public SyncState createSyncDown(SyncDownTarget target, 
    SyncOptions options, String soupName, String syncName) 
    throws JSONException;

Ou pode criar e executar uma operação de sincronização por download sem opções, mas saiba que isso substituirá as alterações feitas localmente:

public SyncState syncDown(SyncDownTarget target, String soupName, 
    SyncUpdateCallback callback) throws JSONException;

Para ter mais controle, você pode criar e executar uma operação de sincronização por download não nomeada que usa suas próprias opções de mesclagem:

public SyncState syncDown(SyncDownTarget target, SyncOptions options,
    String soupName, SyncUpdateCallback callback) 
    throws JSONException;

Ou pode nomear essa configuração de sincronização por download na sua criação e depois executá-la:

public SyncState syncDown(SyncDownTarget target, SyncOptions options, 
    String soupName, SyncUpdateCallback callback) 
    throws JSONException;

Sincronização por upload

Para aplicar as alterações locais ao servidor, use um dos métodos SyncManager a seguir.

  • Você pode criar uma configuração de sincronização por upload nomeada sem executá-la:
    public SyncState createSyncUp(SyncUpTarget target, 
        SyncOptions options, 
        String soupName, 
        String syncName) 
        throws JSONException;
  • Você pode criar e executar uma configuração de sincronização não nomeada em uma chamada:
    public SyncState syncUp(SyncUpTarget target, 
        SyncOptions options, 
        String soupName, 
        SyncUpdateCallback callback) 
        throws JSONException;
  • Ou pode criar e executar uma configuração de sincronização por upload nomeada em uma chamada:
    public SyncState syncUp(SyncUpTarget target, 
        SyncOptions options, 
        String soupName, 
        String syncName, 
        SyncUpdateCallback callback) 
        throws JSONException;

Os métodos syncUp atualizam o servidor com dados do soup do SmartStore especificado. Eles procuram registros criados, atualizados ou excluídos no soup e replicam as alterações no servidor. Um ou ambos os parâmetros target ou options especificam uma lista de campos a serem carregados. Um destino permite diferenciar entre um createFieldlist para criar registros e um updateFieldlist para atualizar os registros existentes. Essas configurações permitem sincronizar novos registros e evitar tentativas de atualizar campos somente leitura nos registros existentes. Se você definir listas de campos de destino e listas de campos de opções, a configuração options é ignorada.

Ressincronização

A dupla de métodos de ressincronização, que é importante, mas muitas vezes ignorada, é versátil e fácil de codificar. Esses métodos executam configurações de sincronização que você definiu em outro lugar anteriormente. Apesar do nome, você também pode usar esses métodos para executar uma sincronização nomeada pela primeira vez. Em execuções subsequentes, os métodos de ressincronização sincronizam somente registros que foram criados ou atualizados desde a sincronização anterior. Se a sincronização nunca foi executada, a ressincronização copia todos os registros, sejam novos ou alterados. Do contrário, ela realiza uma sincronização incremental.

Para usar os métodos de ressincronização, forneça uma ID de sincronização de uma operação anterior ou um nome de sincronização predefinido. Para executar uma sincronização nomeada:

public SyncState reSync(String syncName, SyncUpdateCallback callback) 
    throws JSONException;

Se você armazenou em cache o valor SFSyncState.syncId retornado de uma operação de sincronização anterior, pode executar essa sincronização novamente usando reSync:updateBlock::

public SyncState reSync(long syncId, SyncUpdateCallback callback) 
    throws JSONException;

Os métodos reSync dão suporte tanto a configurações de sincronização por upload quanto por download.

Exemplo

No Android, o aplicativo de exemplo MobileSyncExplorer nativo demonstra como usar as sincronizações nomeadas e os arquivos de configuração de sincronização da Sincronização móvel com registros de contato. Ele define uma classe ContactObject que representa um registro de contato do Salesforce como um objeto Java. Para sincronizar dados de contato por download para o soup do SmartStore, o método syncDown() faz a ressincronização de uma configuração de sincronização por download nomeada que define uma consulta SOQL.

Esse aplicativo armazena os arquivos userstore.json e usersyncs.json na pasta de projeto /res/raw. Aqui está userstore.json:

{
  "soups": [
    {
      "soupName": "contacts",
      "indexes": [
        { "path": "Id", "type": "string"},
        { "path": "FirstName", "type": "string"},
        { "path": "LastName", "type": "string"},
        { "path": "__local__", "type": "string"},
        { "path": "__locally_created__", "type": "string"},
        { "path": "__locally_updated__", "type": "string"},
        { "path": "__locally_deleted__", "type": "string"},
        { "path": "__sync_id__", "type": "integer"}
      ]
    }
  ]
}

E usersyncs.json:

{
  "syncs": [
    {
      "syncName": "syncDownContacts",
      "syncType": "syncDown",
      "soupName": "contacts",
      "target": {"type":"soql", "query":"SELECT FirstName, LastName, Title, MobilePhone, Email, Department, HomePhone FROM Contact LIMIT 10000"},
      "options": {"mergeMode":"OVERWRITE"}
    },
    {
      "syncName": "syncUpContacts",
      "syncType": "syncUp",
      "soupName": "contacts",
      "target": {"createFieldlist":["FirstName", "LastName", "Title", "MobilePhone", "Email", "Department", "HomePhone"]},
      "options": {"fieldlist":["Id", "FirstName", "LastName", "Title", "MobilePhone", "Email", "Department", "HomePhone"], "mergeMode":"LEAVE_IF_CHANGED"}
    }
  ]
 }

Esse aplicativo de exemplo carrega esses arquivos em memória em seu construtor ContactListLoader

public ContactListLoader(Context context, UserAccount account) {
  super(context);
  MobileSyncSDKManager sdkManager = MobileSyncSDKManager.getInstance();
  smartStore = sdkManager.getSmartStore(account);
  syncMgr = SyncManager.getInstance(account);
  // Setup schema if needed
  sdkManager.setupUserStoreFromDefaultConfig();
  // Setup syncs if needed
  sdkManager.setupUserSyncsFromDefaultConfig();
}

No método abaixo da classe ContactListLoader, o método local syncDown() executa reSync() com a configuração syncDownContacts:

public synchronized void syncDown() {
    
    try {
      syncMgr.reSync(SYNC_DOWN_NAME /* see usersyncs.json */, new SyncUpdateCallback() {
            @Override
            public void onUpdate(SyncState sync) {
                if (Status.DONE.equals(sync.getStatus())) {
                    fireLoadCompleteIntent();
                }
            }
        });
    } catch (JSONException e) {
        Log.e(TAG, "JSONException occurred while parsing", e);
    } catch (MobileSyncException e) {
        Log.e(TAG, "MobileSyncException occurred while attempting to sync down", e);
    }
 
}

Se a operação de sincronização por download for bem-sucedida, ou seja, se sync.getStatus() for igual a Status.DONE, os dados recebidos irão para o soup especificado. O método de retorno de chamada aciona uma intenção que recarrega os dados na lista Contatos.

Da mesma forma, o método local syncUp() do ContactListLoader executa reSync() com a configuração syncUpContacts:

public synchronized void syncUp() {
       
    try {
        
        syncMgr.reSync(SYNC_UP_NAME /* see usersyncs.json */, new SyncUpdateCallback() { 
            new SyncUpdateCallback() {

            
                @Override
            
                public void onUpdate(SyncState sync) {
                
                    if (Status.DONE.equals(sync.getStatus())) {
                    
                        syncDown();
                
                    }
            
                }
        
            });
    
    } catch (JSONException e) {
           
        Log.e(TAG, "JSONException occurred while parsing", e);
    
    } catch (MobileSyncException e) {
           
        Log.e(TAG, "MobileSyncException occurred while attempting to sync up", e);
    
    }

 }

Quando a resposta assíncrona retorna Status.DONE, a implementação SyncUpdateCallback aqui dá o passo extra de chamar syncDown(). Essa etapa recomendada faz com que o soup do SmartStore permaneça atualizado em relação a quaisquer alterações mais recentes feitas aos contatos no servidor.

Como usar a Sincronização móvel em aplicativos híbridos

A Sincronização móvel oferece duas abordagens diferentes para aplicativos híbridos.

  • com.salesforce.plugin.mobilesync – esse plug-in Cordova oferece acesso JavaScript às funções nativas de “sincronização por download” e “sincronização por upload” da Sincronização móvel. Por conta disso, as operações de desempenho intensivo, por exemplo, negociações de rede, análise e gerenciamento de SmartStore, são executadas em threads nativos que não têm impacto nas operações de exibição web. Use o plug-in em cenários mais simples para sincronizar grandes quantidades de registros rapidamente em um thread nativo, em vez de na exibição web.
  • mobilesync.js – essa biblioteca JavaScript oferece uma estrutura de dados Force sObject para operações de sincronização mais complexas. A biblioteca se baseia em Backbone.js, uma estrutura JavaScript de código aberto que define um mecanismo de modelagem de dados abrangente. Ao usar mobilesync.js, você poderá criar modelos de objetos do Salesforce e manipular os registros subjacentes com a simples alteração dos dados do modelo. Se você realizar uma consulta SOQL ou SOSL, receberá os registros resultantes em um conjunto de modelos, em vez de uma sequência de caracteres JSON.

Você pode combinar essas abordagens no mesmo aplicativo para ter bons resultados. Por exemplo, o plug-in expõe dois métodos: syncDown() e syncUp(). Quando você usa esses métodos, as diretrizes a seguir podem facilitar a sua vida.

  • Para criar, atualizar ou excluir registros em soups do SmartStore, use Force.SObject de mobilesync.js. A biblioteca mobilesync.js cria campos especiais nos registros de soup esperados pelo plug-in automaticamente. Você pode, então, chamar syncUp() no plug-in para atualizar o servidor.
  • Da mesma forma, para criar o soup das operações de sincronização, use Force.StoreCache de mobilesync.js.
  • Se você mudou objetos no soup, chame sempre syncUp() antes de chamar syncDown().

Aplicativos híbridos criados com forcehybrid incluem automaticamente o plugin de Sincronização móvel.

Sincronização por download

Aqui está o método syncDown() do plugin da Sincronização móvel.

cordova.require("com.salesforce.plugin.mobilesync").syncDown
    ([storeConfig,] target, soupName, options, [syncName,] success, error);

Se você definiu um nome de sincronização para essa configuração, pode fornecê-lo. Você define nomes de sincronização em um arquivo de configuração usersyncs.json incluído no nível superior do seu aplicativo Web.

Para a opção de modo de mesclagem, os aplicativos híbridos usam estes identificadores.

  • {mergeMode:Force.MERGE_MODE_DOWNLOAD.OVERWRITE} (padrão)
  • {mergeMode:Force.MERGE_MODE_DOWNLOAD.LEAVE_IF_CHANGED}

O parâmetro success especifica uma função de retorno de chamada que é chamada várias vezes durante a operação de sincronização:

  • Quando a operação de sincronização é iniciada
  • Quando a solicitação REST interna foi concluída
  • Depois que cada página de resultados é baixada, até que todas tenham sido recebidas

Durante a execução da operação de sincronização, as atualizações de status chegam por meio de eventos do navegador. Para ouvir essas atualizações, use o seguinte ouvinte de eventos:

document.addEventListener("sync",
   function(event)
      {
         // event.detail contains the status of the sync operation
      }
 );

O membro event.detail fornece metadados de sincronização e, mais importante ainda, informações sobre o andamento e o status atual da operação:

  • syncId – a ID da operação de sincronização
  • type – syncDown
  • target – o destino fornecido
  • soupName – o nome do soup fornecido
  • options – matriz de opções especificada
  • status – o status de sincronização, que pode ser um dos seguintes:
    1. NEW (NOVO)
    2. RUNNING (EXECUTANDO)
    3. DONE (CONCLUÍDO)
    4. FAILED (FALHA)
  • progress – a porcentagem do total de registros processados até o momento (número inteiro entre 0 e 100)
  • totalSize – o número de registros processados até o momento

É uma boa ideia armazenar a ID de sincronização. Você pode usar esse valor mais tarde, para executar a operação de sincronização novamente.

Sincronização por upload

O método syncUp() do plug-in da Sincronização móvel replica registros criados, excluídos ou atualizados de um soup do SmartStore para o servidor do Salesforce.

cordova.require("com.salesforce.plugin.mobilesync").syncUp
   ([storeConfig,] [target,] soupName, options, [syncName,] successCb, errorCb);

Forneça as definições de configuração da operação, incluindo

  • target – se você definiu um destino de sincronização por upload nativo personalizado, use este parâmetro para identificar sua classe.
  • syncName — Se você definiu um nome de sincronização para essa configuração, pode fornecê-lo. Você define nomes de sincronização em um arquivo de configuração usersyncs.json incluído no nível superior do seu aplicativo Web.
  • Options – forneça um mapa com a seguinte chave:
    1. fieldlist – uma lista de campos enviados ao servidor
  • successCb, errorCb – funções de retorno de chamada de sucesso e erro.

As atualizações de status na operação de sincronização chegam pelo mesmo manipulador de eventos implementado para syncDown:

document.addEventListener("sync",
   function(event)
      {
         // event.detail contains the status of the sync operation
      }
 );

Assim como nas operações de sincronização por download, o membro event.detail fornece metadados de sincronização e indica o andamento e o status atual da operação.

Ressincronização

Como nos aplicativos nativos, o método reSync oferece flexibilidade e desempenho superiores e promove a facilidade de codificação. Se o nome de sincronização fornecido não tiver sido sincronizado anteriormente, reSync() faz uma sincronização completa. Caso contrário, ele executa uma sincronização incremental apenas de registros novos, alterados ou excluídos.

cordova.require("com.salesforce.plugin.mobilesync").reSync([storeConfig], syncIdOrName, successCB, errorCB)

Forneça as definições de configuração da operação, incluindo

  • syncIdOrName — O ID para essa operação de sincronização ou um nome de sincronização do arquivo usersyncs.json.
  • successCb, errorCb – funções de retorno de chamada de sucesso e erro.

Exemplo

Este exemplo usa as sincronizações nomeadas definidas no arquivo usersyncs.json a seguir. Você pode encontrar o código-fonte completo no repositório GitHub compartilhado pelo SalesforceMobileSDK.

{
  "syncs": [
    {
      "syncName": "syncDownContacts",
      "syncType": "syncDown",
      "soupName": "contacts",
      "target": {"type":"soql", 
      "query":"SELECT FirstName, LastName, Title, MobilePhone, 
               Email, Department, HomePhone FROM Contact LIMIT 10000"},
      "options": {"mergeMode":"OVERWRITE"}
    },
    {
      "syncName": "syncUpContacts",
      "syncType": "syncUp",
      "soupName": "contacts",
      "target": {
         "createFieldlist":["FirstName", "LastName", "Title", "MobilePhone", 
                            "Email", "Department", "HomePhone"]},
      "options": {
         "fieldlist":["Id", "FirstName", "LastName", "Title", 
                      "MobilePhone", "Email", "Department", "HomePhone"], 
         "mergeMode":"LEAVE_IF_CHANGED"}
    }
  ]
}

Nos exemplos a seguir, as duas operações de sincronização chamam reSync() no plug-in Cordova da Sincronização móvel transmitindo um nome de sincronização. Todas as operações usam a função handleSyncUpdate() nos retornos de chamada de sucesso. Observe que essa função chama syncDown() após a conclusão de uma execução de syncUp bem-sucedida. É sempre bom chamar syncDown() depois de syncUp() para fazer com que seus soups reflitam as últimas alterações no servidor. 

Em sua forma atual, o retorno de chamada de sucesso para syncDown() redefine a interface do usuário e seu conteúdo.

 handleSyncUpdate: function(sync) {
  // Called after sync operations succeed 
  if (sync.type === "syncDown") {
    // Reset UI buttons, then search (fetch) from SmartStore
    this.syncInFlight = false;
    $(".sync").disabled = false;
    this.search();
  }
  if (sync.type === "syncUp") {
      this.syncDown();
    }
  }
 },
 syncDown: function() {
   cordova.require("com.salesforce.plugin.mobilesync").
     reSync("syncDownContacts" /* see usersyncs.json */, 
     this.handleSyncUpdate.bind(this));
 },
 syncUp: function() {
   cordova.require("com.salesforce.plugin.mobilesync").
     reSync("syncUpContacts" /* see usersyncs.json */, 
     this.handleSyncUpdate.bind(this));
 }

Como usar a Sincronização móvel em aplicativos React Native

No React Native, a Sincronização móvel oferece suas funções por meio de um módulo mobilesync. Nos seus arquivos JavaScript, você pode importar esse módulo e suas dependências da biblioteca react-native-force da seguinte forma:

import {oauth, net, smartstore, mobilesync} from 'react-native-force';

Os aplicativos criados com forcereact incluem uma instrução import semelhante, mas sem smartstore ou mobilesync. Não deixe de adicionar esses módulos se estiver dando suporte a recursos offline do Mobile SDK.

Configuração de sincronização

Como você já deve esperar, é necessário fornecer os mesmos metadados de configuração dos aplicativos híbridos para aplicativos React Native. Aqui está um exemplo de declaração de destino.

 const fieldlist = ["Id", "FirstName", "LastName", 
    "Title", "Email", "MobilePhone","Department",
    "HomePhone", "LastModifiedDate"];
 const target = {type:"soql", query:
    `SELECT ${fieldlist.join(",")} FROM Contact LIMIT 10000`};

Para o modo de mesclagem em options, use um dos seguintes valores:

  • Para substituir registros que foram modificados:
    {mergeMode:mobilesync.MERGE_MODE.OVERWRITE}
    Se você não definir a chave mergeMode, a Sincronização móvel usará esse modo como padrão.
  • Para preservar registros que foram modificados em vez de substituí-los:
    {mergeMode:mobilesync.MERGE_MODE.LEAVE_IF_CHANGED}

Sincronização por download

A função syncDown() para React Native é idêntica à função híbrida, com a diferença de que é chamada no módulo mobilesync. Ela baixa registros do Salesforce especificados para um soup do SmartStore.

mobilesync.syncDown
    ([storeConfig,] target, soupName, options, [syncName,] success, error);

Se os registros existentes no soup tiverem a mesma ID dos registros retornados pela consulta, a Sincronização móvel substituirá os registros duplicados do soup por padrão. Para controlar como os dados baixados são mesclados com registros editados no soup, especifique um modo de mesclagem no parâmetro options.

O parâmetro success especifica uma função de retorno de chamada que o gerente de sincronização interna chama quando a operação de sincronização é concluída com sucesso. Diferentemente da implementação híbrida, a biblioteca React Native chama essa função apenas uma vez, quando a operação é concluída.

O Mobile SDK transmite um único argumento para o retorno de chamada de sucesso. Esse argumento retorna os metadados de sincronização abaixo, que incluem a ID de sincronização:

  • syncId – a ID da operação de sincronização
  • type – syncDown
  • target – o destino fornecido
  • options – (opcional) uma matriz especificando um ou ambos os elementos: modo de mesclagem, lista de campos
  • soupName – o nome do soup fornecido
  • syncName – o nome de sincronização fornecido, se for o caso

Mesmo que você não tenha outras ações para um retorno de chamada de sucesso, é bom implementá-lo para armazenar a ID de sincronização. Você pode usar esse valor mais tarde, se necessário, em uma operação de ressincronização. Veja um exemplo de sincronização por download.

const syncDown = forceUtil.promiserNoRejection(mobilesync.syncDown);
...
const fieldlist = ["Id", "FirstName", "LastName", 
    "Title", "Email", "MobilePhone","Department",
    "HomePhone", "LastModifiedDate"];
const target = {type:"soql", 
    query:`SELECT ${fieldlist.join(",")} 
           FROM Contact 
           LIMIT 10000`};
syncDown(false,
    target,
    "contacts",
    {mergeMode:mobilesync.MERGE_MODE.OVERWRITE},
    syncName,
    (sync) => {/* Do something meaningful or omit this member */},
    (error) => {/* Do something meaningful or omit this member */}
 );

Sincronização por upload

A função syncUp() do plug-in da Sincronização móvel copia registros criados, atualizados ou excluídos de um soup do SmartStore para o servidor do Salesforce.

mobilesync.syncUp
   ([storeConfig,] target, soupName, options, [syncName,] successCb, errorCb);

Assim como nas sincronizações por download, o argumento de entrada da função de retorno de chamada de sucesso fornece metadados de sincronização, incluindo a ID de sincronização.

Aqui está um exemplo de sincronização por upload.

const syncUp = forceUtil.promiserNoRejection(mobilesync.syncUp);
...
const fieldlist = ["FirstName", "LastName", "Title", "Email", 
  "MobilePhone","Department"];
syncUp(false,
  {},
  "contacts",
  {mergeMode:mobilesync.MERGE_MODE.OVERWRITE, fieldlist},
  (sync) => {/* Do something meaningful or omit this callback */},
  (error) => {/* Do something meaningful or omit this callback */}
);

Ressincronização

Como nos aplicativos nativos, o método reSync() oferece flexibilidade e desempenho superiores e promove a facilidade de codificação. Se o nome de sincronização fornecido não tiver sido sincronizado anteriormente, reSync() faz uma sincronização completa. Caso contrário, ele executa uma sincronização incremental apenas de registros criados, atualizados ou excluídos.

mobilesync.reSync
   ([storeConfig,] syncIdOrName, successCB, errorCB); 

Forneça as definições de configuração da operação, incluindo

  • syncIdOrName — O ID para essa operação de sincronização ou um nome de sincronização do arquivo usersyncs.json.
  • successCb, errorCb – funções de retorno de chamada de sucesso e erro.

Recursos

Continue a aprender de graça!
Inscreva-se em uma conta para continuar.
O que você ganha com isso?
  • Receba recomendações personalizadas para suas metas de carreira
  • Pratique suas habilidades com desafios práticos e testes
  • Monitore e compartilhe seu progresso com os empregadores
  • Conecte-se a orientação e oportunidades de carreira