Offline synchroniseren met mobiele iOS-apps inschakelen

Overzicht

In deze zelfstudie wordt offlinesynchronisatie 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 quickstartserverproject niet gebruikt, moet u de uitbreidingspakketten voor gegevenstoegang toevoegen aan uw project. Zie Work with the .NET backend server server SDK for Azure Mobile Apps (Werken met de .NET-back-endserver-SDK voor Azure Mobile Apps) voor meer informatie over serverextensiepakketten.

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

De synchronisatiecode van de client controleren

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

Met de functie voor offlinegegevenssynchronisatie van Mobile Apps kunnen eindgebruikers communiceren met een lokale database, zelfs wanneer het netwerk niet toegankelijk is. Als u deze functies in uw app wilt gebruiken, initialiseert u de synchronisatiecontext van MSClient een lokaal archief en verwijst u ernaar. Vervolgens verwijst u naar de tabel via de MSSyncTable-interface .

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

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

Voordat tabelbewerkingen kunnen worden uitgevoerd, moet het lokale archief 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 lokaal archief met behulp van de MSCoreDataStore interface, die de Mobile Apps SDK biedt. U kunt ook een ander lokaal archief opgeven door het MSSyncContextDataSource protocol te implementeren. Ook wordt de eerste parameter van MSSyncContext gebruikt om een conflicthandler op te geven. Omdat we zijn geslaagd nil, krijgen we de standaard conflicthandler, die mislukt bij een 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 roepen syncDatawe eerst pushWithCompletion aan in de synchronisatiecontext. Deze methode is lid van MSSyncContext (en niet de synchronisatietabel zelf), omdat wijzigingen in alle tabellen worden gepusht. 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 voor 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, is het raadzaam om push expliciet aan te roepen om ervoor te zorgen dat alles consistent is in gerelateerde tabellen.

In de versies Objective-C en Swift kunt u de methode pullWithQuery gebruiken om een query op te geven om de records te filteren 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 nil u deze door als de query-id. Deze benadering kan mogelijk inefficiënt zijn, omdat alle records voor elke pull-bewerking worden opgehaald.

De Objective-C-app wordt gesynchroniseerd wanneer u gegevens wijzigt of toevoegt, wanneer een gebruiker het 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 gaat u de app bijwerken, zodat gebruikers zelfs wanneer ze offline zijn, kunnen bewerken.

Het basisgegevensmodel 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 een die wordt gebruikt voor de takenitems 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.
  • Taakitem: slaat de taakitems 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 functie offlinesynchronisatie gebruikt, definieert u de drie systeemtabellen en de gegevenstabel.

Systeemtabellen

MS_TableOperations

MS_TableOperations tabelkenmerken

Kenmerk Type
id Geheel getal 64
itemId Tekenreeks
properties Binaire gegevens
tabel Tekenreeks
tableKind Geheel getal 16

MS_TableOperationErrors

MS_TableOperationErrors tabelkenmerken

Kenmerk Type
id Tekenreeks
operationId Geheel getal 64
properties Binaire gegevens
tableKind Geheel getal 16

MS_TableConfig

Kenmerk Type
id Tekenreeks
sleutel Tekenreeks
Keytype Geheel getal 64
tabel Tekenreeks
waarde Tekenreeks

Gegevenstabel

Taakitem

Kenmerk Type Notitie
id Tekenreeks, gemarkeerd als vereist Primaire sleutel in externe opslag
voltooid Booleaans Takenitemveld
tekst Tekenreeks Takenitemveld
createdAt Date (optioneel) Wordt toegewezen aan de systeemeigenschap CreatedAt
updatedAt Date (optioneel) Wordt toegewezen aan bijgewerkte SysteemeigenschapAt
versie Tekenreeks (optioneel) Wordt gebruikt om conflicten te detecteren, wordt toegewezen 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. Deze wordt alleen gesynchroniseerd wanneer de knop Voor vernieuwen wordt uitgevoerd.

Objective-C:

  1. Wijzig in QSTodoListViewController.m de viewDidLoad-methode om de aanroep aan het einde van de methode te [self refresh] 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 het lokale archief.

  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 en self syncData vervang het door het volgende:

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

Swift:

In viewDidLoadToDoTableViewController.swift markeert u de twee regels die hier worden weergegeven om te stoppen met synchroniseren bij het starten 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-archief, 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 takenitems toe. Sluit de simulator af (of sluit de app geforceerd) en start deze opnieuw. Controleer of uw wijzigingen behouden blijven.

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

    • Voor een Node.js back-end gaat u naar de 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 terug 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 voortgangs spinner weergegeven.

  7. Bekijk de TodoItem-gegevens opnieuw. De nieuwe en gewijzigde takenitems moeten nu worden weergegeven.

Samenvatting

Ter ondersteuning van de functie voor offlinesynchronisatie hebben we de MSSyncTable interface gebruikt en geïnitialiseerd MSClient.syncContext met een lokaal archief. In dit geval was het lokale archief een database op basis van kerngegevens.

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 in de lokale store.

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

Aanvullende resources