为 Cordova 移动应用启用脱机同步

概述

本教程介绍适用于 Cordova 的 Azure 移动应用的脱机同步功能。 脱机同步允许最终用户与移动应用交互(查看、添加或修改数据),即使没有网络连接也是如此。 更改存储在本地数据库中。 设备重新联机后,这些更改将与远程服务同步。

本教程基于在完成本教程 Apache Cordova 快速入门时创建的移动应用的 Cordova 快速入门解决方案。 在本教程中,你将更新快速入门解决方案,以添加 Azure 移动应用的脱机功能。 我们还在应用中高亮显示离线专用代码。

若要了解有关脱机同步功能的详细信息,请参阅主题 Azure 移动应用中的脱机数据同步。 有关 API 使用情况的详细信息,请参阅 API 文档

将脱机同步添加到快速开始解决方案

必须将脱机同步代码添加到应用。 脱机同步需要 cordova-sqlite-storage 插件,当项目中包含 Azure 移动应用插件时,该插件会自动添加到应用。 快速入门项目包括这两个插件。

  1. 在 Visual Studio 的解决方案资源管理器中,打开 index.js 并替换以下代码

     var client,            // Connection to the Azure Mobile App backend
        todoItemTable;      // Reference to a table endpoint on backend
    

    使用此代码:

     var client,            // Connection to the Azure Mobile App backend
        todoItemTable,      // Reference to a table endpoint on backend
        syncContext;        // Reference to offline data sync context
    
  2. 接下来,替换以下代码:

     client = new WindowsAzure.MobileServiceClient('http://yourmobileapp.azurewebsites.net');
    

    使用此代码:

     client = new WindowsAzure.MobileServiceClient('http://yourmobileapp.azurewebsites.net');
     var store = new WindowsAzure.MobileServiceSqliteStore('store.db');
    
     store.defineTable({
       name: 'todoitem',
       columnDefinitions: {
           id: 'string',
           text: 'string',
           complete: 'boolean',
           version: 'string'
       }
     });
    
     // Get the sync context from the client
     syncContext = client.getSyncContext();
    

    前面的代码添加将初始化本地存储并定义与 Azure 后端中使用的列值匹配的本地表。 (无需在此代码中包含所有列值。version 字段由移动后端维护,用于解决冲突。

    通过调用 getSyncContext来获取对同步上下文的引用。 同步上下文通过跟踪和推送客户端应用在调用 .push() 时修改的所有表中的更改来帮助保留表关系。

  3. 将应用程序 URL 更新到移动应用应用程序 URL。

  4. 接下来,替换以下代码:

     todoItemTable = client.getTable('todoitem'); // todoitem is the table name
    

    使用此代码:

     // Initialize the sync context with the store
     syncContext.initialize(store).then(function () {
    
     // Get the local table reference.
     todoItemTable = client.getSyncTable('todoitem');
    
     syncContext.pushHandler = {
         onConflict: function (pushError) {
             // Handle the conflict.
             console.log("Sync conflict! " + pushError.getError().message);
             // Update failed, revert to server's copy.
             pushError.cancelAndDiscard();
           },
           onError: function (pushError) {
               // Handle the error
               // In the simulated offline state, you get "Sync error! Unexpected connection failure."
               console.log("Sync error! " + pushError.getError().message);
           }
     };
    
     // Call a function to perform the actual sync
     syncBackend();
    
     // Refresh the todoItems
     refreshDisplay();
    
     // Wire up the UI Event Handler for the Add Item
     $('#add-item').submit(addItemHandler);
     $('#refresh').on('click', refreshDisplay);
    

    前面的代码初始化同步上下文,然后调用 getSyncTable(而不是 getTable)来获取对本地表的引用。

    此代码使用本地数据库执行所有创建、读取、更新和删除(CRUD)表作。

    此示例对同步冲突执行简单的错误处理。 实际应用程序将处理各种错误,例如网络条件、服务器冲突和其他错误。 有关代码示例,请参阅 脱机同步示例

  5. 接下来,添加此函数以执行实际同步。

     function syncBackend() {
    
       // Sync local store to Azure table when app loads, or when login complete.
       syncContext.push().then(function () {
           // Push completed
    
       });
    
       // Pull items from the Azure table after syncing to Azure.
       syncContext.pull(new WindowsAzure.Query('todoitem'));
     }
    

    通过调用 syncContext.push(),决定何时将更改推送到移动应用后端。 例如,可以在绑定到同步按钮的按钮事件处理程序中调用 syncBackend

脱机同步注意事项

在此示例中,syncContextpush 方法仅在用于登录的回调函数中的应用启动时调用。 在实际应用程序中,还可以手动触发此同步功能,或者在网络状态发生更改时触发。

当对上下文跟踪的有挂起本地更新的表进行拉取操作时,该操作会自动触发推送。 刷新、添加和完成此示例中的项时,可以省略显式 推送 调用,因为它可能是冗余的。

在提供的代码中,查询远程 todoItem 表中的所有记录,但也可以通过将查询 ID 和查询传递给 推送来筛选记录。 有关详细信息,请参阅 Azure 移动应用中的 脱机数据同步中的 增量同步 部分。

(可选)禁用身份验证

如果不想在测试脱机同步之前进行身份验证,请注释掉登录的回调函数,但请保留回调函数内的代码不做注释。 注释掉登录行后,代码如下所示:

  // Login to the service.
  // client.login('twitter')
  //    .then(function () {
    syncContext.initialize(store).then(function () {
      // Leave the rest of the code in this callback function  uncommented.
            ...
    });
  // }, handleError);

现在,运行应用时,应用会与 Azure 后端同步。

运行客户端应用

启用脱机同步后,可以在每个平台上至少运行一次客户端应用程序,以填充本地存储数据库。 稍后,模拟脱机方案,并在应用脱机时修改本地存储中的数据。

(可选)测试同步行为

在本部分中,将修改客户端项目,以使用后端的无效应用程序 URL 来模拟脱机方案。 添加或更改数据项时,这些更改保存在本地存储中,但在重新建立连接之前不会同步到后端数据存储。

  1. 在解决方案资源管理器中,打开 index.js 项目文件,并将应用程序 URL 更改为指向无效 URL,如以下代码:

     client = new WindowsAzure.MobileServiceClient('http://yourmobileapp.azurewebsites.net-fail');
    
  2. 在 index.html中,使用相同的无效 URL 更新 CSP <meta> 元素。

     <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: http://yourmobileapp.azurewebsites.net-fail; style-src 'self'; media-src *">
    
  3. 生成并运行客户端应用,并注意到在登录后应用尝试与后端同步时,控制台中记录了异常。 添加的任何新项仅存在于本地存储中,直到它们被推送到移动后端。 客户端应用的行为就像它连接到后端一样。

  4. 关闭应用并重启它,以验证你创建的新项是否持久保存到本地存储中。

  5. (可选)使用 Visual Studio 查看 Azure SQL 数据库表,以查看后端数据库中的数据未更改。

    在 Visual Studio 中,打开 服务器资源管理器。 导航到您的 Azure SQL 数据库 ->。 右键单击您的数据库,然后选择“在 SQL Server 对象资源管理器 中打开”。 现在可以浏览到 SQL 数据库表及其内容。

(可选)测试重连到移动后端

在本部分中,将应用重新连接到移动后端,该后端模拟返回到联机状态的应用。 登录时,数据将同步到移动后端。

  1. 重新打开 index.js 并还原应用程序 URL。

  2. 重新打开 index.html 并更正 CSP <meta> 元素中的应用程序 URL。

  3. 重新生成并运行客户端应用。 该应用在登录后尝试与移动应用后端同步。 验证调试控制台中是否未记录任何异常。

  4. (可选)使用 SQL Server 对象资源管理器或 REST 工具(如 Fiddler)查看更新的数据。 请注意,数据已在后端数据库和本地存储之间同步。

    请注意,数据已在数据库和本地存储之间同步,并包含应用断开连接时添加的项。

其他资源

后续步骤