Delen via


Offline synchroniseren met mobiele iOS-apps inschakelen

Overzicht

In deze zelfstudie wordt het offline synchroniseren behandeld met de functie Mobile Apps van Azure App Service voor iOS. Wanneer eindgebruikers offline synchroniseren, kunnen ze communiceren met een mobiele app om gegevens weer te geven, toe te voegen of te wijzigen, zelfs wanneer ze geen netwerkverbinding hebben. Wijzigingen worden opgeslagen in een lokale database. Nadat het apparaat weer online is, worden de wijzigingen gesynchroniseerd met de externe back-end.

Als dit uw eerste ervaring is met Mobile Apps, moet u eerst de zelfstudie Een iOS-app maken voltooien. Als u het gedownloade snelstartserverproject niet gebruikt, moet u de uitbreidingspakketten voor gegevenstoegang toevoegen aan uw project. Zie Werken met de SDK van de .NET-back-endserver voor Azure Mobile Appsvoor meer informatie over serveruitbreidingspakketten.

Zie Offline Data Sync in Mobile Apps voor meer informatie over de functie voor offlinesynchronisatie.

De clientsynchronisatiecode controleren

Het clientproject dat u hebt gedownload voor de zelfstudie Een iOS-app maken bevat al code die offlinesynchronisatie ondersteunt met behulp van een lokale Core Data-database. In deze sectie wordt samengevat wat al is opgenomen in de zelfstudiecode. Zie Offline data sync in Mobile Apps voor een conceptueel overzicht van de functie.

Met behulp van de offlinefunctie voor gegevenssynchronisatie van Mobiele apps kunnen eindgebruikers communiceren met een lokale database, zelfs als het netwerk niet toegankelijk is. Als u deze functies in uw app wilt gebruiken, initialiseert u de synchronisatiecontext van MSClient en verwijst u naar een lokale opslag. Vervolgens verwijst u naar uw tabel via de MSSyncTable-interface .

In QSTodoService.m (Objective-C) of ToDoTableViewController.swift (Swift) merkt u op dat het type van het lid syncTableMSSyncTable is. Offlinesynchronisatie maakt gebruik van deze interface voor synchronisatietabellen in plaats van MSTable. Wanneer een synchronisatietabel wordt gebruikt, gaan alle bewerkingen naar de lokale opslag en worden ze alleen met expliciete push- en pull-bewerkingen gesynchroniseerd met de externe back-end.

Als u een verwijzing naar een synchronisatietabel wilt ophalen, gebruikt u de methode syncTableWithName op MSClient. Als u de offlinesynchronisatiefunctionaliteit wilt verwijderen, gebruikt u in plaats daarvan tableWithName .

Voordat tabelbewerkingen kunnen worden uitgevoerd, moet de lokale opslag worden geïnitialiseerd. Dit is de relevante code:

  • Objective-C. In de methode QSTodoService.init :

    MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
    self.client.syncContext = [[MSSyncContext alloc] initWithDelegate:nil dataSource:store callback:nil];
    
  • Swift. In de methode 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)
    

    Met deze methode maakt u een lokale store met behulp van de MSCoreDataStore interface, die de Mobile Apps SDK biedt. U kunt ook een andere lokale winkel aangeven door het MSSyncContextDataSource protocol te implementeren. Ook wordt de eerste parameter van MSSyncContext gebruikt om een conflicthandler op te geven. Omdat we nil hebben doorlopen, ontvangen we de standaard conflicthandler, die faalt bij elk conflict.

Nu gaan we de werkelijke synchronisatiebewerking uitvoeren en gegevens ophalen uit de externe back-end:

  • Objective-C. syncData pusht eerst nieuwe wijzigingen en roept vervolgens pullData aan om gegevens op te halen uit de externe back-end. Op zijn beurt haalt de pullData-methode nieuwe gegevens op die overeenkomen met een query:

    -(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);
             }
         }];
    }
    
  • Swift:

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

In de Objective-C versie, in syncData, roepen we eerst pushWithCompletion aan in de synchronisatiecontext. Deze methode is een functie van MSSyncContext (en niet van de synchronisatietabel zelf), omdat deze veranderingen doorvoert in alle tabellen. Alleen records die lokaal zijn gewijzigd (via CUD-bewerkingen) worden naar de server verzonden. Vervolgens wordt de helper pullData aangeroepen, die MSSyncTable.pullWithQuery aanroept om externe gegevens op te halen en op te slaan in de lokale database.

In de Swift-versie, omdat de pushbewerking niet strikt noodzakelijk was, is er geen aanroep naar pushWithCompletion. Als er wijzigingen in behandeling zijn in de synchronisatiecontext voor de tabel die een pushbewerking uitvoert, geeft pull altijd eerst een push uit. Als u echter meer dan één synchronisatietabel hebt, kunt u het beste push expliciet aanroepen om ervoor te zorgen dat alles consistent is in gerelateerde tabellen.

In zowel de versies Objective-C als Swift kunt u de pullWithQuery-methode gebruiken om een query op te geven voor het filteren van de records die u wilt ophalen. In dit voorbeeld haalt de query alle records in de externe TodoItem tabel op.

De tweede parameter van pullWithQuery is een query-id die wordt gebruikt voor incrementele synchronisatie. Incrementele synchronisatie haalt alleen records op die zijn gewijzigd sinds de laatste synchronisatie, met behulp van het tijdstempel van de record UpdatedAt (aangeroepen updatedAt in het lokale archief.) De query-id moet een beschrijvende tekenreeks zijn die uniek is voor elke logische query in uw app. Als u zich wilt afmelden voor incrementele synchronisatie, geeft u nil deze door als de query-id. Deze benadering kan mogelijk inefficiënt zijn, omdat hiermee alle records voor elke pull-bewerking worden opgehaald.

De Objective-C-app wordt gesynchroniseerd wanneer u gegevens wijzigt of toevoegt, wanneer een gebruiker de vernieuwingsbeweging uitvoert en bij het starten.

De Swift-app wordt gesynchroniseerd wanneer de gebruiker de vernieuwingsbeweging uitvoert en bij het starten.

Omdat de app wordt gesynchroniseerd wanneer gegevens worden gewijzigd (Objective-C) of wanneer de app wordt gestart (Objective-C en Swift), wordt ervan uitgegaan dat de gebruiker online is. In een latere sectie werkt u de app bij, zodat gebruikers deze zelfs kunnen bewerken wanneer ze offline zijn.

Het kerngegevensmodel controleren

Wanneer u het offlinearchief Core Data gebruikt, moet u bepaalde tabellen en velden in uw gegevensmodel definiëren. De voorbeeld-app bevat al een gegevensmodel met de juiste indeling. In deze sectie doorlopen we deze tabellen om te laten zien hoe ze worden gebruikt.

Open QSDataModel.xcdatamodeld. Vier tabellen zijn gedefinieerd: drie tabellen die worden gebruikt door de SDK en één die wordt gebruikt voor de to-do items zelf:

  • MS_TableOperations: houdt de items bij die moeten worden gesynchroniseerd met de server.
  • MS_TableOperationErrors: houdt eventuele fouten bij die optreden tijdens offlinesynchronisatie.
  • MS_TableConfig: houdt de laatst bijgewerkte tijd bij voor de laatste synchronisatiebewerking voor alle pull-bewerkingen.
  • TodoItem: slaat to-do-items op. De systeemkolommen createdAt, updatedAt en versie zijn optionele systeemeigenschappen.

Notitie

De Mobile Apps SDK reserveert kolomnamen die beginnen met '``'. Gebruik dit voorvoegsel niet met iets anders dan systeemkolommen. Anders worden de kolomnamen gewijzigd wanneer u de externe back-end gebruikt.

Wanneer u de offlinesynchronisatiefunctie gebruikt, definieert u de drie systeemtabellen en de gegevenstabel.

Systeemtabellen

MS_TableOperations

MS_TableOperations tabelkenmerken

Kenmerk Typ
identiteitskaart Geheel getal 64
artikelID Touwtje
eigenschappen Binaire gegevens
tafel Touwtje
tableKind Geheel getal 16

MS_TableOperationErrors

MS_TableOperationErrors tabelkenmerken

Kenmerk Typ
identiteitskaart Touwtje
operationId Integer 64
eigenschappen Binaire gegevens
tableKind Integer 16

MS_TableConfig

Kenmerk Typ
identiteitskaart Touwtje
sleutel Touwtje
sleuteltype Integer 64
tafel Touwtje
waarde Touwtje

Gegevenstabel

TodoItem

Kenmerk Typ Notitie
identiteitskaart Tekenreeks, gemarkeerd als vereist Primaire sleutel in externe opslag
compleet Booleaan Takenitemveld
Tekst Touwtje Takenitemveld
createdAt Datum (optioneel) Wordt toegewezen aan de systeemeigenschap CreatedAt
BijgewerktOp Datum (optioneel) Komt overeen met de updatedAt-systeemeigenschap
Versie Touwtje (optioneel) Wordt gebruikt om conflicten te detecteren, koppelt aan versie

Het synchronisatiegedrag van de app wijzigen

In deze sectie wijzigt u de app zodat deze niet wordt gesynchroniseerd bij het starten van de app of wanneer u items invoegt en bijwerkt. Synchronisatie vindt alleen plaats wanneer de vernieuwingstegelknop wordt gebruikt.

Objective-C:

  1. Wijzig in QSTodoListViewController.m de methode viewDidLoad om de aanroep aan het einde van de methode [self refresh] te verwijderen. De gegevens worden nu niet gesynchroniseerd met de server bij het starten van de app. In plaats daarvan wordt deze gesynchroniseerd met de inhoud van de lokale winkel.

  2. Wijzig in QSTodoService.m de definitie addItem zodat deze niet wordt gesynchroniseerd nadat het item is ingevoegd. Verwijder het self syncData blok en vervang het door het volgende:

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. Wijzig de definitie van completeItem zoals eerder vermeld. Verwijder het blok self syncData en vervang het door het volgende:

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

Swift:

In viewDidLoad, in ToDoTableViewController.swift, commentarieert u de twee regels die hier worden weergegeven om te stoppen met synchroniseren bij het opstarten van de app. Op het moment van schrijven werkt de Swift Todo-app de service niet bij wanneer iemand een item toevoegt of voltooit. De service wordt alleen bijgewerkt bij het starten van de app.

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

De app testen

In deze sectie maakt u verbinding met een ongeldige URL om een offlinescenario te simuleren. Wanneer u gegevensitems toevoegt, worden ze bewaard in het lokale Core Data Store, maar worden ze niet gesynchroniseerd met de back-end van de mobiele app.

  1. Wijzig de URL van de mobiele app in QSTodoService.m in een ongeldige URL en voer de app opnieuw uit:

    Objective-C. In QSTodoService.m:

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

    Swift. In ToDoTableViewController.swift:

    let client = MSClient(applicationURLString: "https://sitename.azurewebsites.net.fail")
    
  2. Voeg enkele to-do items toe. Sluit de simulator (of sluit de app geforceerd af) en start deze opnieuw op. Controleer of uw wijzigingen behouden blijven.

  3. De inhoud van de externe todoItem-tabel weergeven:

    • Voor een Node.js back-end gaat u naar Azure Portal en klikt u in de back-end van uw mobiele app op Easy Tables>TodoItem.
    • Gebruik voor een .NET-back-end een SQL-hulpprogramma, zoals SQL Server Management Studio of een REST-client, zoals Fiddler of Postman.
  4. Controleer of de nieuwe items niet zijn gesynchroniseerd met de server.

  5. Wijzig de URL weer in de juiste url in QSTodoService.m en voer de app opnieuw uit.

  6. Voer de vernieuwingsbeweging uit door de lijst met items omlaag te trekken.
    Er wordt een voortgangsspinner weergegeven.

  7. Bekijk de todoItem-gegevens opnieuw. De nieuwe en gewijzigde to-do items moeten nu worden weergegeven.

Samenvatting

Ter ondersteuning van de offlinesynchronisatiefunctie hebben we de MSSyncTable interface gebruikt en MSClient.syncContext geïnitialiseerd met een lokaal archief. In dit geval was de lokale database een op Core Data gebaseerde database.

Wanneer u een lokaal kerngegevensarchief gebruikt, moet u verschillende tabellen met de juiste systeemeigenschappen definiëren.

De normale CRUD-bewerkingen (Create, Read, Update en Delete) voor mobiele apps werken alsof de app nog steeds is verbonden, maar alle bewerkingen worden uitgevoerd op basis van de lokale store.

Toen we het lokale archief met de server hebben gesynchroniseerd, hebben we de methode MSSyncTable.pullWithQuery gebruikt.

Aanvullende bronnen