Aktivera offlinesynkronisering med iOS-mobilappar

Översikt

Den här självstudien beskriver offlinesynkronisering med mobile apps-funktionen i Azure App Service för iOS. Med offlinesynkronisering kan slutanvändarna interagera med en mobilapp för att visa, lägga till eller ändra data, även om de inte har någon nätverksanslutning. Ändringar lagras i en lokal databas. När enheten är online igen synkroniseras ändringarna med fjärrserverdelen.

Om det här är din första upplevelse med Mobile Apps bör du först slutföra självstudien Skapa en iOS-app. Om du inte använder det nedladdade snabbstartsserverprojektet måste du lägga till paketen för dataåtkomsttillägg i projektet. Mer information om servertilläggspaket finns i Arbeta med .NET-serverdels-SDK för Azure Mobile Apps.

Mer information om funktionen för offlinesynkronisering finns i Synkronisering av offlinedata i Mobilappar.

Granska klientsynkroniseringskoden

Klientprojektet som du laddade ned för självstudien Skapa en iOS-app innehåller redan kod som stöder offlinesynkronisering med hjälp av en lokal Core Data-baserad databas. Det här avsnittet sammanfattar vad som redan ingår i självstudiekoden. En konceptuell översikt över funktionen finns i Offline datasynkronisering i Mobilappar.

Med hjälp av funktionen för datasynkronisering offline i Mobile Apps kan slutanvändarna interagera med en lokal databas även om nätverket inte är tillgängligt. Om du vill använda dessa funktioner i din app initierar du synkroniseringskontexten MSClient för och refererar till ett lokalt arkiv. Sedan refererar du till tabellen via MSSyncTable-gränssnittet .

Observera att typen av medlemssynkroniseringstabell är MSSyncTable i QSTodoService.m (Objective-C) eller ToDoTableViewController.swift (Swift). Offlinesynkronisering använder det här synkroniseringstabellgränssnittet i stället för MSTable. När en synkroniseringstabell används går alla åtgärder till det lokala arkivet och synkroniseras endast med fjärrserverdelen med explicita push- och pull-åtgärder.

Om du vill hämta en referens till en synkroniseringstabell använder du metoden syncTableWithNameMSClient. Om du vill ta bort funktionen för offlinesynkronisering använder du tableWithName i stället.

Innan några tabellåtgärder kan utföras måste det lokala arkivet initieras. Här är relevant kod:

  • Objective-C. I metoden QSTodoService.init :

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

    Den här metoden skapar ett lokalt arkiv med hjälp MSCoreDataStore av gränssnittet, som tillhandahålls av Mobile Apps SDK. Du kan också ange ett annat lokalt arkiv genom att implementera protokollet MSSyncContextDataSource . Dessutom används den första parametern för MSSyncContext för att ange en konflikthanterare. Eftersom vi har passerat nilfår vi standardkonflikthanteraren, som misslyckas vid eventuella konflikter.

Nu ska vi utföra den faktiska synkroniseringsåtgärden och hämta data från fjärrserverdelen:

  • Objective-C. syncData skickar först nya ändringar och anropar sedan pullData för att hämta data från fjärrserverdelen. Metoden pullData hämtar i sin tur nya data som matchar en fråga:

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

I Objective-C-versionen i syncDataanropar vi först pushWithCompletion i synkroniseringskontexten. Den här metoden är medlem i MSSyncContext (och inte själva synkroniseringstabellen) eftersom den skickar ändringar över alla tabeller. Endast poster som har ändrats lokalt (via CUD-åtgärder) skickas till servern. Sedan anropas hjälpverktyget pullData , som anropar MSSyncTable.pullWithQuery för att hämta fjärrdata och lagra dem i den lokala databasen.

Eftersom push-åtgärden inte var absolut nödvändig i Swift-versionen finns det inget anrop till pushWithCompletion. Om det finns ändringar som väntar i synkroniseringskontexten för tabellen som utför en push-åtgärd utfärdar pull alltid en push-överföring först. Men om du har fler än en synkroniseringstabell är det bäst att uttryckligen anropa push för att säkerställa att allt är konsekvent mellan relaterade tabeller.

I både Objective-C- och Swift-versionerna kan du använda metoden pullWithQuery för att ange en fråga för att filtrera de poster som du vill hämta. I det här exemplet hämtar frågan alla poster i fjärrtabellen TodoItem .

Den andra parametern för pullWithQuery är ett fråge-ID som används för inkrementell synkronisering. Inkrementell synkronisering hämtar endast poster som har ändrats sedan den senaste synkroniseringen med postens tidsstämpel (anropas UpdatedAtupdatedAt i det lokala arkivet.) Fråge-ID:t ska vara en beskrivande sträng som är unik för varje logisk fråga i din app. Om du vill välja bort inkrementell synkronisering skickar nil du som fråge-ID. Den här metoden kan vara potentiellt ineffektiv eftersom den hämtar alla poster för varje pull-åtgärd.

Objective-C-appen synkroniseras när du ändrar eller lägger till data, när en användare utför uppdateringsgesten och vid start.

Swift-appen synkroniseras när användaren utför uppdateringsgesten och vid start.

Eftersom appen synkroniseras när data ändras (Objective-C) eller när appen startar (Objective-C och Swift) förutsätter appen att användaren är online. I ett senare avsnitt uppdaterar du appen så att användarna kan redigera även när de är offline.

Granska Core Data-modellen

När du använder Core Data Offline Store måste du definiera specifika tabeller och fält i datamodellen. Exempelappen innehåller redan en datamodell med rätt format. I det här avsnittet går vi igenom de här tabellerna för att visa hur de används.

Öppna QSDataModel.xcdatamodeld. Fyra tabeller definieras – tre som används av SDK:t och en som används för att göra-objekten själva:

  • MS_TableOperations: Spårar de objekt som måste synkroniseras med servern.
  • MS_TableOperationErrors: Spårar eventuella fel som inträffar under offlinesynkronisering.
  • MS_TableConfig: Spårar den senast uppdaterade tiden för den senaste synkroniseringsåtgärden för alla pull-åtgärder.
  • TodoItem: Lagrar att göra-objekten. Systemkolumnerna createdAt, updatedAt och version är valfria systemegenskaper.

Anteckning

Mobile Apps SDK reserverar kolumnnamn som börjar med "``". Använd inte det här prefixet med något annat än systemkolumner. Annars ändras kolumnnamnen när du använder fjärrbacksdelen.

När du använder funktionen för offlinesynkronisering definierar du de tre systemtabellerna och datatabellen.

Systemtabeller

MS_TableOperations

MS_TableOperations tabellattribut

Attribut Typ
id Heltal 64
Itemid Sträng
properties Binära data
tabell Sträng
tableKind Heltal 16

MS_TableOperationErrors

MS_TableOperationErrors tabellattribut

Attribut Typ
id Sträng
operationId Heltal 64
properties Binära data
tableKind Heltal 16

MS_TableConfig

Attribut Typ
id Sträng
key Sträng
Keytype Heltal 64
tabell Sträng
värde Sträng

Datatabell

TodoItem

Attribut Typ Anteckning
id Sträng, markerad som obligatorisk Primärnyckel i fjärrarkiv
slutföra Boolesk Att göra-objektfält
text Sträng Att göra-objektfält
createdAt Date (valfritt) Kartor till createdAt system-egenskapen
updatedAt Date (valfritt) Kartor till updatedAt systemegenskap
version Sträng (valfritt) Används för att identifiera konflikter, mappar till version

Ändra synkroniseringsbeteendet för appen

I det här avsnittet ändrar du appen så att den inte synkroniseras vid appstart eller när du infogar och uppdaterar objekt. Den synkroniseras bara när knappen uppdatera gest utförs.

Objective-C:

  1. I QSTodoListViewController.m ändrar du metoden viewDidLoad för att ta bort anropet till [self refresh] i slutet av metoden. Nu synkroniseras inte data med servern vid start av appen. I stället synkroniseras den med innehållet i det lokala arkivet.

  2. I QSTodoService.m ändrar du definitionen för addItem så att den inte synkroniseras när objektet har infogats. self syncData Ta bort blocket och ersätt det med följande:

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. Ändra definitionen av completeItem som nämnts tidigare. Ta bort blocket för self syncData och ersätt det med följande:

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

Swift:

I viewDidLoad, i ToDoTableViewController.swift, kommenterar du ut de två raderna som visas här för att stoppa synkroniseringen vid appstart. När detta skrivs uppdaterar inte Swift Todo-appen tjänsten när någon lägger till eller slutför ett objekt. Tjänsten uppdateras endast vid start av appen.

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

Testa appen

I det här avsnittet ansluter du till en ogiltig URL för att simulera ett offlinescenario. När du lägger till dataobjekt lagras de i det lokala Core Data Store, men de synkroniseras inte med mobilappens serverdel.

  1. Ändra mobilappens URL i QSTodoService.m till en ogiltig URL och kör appen igen:

    Objective-C. I QSTodoService.m:

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

    Swift. I ToDoTableViewController.swift:

    let client = MSClient(applicationURLString: "https://sitename.azurewebsites.net.fail")
    
  2. Lägg till några att göra-objekt. Avsluta simulatorn (eller stäng appen med två två skäl) och starta sedan om den. Kontrollera att ändringarna bevaras.

  3. Visa innehållet i den fjärranslutna TodoItem-tabellen :

    • För en Node.js serverdel går du till Azure Portal och i mobilappens serverdel klickar du på Enkla tabeller>TodoItem.
    • För en .NET-serverdel använder du antingen ett SQL-verktyg, till exempel SQL Server Management Studio eller en REST-klient, till exempel Fiddler eller Postman.
  4. Kontrollera att de nya objekten inte har synkroniserats med servern.

  5. Ändra url:en tillbaka till rätt i QSTodoService.m och kör appen igen.

  6. Utför uppdateringsgesten genom att hämta listan med objekt.
    En förloppssnurrare visas.

  7. Visa TodoItem-data igen. De nya och ändrade att göra-objekten ska nu visas.

Sammanfattning

För att stödja offlinesynkroniseringsfunktionen MSSyncTable använde vi gränssnittet och initierades MSClient.syncContext med ett lokalt arkiv. I det här fallet var det lokala arkivet en Core Data-baserad databas.

När du använder ett lokalt Core Data-arkiv måste du definiera flera tabeller med rätt systemegenskaper.

Crud-åtgärderna (normal create, read, update och delete) för mobilappar fungerar som om appen fortfarande är ansluten, men alla åtgärder utförs mot det lokala arkivet.

När vi synkroniserade det lokala arkivet med servern använde vi metoden MSSyncTable.pullWithQuery .

Ytterligare resurser