次の方法で共有


iOS モバイル アプリとのオフライン同期を有効にする

概要

このチュートリアルでは、Azure App Service for iOS の Mobile Apps 機能とのオフライン同期について説明します。 オフライン同期を使用すると、エンドユーザーはモバイル アプリと対話して、ネットワークに接続していない場合でも、データを表示、追加、または変更できます。 変更はローカル データベースに格納されます。 デバイスがオンラインに戻ると、変更はリモート バックエンドと同期されます。

これが Mobile Apps を初めて使用する場合は、最初に「iOS アプリ を作成する」チュートリアルを完了する必要があります。 ダウンロードしたクイック スタート サーバー プロジェクトを使用しない場合は、データ アクセス拡張機能パッケージをプロジェクトに追加する必要があります。 サーバー拡張機能パッケージの詳細については、「.NET バックエンド サーバー SDK for Azure Mobile Appsを使用する」を参照してください。

オフライン同期機能の詳細については、「Mobile Apps でのオフライン データ同期の」を参照してください。

クライアント同期コードを確認する

iOS アプリ の作成チュートリアル用にダウンロードしたクライアント プロジェクトには、ローカルの Core データ ベースデータベースを使用したオフライン同期をサポートするコードが既に含まれています。 このセクションでは、チュートリアル コードに既に含まれている内容をまとめます。 この機能の概念の概要については、「Mobile Apps でのオフライン データ同期」を参照してください。

モバイル アプリのオフライン データ同期機能を使用すると、エンド ユーザーはネットワークにアクセスできない場合でもローカル データベースと対話できます。 アプリでこれらの機能を使用するには、MSClient の同期コンテキストを初期化し、ローカル ストアを参照します。 次に、MSSyncTable インターフェイスを使用してテーブルを参照します。

QSTodoService.m (Objective-C) または ToDoTableViewController.swift (Swift) で、メンバー syncTable の型が MSSyncTableであることを確認してください。 オフライン同期では、MSTable ではなく、この同期テーブル インターフェイス使用します。 同期テーブルを使用すると、すべての操作がローカル ストアに移動し、明示的なプッシュ操作とプル操作を使用してリモート バックエンドとのみ同期されます。

同期テーブルへの参照を取得するには、MSClient メソッドを使用します。 オフライン同期機能を削除するには、代わりに tableWithName 使用します。

テーブル操作を実行する前に、ローカル ストアを初期化する必要があります。 関連するコードを次に示します。

  • Objective-C. QSTodoService.init メソッドで、次の手順を実行します。

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

    このメソッドは、Mobile Apps SDK が提供する MSCoreDataStore インターフェイスを使用してローカル ストアを作成します。 または、MSSyncContextDataSource プロトコルを実装することで、別のローカル ストアを提供することもできます。 また、MSSyncContext の最初のパラメーターを使用して、競合ハンドラーを指定します。 nilを通過したため、既定の競合ハンドラーが取得され、競合が発生すると失敗します。

次に、実際の同期操作を実行し、リモート バックエンドからデータを取得してみましょう。

  • Objective-C. syncData 最初に新しい変更をプッシュしてから pullData 呼び出してリモート バックエンドからデータを取得します。 さらに、pullData メソッドは、クエリに一致する新しいデータを取得します。

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

Objective-C バージョンでは、syncDataでは、最初に同期コンテキスト pushWithCompletion を呼び出します。 このメソッドは、すべてのテーブルに変更をプッシュするため、MSSyncContext (同期テーブル自体ではなく) のメンバーです。 (CUD 操作を介して) 何らかの方法で変更されたレコードのみがサーバーに送信されます。 次に、pullData ヘルパーが呼び出され、MSSyncTable.pullWithQuery 呼び出してリモート データを取得し、ローカル データベースに格納します。

Swift バージョンでは、プッシュ操作は厳密に必要なかったため、pushWithCompletion で呼び出すことはありません。 プッシュ操作を実行しているテーブルの同期コンテキストで保留中の変更がある場合、プルは常に最初にプッシュを発行します。 ただし、複数の同期テーブルがある場合は、プッシュを明示的に呼び出して、関連するテーブル間ですべてが一貫していることを確認することをお勧めします。

Objective-C バージョンと Swift バージョンの両方で、pullWithQuery メソッドを使用して、取得するレコードをフィルター処理するクエリを指定できます。 この例では、クエリはリモート TodoItem テーブル内のすべてのレコードを取得します。

pullWithQuery の 2 番目のパラメーターは、増分同期 使用されるクエリ ID です。増分同期では、レコードの UpdatedAt タイム スタンプ (ローカル ストアで updatedAt と呼ばれます) を使用して、前回の同期以降に変更されたレコードのみが取得されます。クエリ ID は、アプリ内の各論理クエリに対して一意の説明文字列にする必要があります。 増分同期を無効にするには、クエリ ID として nil を渡します。 この方法は、各プル操作のすべてのレコードを取得するため、非効率的になる可能性があります。

Objective-C アプリは、データを変更または追加するとき、ユーザーが更新ジェスチャを実行したとき、および起動時に同期されます。

Swift アプリは、ユーザーが更新ジェスチャを実行し、起動時に同期します。

アプリは、データが変更されたとき (Objective-C) またはアプリが起動するたびに (Objective-C および Swift) 同期されるため、アプリはユーザーがオンラインであると見なします。 後のセクションでは、ユーザーがオフラインの場合でも編集できるように、アプリを更新します。

コア データ モデルを確認する

コア データ オフライン ストアを使用する場合は、データ モデルで特定のテーブルとフィールドを定義する必要があります。 サンプル アプリには、適切な形式のデータ モデルが既に含まれています。 このセクションでは、これらのテーブルの使用方法について説明します。

QSDataModel.xcdatamodeld を開きます。 4 つのテーブルが定義されています。3 つは SDK によって使用され、1 つは to-do 項目自体に使用されます。

  • MS_TableOperations: サーバーと同期する必要がある項目を追跡します。
  • MS_TableOperationErrors: オフライン同期中に発生したエラーを追跡します。
  • MS_TableConfig: すべてのプル操作の最後の同期操作の最終更新時刻を追跡します。
  • TodoItem: to-do 項目を格納します。 システム列 createdAtupdatedAt、および バージョン はオプションのシステム プロパティです。

Mobile Apps SDK では、"``" で始まる列名が予約されます。 このプレフィックスは、システム列以外には使用しないでください。 それ以外の場合、リモート バックエンドを使用すると列名が変更されます。

オフライン同期機能を使用する場合は、3 つのシステム テーブルとデータ テーブルを定義します。

システム テーブル

MS_TableOperations

MS_TableOperations テーブル属性

特性 タイプ
識別子 整数 64
アイテムID
プロパティ バイナリデータ
テーブルの種類 整数 16

MS_TableOperationErrors

MS_TableOperationErrors テーブル属性

特性 タイプ
識別子
operationId 整数 64
プロパティ バイナリデータ
テーブルの種類 整数 16

MS_TableConfig

特性 タイプ
識別子
キータイプ 整数 64
価値

データ テーブル

の Todo項目 を処理する

特性 タイプ
識別子 必須としてマークされた文字列 リモート ストアの主キー
完了 ボーリアン やること項目フィールド
テキスト やること項目フィールド
createdAt 日付 (省略可能) システム プロパティに "createdAt" をマップします
更新日時 日付 (省略可能)updatedAt システム プロパティにマップされます
バージョン (省略可能)競合を検出するために使用され、バージョンにマップされます

アプリの同期動作を変更する

このセクションでは、アプリの起動時またはアイテムの挿入と更新時に同期されないように、アプリを変更します。 更新ジェスチャ ボタンが実行されたときにのみ同期されます。

Objective-C:

  1. QSTodoListViewController.mで、viewDidLoad メソッドを変更して、メソッドの末尾にある [self refresh] の呼び出しを削除します。 これで、アプリの起動時にデータがサーバーと同期されません。 代わりに、ローカル ストアの内容と同期されます。

  2. QSTodoService.mで、項目の挿入後に同期されないように addItem の定義を変更します。 self syncData ブロックを削除し、次のように置き換えます。

    if (completion != nil) {
        dispatch_async(dispatch_get_main_queue(), completion);
    }
    
  3. 前述のように、completeItem の定義を変更します。 self syncData のブロックを削除し、次のように置き換えます。

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

Swift:

viewDidLoadでは、の ToDoTableViewController.swiftで、ここに示されている 2 行をコメントアウトして、アプリ起動時の同期を停止します。 この記事の執筆時点では、Swift Todo アプリは、誰かがアイテムを追加または完了したときにサービスを更新しません。 アプリの起動時にのみサービスが更新されます。

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

アプリをテストする

このセクションでは、無効な URL に接続してオフライン シナリオをシミュレートします。 データ項目を追加すると、それらはローカルのコア データ ストアに保持されますが、モバイル アプリバックエンドと同期されません。

  1. QSTodoService.m のモバイル アプリ URL を無効な URL に変更し、アプリをもう一度実行します。

    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. いくつかの to-do 項目を追加します。 シミュレーターを終了し (またはアプリを強制的に閉じてから)、再起動します。 変更が保持されることを確認します。

  3. リモート TodoItem テーブルの内容を表示します。

    • Node.js バックエンドの場合、Azure ポータル にアクセスし、モバイル アプリのバックエンドで をクリックし、[Easy Tables>TodoItem] を選択します。
    • .NET バックエンドの場合は、SQL Server Management Studio などの SQL ツール、または Fiddler や Postman などの REST クライアントを使用します。
  4. 新しい項目がサーバーと同期されたのではなくであることを確認します。

  5. QSTodoService.mで URL を正しいものに戻し、アプリを再実行します。

  6. 項目の一覧をプルダウンして、更新ジェスチャを実行します。
    進行状況のスピナーが表示されます。

  7. TodoItem データをもう一度表示します。 新しい項目と変更された to-do 項目が今表示されるはずです。

概要

オフライン同期機能をサポートするために、MSSyncTable インターフェイスを使用し、ローカル ストアで MSClient.syncContext を初期化しました。 この場合、ローカル ストアはコア データ ベースのデータベースでした。

コア データ ローカル ストアを使用する場合は、正しいシステム プロパティ 複数のテーブルを定義する必要があります。

モバイル アプリの通常の作成、読み取り、更新、削除 (CRUD) 操作は、アプリがまだ接続されているかのように機能しますが、すべての操作はローカル ストアに対して実行されます。

ローカル ストアをサーバーと同期するときに、MSSyncTable.pullWithQuery メソッドを使用しました。

その他のリソース