Udostępnij za pośrednictwem


Włączanie synchronizacji w trybie offline z aplikacjami mobilnymi systemu iOS

Przegląd

W tym samouczku opisano synchronizowanie w trybie offline z funkcją Mobile Apps usługi Azure App Service dla systemu iOS. Dzięki synchronizacji w trybie offline użytkownicy końcowi mogą wchodzić w interakcje z aplikacją mobilną w celu wyświetlania, dodawania lub modyfikowania danych, nawet jeśli nie mają połączenia sieciowego. Zmiany są przechowywane w lokalnej bazie danych. Po powrocie urządzenia do trybu online zmiany są synchronizowane z zdalnym zapleczem.

Jeśli to jest Twoje pierwsze doświadczenie z aplikacjami mobilnymi, powinieneś najpierw ukończyć samouczek Stwórz aplikację na iOS. Jeśli nie używasz pobranego projektu serwera Szybkiego startu, musisz dodać pakiety rozszerzeń dostępu do danych do projektu. Aby uzyskać więcej informacji na temat pakietów rozszerzeń serwera, zobacz Work with the .NET backend server SDK for Azure Mobile Apps.

Aby dowiedzieć się więcej na temat funkcji synchronizacji w trybie offline, zobacz Offline Data Sync in Mobile Apps.

Przeglądanie kodu synchronizacji klienta

Projekt klienta pobrany dla Tworzenie aplikacji iOS zawiera już kod obsługujący synchronizację w trybie offline przy użyciu lokalnej bazy danych opartej na Core Data. W tej sekcji podsumowano, co zostało już uwzględnione w kodzie samouczka. Aby zapoznać się z koncepcyjnym omówieniem tej funkcji, zobacz Offline Data Sync in Mobile Apps.

Korzystając z funkcji synchronizacji danych w trybie offline usługi Mobile Apps, użytkownicy końcowi mogą korzystać z lokalnej bazy danych nawet wtedy, gdy sieć jest niedostępna. Aby użyć tych funkcji w aplikacji, należy zainicjować kontekst synchronizacji MSClient i odwołać się do magazynu lokalnego. Następnie odwołujesz się do swojej tabeli za pomocą interfejsu MSSyncTable.

W QSTodoService.m (Objective-C) lub ToDoTableViewController.swift (Swift), zwróć uwagę, że typ członka syncTable jest MSSyncTable. Synchronizacja w trybie offline używa tego interfejsu tabeli synchronizacji zamiast MSTable. Gdy jest używana tabela synchronizacji, wszystkie operacje przechodzą do magazynu lokalnego i są synchronizowane tylko z zdalnym zapleczem z jawnymi operacjami wypychania i ściągania.

Aby uzyskać odwołanie do tabeli synchronizacji, użyj metody syncTableWithName w MSClient. Aby usunąć funkcje synchronizacji offline, zamiast tego użyj tableWithName.

Przed wykonaniem jakichkolwiek operacji na tabeli należy zainicjować sklep lokalny. Oto odpowiedni kod:

  • Objective-C. W metodzie QSTodoService.init:

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

    Ta metoda tworzy magazyn lokalny przy użyciu interfejsu MSCoreDataStore, który udostępnia SDK dla aplikacji mobilnych. Alternatywnie możesz udostępnić inny magazyn lokalny, implementując protokół MSSyncContextDataSource. Ponadto pierwszy parametr msSyncContext służy do określania procedury obsługi konfliktów. Ponieważ przeszliśmy przez nil, otrzymujemy domyślną procedurę obsługi konfliktów, która zawodzi przy jakimkolwiek konflikcie.

Teraz przeprowadźmy rzeczywistą operację synchronizacji i pobierzemy dane z zdalnego zaplecza:

  • Objective-C. syncData najpierw wprowadza nowe zmiany, a następnie wywołuje pullData, aby pobrać dane z zdalnego backendu. Z kolei metoda pullData pobiera nowe dane zgodne z zapytaniem:

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

W wersji Objective-C w syncDatanajpierw wywołujemy pushWithCompletion w kontekście synchronizacji. Ta metoda jest elementem MSSyncContext (a nie samej tabeli synchronizacji), ponieważ przenosi zmiany we wszystkich tabelach. Do serwera są wysyłane tylko rekordy, które zostały zmodyfikowane lokalnie (za pośrednictwem operacji CUD). Następnie wywoływana jest funkcja pomocnicza pullData, która następnie uruchamia MSSyncTable.pullWithQuery, aby pobrać zdalne dane i zapisać je w lokalnej bazie danych.

W wersji Swift, operacja wypychania nie była ściśle konieczna, więc nie ma wywołania pushWithCompletion. Jeśli w kontekście synchronizacji tabeli, która wykonuje operację wypychania, występują jakiekolwiek zmiany, ściąganie zawsze najpierw inicjuje wypchnięcie. Jeśli jednak masz więcej niż jedną tabelę synchronizacji, najlepiej jest jawnie wywołać operację push, aby w powiązanych tabelach zapewnić spójność danych.

W obu wersjach Objective-C i Swift można użyć metody pullWithQuery, aby określić zapytanie do filtrowania rekordów, które chcesz pobrać. W tym przykładzie zapytanie pobiera wszystkie rekordy w zdalnej tabeli TodoItem.

Drugi parametr pullWithQuery to identyfikator zapytania używany do synchronizacji przyrostowej . Synchronizacja przyrostowa pobiera tylko rekordy, które zostały zmodyfikowane od ostatniej synchronizacji, wykorzystując znacznik czasu UpdatedAt rekordu (znany jako updatedAt w magazynie lokalnym). Identyfikator zapytania powinien być opisowym, unikatowym ciągiem dla każdego logicznego zapytania w aplikacji. Aby zrezygnować z synchronizacji przyrostowej, przekaż nil jako identyfikator zapytania. Takie podejście może być potencjalnie nieefektywne, ponieważ pobiera wszystkie rekordy dla każdej operacji ściągania.

Aplikacja Objective-C jest synchronizowana podczas modyfikowania lub dodawania danych, gdy użytkownik wykonuje gest odświeżania i podczas uruchamiania.

Aplikacja Swift synchronizuje się, gdy użytkownik wykonuje gest odświeżania i podczas uruchamiania.

Ponieważ aplikacja synchronizuje się za każdym razem, gdy dane są modyfikowane (Objective-C) lub za każdym razem, gdy aplikacja jest uruchamiana (Objective-C i Swift), aplikacja zakłada, że użytkownik jest w trybie online. W późniejszej sekcji zaktualizujesz aplikację, aby użytkownicy mogli edytować nawet wtedy, gdy są w trybie offline.

Przeglądanie podstawowego modelu danych

W przypadku korzystania z magazynu danych podstawowych w trybie offline należy zdefiniować określone tabele i pola w modelu danych. Przykładowa aplikacja zawiera już model danych z odpowiednim formatem. W tej sekcji omówimy te tabele, aby pokazać, jak są używane.

Otwórz QSDataModel.xcdatamodeld. Cztery tabele są zdefiniowane — trzy, które są używane przez zestaw SDK i jeden, który jest używany dla samych elementów to-do:

  • MS_TableOperations: śledzi elementy, które należy zsynchronizować z serwerem.
  • MS_TableOperationErrors: śledzi wszelkie błędy występujące podczas synchronizacji w trybie offline.
  • MS_TableConfig: Rejestruje czas ostatniej aktualizacji dla ostatniej operacji synchronizacji we wszystkich operacjach ściągania.
  • TodoItem: przechowuje elementy to-do. Kolumny systemowe createdAt, updatedAtoraz wersja są opcjonalnymi właściwościami systemu.

Uwaga

Zestaw SDK usługi Mobile Apps rezerwuje nazwy kolumn rozpoczynające się od "``". Nie używaj tego prefiksu z innymi kolumnami systemowymi. W przeciwnym razie nazwy kolumn są modyfikowane podczas korzystania z zdalnego zaplecza systemu.

W przypadku korzystania z funkcji synchronizacji offline zdefiniuj trzy tabele systemowe i tabelę danych.

Tabele systemowe

MS_TableOperations

atrybuty tabeli MS_TableOperations

Atrybut Typ
id Liczba całkowita 64
identyfikator przedmiotu Sznurek
właściwości Dane binarne
stół Sznurek
tableKind Int16

MS_TableOperationErrors

atrybuty tabeli MS_TableOperationErrors

Atrybut Typ
id Sznurek
operationId Liczba całkowita 64
właściwości Dane binarne
tableKind Liczba całkowita 16

MS_TableConfig

Atrybut Typ
id Sznurek
klucz Sznurek
typ klucza Liczba całkowita 64
stół Sznurek
wartość Sznurek

Tabela danych

todoItem

Atrybut Typ Uwaga
id Ciąg, oznaczony jako wymagany Klucz podstawowy w magazynie zdalnym
ukończyć Boolean Pole zadania do wykonania
Tekst Sznurek Pole zadania do wykonania
createdAt Data (opcjonalnie) Odnosi się do właściwości systemowej createdAt
data aktualizacji Data (opcjonalnie) Mapuje zaktualizowanąW właściwość systemowa
wersja Sznurek (opcjonalnie) Służy do wykrywania konfliktów, odpowiada wersji

Zmienianie zachowania synchronizacji aplikacji

W tej sekcji zmodyfikujesz aplikację tak, aby nie była synchronizowana podczas uruchamiania aplikacji ani podczas wstawiania i aktualizowania elementów. Synchronizuje się tylko po wykonaniu przycisku gestu odświeżania.

Objective-C:

  1. W QSTodoListViewController.mzmień metodę viewDidLoad, aby usunąć wywołanie metody [self refresh] na końcu. Teraz dane nie są synchronizowane z serwerem podczas uruchamiania aplikacji. Zamiast tego, synchronizowana jest z zawartością lokalnego magazynu.

  2. W QSTodoService.mzmodyfikuj definicję addItem, aby nie była synchronizowana po wstawieniu elementu. Usuń blok self syncData i zastąp go następującymi elementami:

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. Zmodyfikuj definicję completeItem, jak wspomniano wcześniej. Usuń blok dla self syncData i zastąp go następującymi elementami:

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

Swift:

W viewDidLoadw ToDoTableViewController.swiftzakomentuj dwie linie przedstawione tutaj, aby zatrzymać synchronizację przy uruchomieniu aplikacji. W momencie pisania tego tekstu aplikacja Swift Todo nie aktualizuje usługi, gdy ktoś dodaje lub kończy element. Aktualizuje usługę tylko podczas uruchamiania aplikacji.

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

Testowanie aplikacji

W tej sekcji łączysz się z nieprawidłowym adresem URL, aby zsymulować scenariusz offline. Po dodaniu elementów danych są one przechowywane w lokalnym magazynie danych Core Data Store, ale nie są one synchronizowane z zapleczem aplikacji mobilnej.

  1. Zmień adres URL aplikacji mobilnej w QSTodoService.m na nieprawidłowy adres URL i uruchom aplikację ponownie:

    Objective-C. W pliku QSTodoService.m:

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

    Swift. W pliku ToDoTableViewController.swift:

    let client = MSClient(applicationURLString: "https://sitename.azurewebsites.net.fail")
    
  2. Dodaj niektóre elementy to-do. Zamknij symulator (lub wymuś zamknięcie aplikacji), a następnie uruchom go ponownie. Sprawdź, czy zmiany są utrwalane.

  3. Wyświetl zawartość zdalnej tabeli TodoItem:

    • Aby uzyskać zaplecze Node.js, przejdź do witryny Azure Portal, a następnie w zapleczu aplikacji mobilnej kliknij pozycję Łatwe tabele>TodoItem.
    • W przypadku zaplecza platformy .NET użyj narzędzia SQL, takiego jak SQL Server Management Studio, lub klienta REST, takiego jak Fiddler lub Postman.
  4. Sprawdź, czy nowe elementy nie zostały zsynchronizowane z serwerem, a nie.

  5. Zmień adres URL z powrotem na poprawny w QSTodoService.mi uruchom ponownie aplikację.

  6. Wykonaj gest odświeżania, ściągając listę elementów.
    Jest wyświetlany wskaźnik postępu.

  7. Ponownie wyświetl dane TodoItem. Nowe i zmienione elementy to-do powinny być teraz wyświetlane.

Podsumowanie

Aby obsługiwać funkcję synchronizacji w trybie offline, użyliśmy interfejsu MSSyncTable i zainicjowaliśmy MSClient.syncContext z magazynem lokalnym. W tym przypadku magazyn lokalny był bazą danych opartą na danych podstawowych.

W przypadku korzystania z lokalnego magazynu Core Data musisz zdefiniować kilka tabel z poprawnymi właściwościami systemu.

Normalne operacje tworzenia, odczytu, aktualizacji i usuwania (CRUD) dla aplikacji mobilnych działają tak, jakby aplikacja jest nadal połączona, ale wszystkie operacje występują w sklepie lokalnym.

Podczas synchronizowania magazynu lokalnego z serwerem użyliśmy metody MSSyncTable.pullWithQuery.

Dodatkowe zasoby