Freigeben über


Aktivieren der Offlinesynchronisierung mit mobilen iOS-Apps

Überblick

In diesem Lernprogramm wird die Offlinesynchronisierung mit dem Feature "Mobile Apps" von Azure App Service für iOS behandelt. Mit der Offlinesynchronisierung können Endbenutzer mit einer mobilen App interagieren, um Daten anzuzeigen, hinzuzufügen oder zu ändern, auch wenn sie keine Netzwerkverbindung haben. Änderungen werden in einer lokalen Datenbank gespeichert. Nachdem das Gerät wieder online ist, werden die Änderungen mit dem Remote-Back-End synchronisiert.

Wenn dies Ihre erste Erfahrung mit mobilen Apps ist, sollten Sie zuerst das Lernprogramm "Erstellen einer iOS-App" abschließen. Wenn Sie das heruntergeladene Schnellstartserverprojekt nicht verwenden, müssen Sie dem Projekt die Erweiterungspakete für den Datenzugriff hinzufügen. Weitere Informationen zu Servererweiterungspaketen finden Sie unter Arbeiten mit dem .NET-Back-End-Server-SDK für Azure Mobile Apps.

Weitere Informationen zum Offlinesynchronisierungsfeature finden Sie unter Offlinedatensynchronisierung in mobilen Apps.

Überprüfen des Clientsynchronisierungscodes

Das Clientprojekt, das Sie für das Lernprogramm zum Erstellen einer iOS-App heruntergeladen haben, enthält bereits Code, der die Offlinesynchronisierung mithilfe einer lokalen Core Data-basierten Datenbank unterstützt. In diesem Abschnitt wird zusammengefasst, was bereits im Lernprogrammcode enthalten ist. Eine konzeptionelle Übersicht über das Feature finden Sie unter Offlinedatensynchronisierung in mobilen Apps.

Mithilfe der Offlinedatensynchronisierungsfunktion mobiler Apps können Endbenutzer auch dann mit einer lokalen Datenbank interagieren, wenn auf das Netzwerk nicht zugegriffen werden kann. Um diese Features in Ihrer App zu verwenden, initialisieren Sie den Synchronisierungskontext von MSClient und verweisen Sie auf einen lokalen Store. Anschließend verweisen Sie auf die Tabelle über die MSSyncTable-Schnittstelle .

Beachten Sie in QSTodoService.m (Objective-C) oder ToDoTableViewController.swift (Swift), dass der Typ der Member syncTableMSSyncTable ist. Die Offlinesynchronisierung verwendet diese Synchronisierungstabellenschnittstelle anstelle von MSTable. Wenn eine Synchronisierungstabelle verwendet wird, wechseln alle Vorgänge zum lokalen Speicher und werden nur mit dem Remote-Back-End mit expliziten Push- und Pullvorgängen synchronisiert.

Verwenden Sie zum Abrufen eines Verweises auf eine Synchronisierungstabelle die syncTableWithName-Methode für MSClient. Verwenden Sie " tableWithName " stattdessen, um die Offlinesynchronisierungsfunktion zu entfernen.

Bevor Tabellenvorgänge ausgeführt werden können, muss der lokale Speicher initialisiert werden. Hier ist der relevante Code:

  • Objective-C. In der QSTodoService.init-Methode :

    MSCoreDataStore *store = [[MSCoreDataStore alloc] initWithManagedObjectContext:context];
    self.client.syncContext = [[MSSyncContext alloc] initWithDelegate:nil dataSource:store callback:nil];
    
  • Swift. In der ToDoTableViewController.viewDidLoad-Methode :

    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)
    

    Diese Methode erstellt einen lokalen Speicher mithilfe der MSCoreDataStore Schnittstelle, die das Mobile Apps SDK bereitstellt. Alternativ können Sie einen anderen lokalen Speicher bereitstellen, indem Sie das MSSyncContextDataSource Protokoll implementieren. Außerdem wird der erste Parameter von MSSyncContext verwendet, um einen Konflikthandler anzugeben. Da wir nil übergeben haben, wird der Standardkonflikthandler abgerufen, der bei jedem Konflikt fehlschlägt.

Nun führen wir den tatsächlichen Synchronisierungsvorgang aus und rufen Daten aus dem Remote-Back-End ab:

  • Objective-C. syncData pusht zuerst neue Änderungen und ruft dann pullData auf, um Daten vom Remote-Back-End abzurufen. Die pullData-Methode ruft wiederum neue Daten ab, die einer Abfrage entsprechen:

    -(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 der Objective-C-Version syncDatarufen wir zuerst pushWithCompletion im Synchronisierungskontext auf. Diese Methode ist ein Element von MSSyncContext (und nicht der Synchronisierungstabelle selbst), da sie Änderungen über alle Tabellen hinweg verschiebt. Nur Datensätze, die lokal (über CUD-Vorgänge) geändert wurden, werden an den Server gesendet. Anschließend wird das Hilfs-PullData-Element aufgerufen, das MSSyncTable.pullWithQuery aufruft, um Remotedaten abzurufen und in der lokalen Datenbank zu speichern.

In der Swift-Version, da der Pushvorgang nicht unbedingt erforderlich war, gibt es keinen Aufruf von pushWithCompletion. Wenn im Synchronisierungskontext für die Tabelle, die einen Pushvorgang ausführt, Änderungen ausstehen, führt Pull immer zuerst einen Push aus. Wenn Sie jedoch mehrere Synchronisierungstabellen haben, empfiehlt es sich, push explizit aufzurufen, um sicherzustellen, dass alles in verwandten Tabellen konsistent ist.

In den versionen Objective-C und Swift können Sie die pullWithQuery-Methode verwenden, um eine Abfrage zum Filtern der abzurufenden Datensätze anzugeben. In diesem Beispiel ruft die Abfrage alle Datensätze in der Remotetabelle TodoItem ab.

Der zweite Parameter von pullWithQuery ist eine Abfrage-ID, die für die inkrementelle Synchronisierung verwendet wird. Bei der inkrementellen Synchronisierung werden nur Datensätze abgerufen, die seit der letzten Synchronisierung geändert wurden, wobei der Zeitstempel des Datensatzes UpdatedAt verwendet wird (im lokalen Speicher aufgerufen updatedAt ).) Die Abfrage-ID sollte eine beschreibende Zeichenfolge sein, die für jede logische Abfrage in Ihrer App eindeutig ist. Um die inkrementelle Synchronisierung zu deaktivieren, übergeben Sie nil die Abfrage-ID. Dieser Ansatz kann potenziell ineffizient sein, da er alle Datensätze für jeden Pullvorgang abruft.

Die Objective-C-App wird synchronisiert, wenn Sie Daten ändern oder hinzufügen, wenn ein Benutzer die Aktualisierungsgeste ausführt, und beim Starten.

Die Swift-App wird synchronisiert, wenn der Benutzer die Aktualisierungsgeste und den Start ausführt.

Da die App immer synchronisiert wird, wenn Daten geändert werden (Objective-C) oder wann immer die App gestartet wird (Objective-C und Swift), geht die App davon aus, dass der Benutzer online ist. In einem späteren Abschnitt aktualisieren Sie die App so, dass Benutzer auch dann bearbeiten können, wenn sie offline sind.

Überprüfen des Kerndatenmodells

Wenn Sie den Offlinespeicher "Core Data" verwenden, müssen Sie bestimmte Tabellen und Felder in Ihrem Datenmodell definieren. Die Beispiel-App enthält bereits ein Datenmodell mit dem richtigen Format. In diesem Abschnitt werden die folgenden Tabellen erläutert, um zu zeigen, wie sie verwendet werden.

Öffnen Sie QSDataModel.xcdatamodeld. Vier Tabellen sind definiert – drei, die vom SDK verwendet werden und eines, das für die to-do Elemente selbst verwendet wird:

  • MS_TableOperations: Verfolgt die Elemente, die mit dem Server synchronisiert werden müssen.
  • MS_TableOperationErrors: Verfolgt alle Fehler, die während der Offlinesynchronisierung auftreten.
  • MS_TableConfig: Verfolgt die Uhrzeit der letzten Aktualisierung des letzten Synchronisierungsvorgangs bei allen Pullvorgängen.
  • TodoItem: Speichert die to-do Elemente. Die systemspalten createdAt, updatedAt und version sind optionale Systemeigenschaften.

Hinweis

Das Mobile Apps SDK reserviert Spaltennamen, die mit "``" beginnen. Verwenden Sie dieses Präfix nicht mit etwas anderem als Systemspalten. Andernfalls werden die Spaltennamen geändert, wenn Sie das Remote-Back-End verwenden.

Wenn Sie die Offlinesynchronisierungsfunktion verwenden, definieren Sie die drei Systemtabellen und die Datentabelle.

Systemtabellen

MS_TableOperations

MS_TableOperations Tabellenattribute

Attribut Typ
id Integer 64
Artikel-ID Schnur
Eigenschaften Binärdaten
Tisch Schnur
tableKind Ganze Zahl 16

MS_Tabellenoperationenfehler

MS_TableOperationErrors Tabellenattribute

Attribut Typ
id Schnur
operationId Integer 64
Eigenschaften Binärdaten
tableKind Ganze Zahl 16

MS_TableConfig

Attribut Typ
id Schnur
Schlüssel Schnur
Schlüsseltyp Integer 64
Tisch Schnur
Wert Schnur

Datentabelle

TodoItem

Attribut Typ Hinweis
id Zeichenfolge, als erforderlich gekennzeichnet Primärschlüssel im Remotespeicher
abgeschlossen Boolescher Typ (Boolean) Aufgabenelementfeld
Text Schnur To-Do-Aufgabenfeld
ErstelltAm Datum (optional) Zuordnung zur createdAt-Systemeigenschaft
aktualisiert am Datum Optional: Zuordnung zur Systemeigenschaft updatedAt
Ausgabe Schnur (optional) Wird verwendet, um Konflikte zu erkennen, der Version zugeordnet

Ändern des Synchronisierungsverhaltens der App

In diesem Abschnitt ändern Sie die App so, dass sie beim Starten der App oder beim Einfügen und Aktualisieren von Elementen nicht synchronisiert wird. Die Synchronisierung erfolgt nur, wenn die Aktualisierungs-Geste ausgeführt wird.

Objective-C:

  1. Ändern Sie in QSTodoListViewController.m die viewDidLoad-Methode , um den Aufruf [self refresh] am Ende der Methode zu entfernen. Jetzt werden die Daten nicht mit dem Server synchronisiert, wenn die App gestartet wird. Stattdessen wird es mit den Inhalten des lokalen Speichers synchronisiert.

  2. Ändern Sie in QSTodoService.m die Definition addItem so, dass sie nach dem Einfügen des Elements nicht synchronisiert wird. Entfernen Sie den self syncData Block, und ersetzen Sie ihn durch Folgendes:

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. Ändern Sie die Definition von completeItem, wie zuvor erwähnt. Entfernen Sie den Block für self syncData und ersetzen Sie ihn durch Folgendes:

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

Swift:

viewDidLoadKommentieren Sie in "ToDoTableViewController.swift" die beiden hier gezeigten Zeilen aus, um die Synchronisierung beim Start der App zu beenden. Zum Zeitpunkt dieses Schreibens aktualisiert die Swift Todo-App den Dienst nicht, wenn jemand ein Element hinzufügt oder abschließt. Er aktualisiert den Dienst nur beim Starten der App.

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

Testen der App

In diesem Abschnitt stellen Sie eine Verbindung mit einer ungültigen URL her, um ein Offlineszenario zu simulieren. Wenn Sie Datenelemente hinzufügen, werden sie im lokalen Core-Datenspeicher gespeichert, aber nicht mit dem Back-End der mobilen App synchronisiert.

  1. Ändern Sie die URL für mobile Apps in QSTodoService.m in eine ungültige URL, und führen Sie die App erneut aus:

    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. Fügen Sie einige to-do Elemente hinzu. Beenden Sie den Simulator (oder schließen Sie die App), und starten Sie sie dann neu. Überprüfen Sie, ob Ihre Änderungen beibehalten werden.

  3. Zeigen Sie den Inhalt der Remote-TodoItem-Tabelle an:

    • Wechseln Sie für ein Node.js Back-End zum Azure-Portal , und klicken Sie in Ihrem Mobilen App-Back-End auf "Einfache Tabellen>todoItem".
    • Verwenden Sie für ein .NET-Back-End entweder ein SQL-Tool wie SQL Server Management Studio oder einen REST-Client, z. B. Fiddler oder Postman.
  4. Stellen Sie sicher, dass die neuen Elemente nicht mit dem Server synchronisiert wurden.

  5. Ändern Sie die URL zurück zum richtigen in QSTodoService.m, und führen Sie die App erneut aus.

  6. Führen Sie die Aktualisierungsgeste aus, indem Sie die Liste der Elemente nach unten ziehen.
    Eine Fortschrittsanzeige wird angezeigt.

  7. Zeigen Sie die TodoItem-Daten erneut an. Die neuen und geänderten to-do Elemente sollten jetzt angezeigt werden.

Zusammenfassung

Zur Unterstützung der Offline-Synchronisierungsfunktion haben wir die MSSyncTable-Schnittstelle verwendet und MSClient.syncContext mit einem lokalen Speicher initialisiert. In diesem Fall war der lokale Speicher eine Datenbank, die auf Kerndaten basiert.

Wenn Sie einen lokalen Kerndatenspeicher verwenden, müssen Sie mehrere Tabellen mit den richtigen Systemeigenschaften definieren.

Die normalen Erstellungs-, Lese-, Aktualisierungs- und Löschvorgänge (CRUD)-Vorgänge für mobile Apps funktionieren so, als ob die App noch verbunden ist, aber alle Vorgänge treten für den lokalen Store auf.

Wenn wir den lokalen Speicher mit dem Server synchronisiert haben, haben wir die MSSyncTable.pullWithQuery-Methode verwendet.

Weitere Ressourcen