如何使用适用于 Azure 移动应用的 Apache Cordova 客户端库

本指南介绍如何使用最新的适用于 Azure 移动应用的 Apache Cordova 插件执行常见任务。对于 Azure 移动应用的新手,请先完成 Azure Mobile Apps Quick Start(Azure 移动应用快速入门),创建后端、创建表并下载预先生成的 Apache Cordova 项目。本指南侧重于客户端 Apache Cordova 插件。

支持的平台

此 SDK 在 iOS、Android 和 Windows 设备上支持 Apache Cordova v6.0.0 和更高版本。平台支持如下所示:

  • Android API 19-24(KitKat 到 Nougat)
  • iOS 8.0 和更高版本。
  • Windows Phone 8.1。
  • 通用 Windows 平台。

安装与先决条件

本指南假设已创建了包含表的后端。本指南假设该表的架构与这些教程中的表相同。本指南还假设已将 Apache Cordova 插件添加到代码。如果尚未这样做,可以在命令行中将 Apache Cordova 插件添加到项目:

cordova plugin add cordova-plugin-ms-azure-mobile-apps

有关创建第一个 Apache Cordova 应用的详细信息,请参阅相关文档。

设置 Ionic v2 应用

若要正确配置 Ionic v2 项目,首先需创建一个基本应用,并添加 Cordova 插件:

ionic start projectName --v2
cd projectName
ionic plugin add cordova-plugin-ms-azure-mobile-apps

app.component.ts 中添加以下行以创建客户端对象:

declare var WindowsAzure: any;
var client = new WindowsAzure.MobileServiceClient("https://yoursite.azurewebsites.cn");

现在可以在浏览器中生成并运行项目:

ionic platform add browser
ionic run browser

Azure 移动应用 Cordova 插件同时支持 Ionic v1 和 v2 应用。只有 Ionic v2 应用需要额外的针对 WindowsAzure 对象的声明。

创建客户端连接

通过创建 WindowsAzure.MobileServiceClient 对象创建客户端连接。将 appUrl 替换为到移动应用的 URL。

var client = WindowsAzure.MobileServiceClient(appUrl);

使用表格

若要访问或更新数据,请创建到后端表的引用。将 tableName 替换为表名称

var table = client.getTable(tableName);

拥有表格引用后,可进一步使用表格:

如何:查询表格引用

拥有表格引用后,可用其查询服务器上的数据。查询使用了“类 LINQ”语言。 若要返回表中的所有数据,请使用以下项:

/**
 * Process the results that are received by a call to table.read()
 *
 * @param {Object} results the results as a pseudo-array
 * @param {int} results.length the length of the results array
 * @param {Object} results[] the individual results
 */
function success(results) {
   var numItemsRead = results.length;

   for (var i = 0 ; i < results.length ; i++) {
       var row = results[i];
       // Each row is an object - the properties are the columns
   }
}

function failure(error) {
    throw new Error('Error loading data: ', error);
}

table
    .read()
    .then(success, failure);

随结果调用 success 函数。请勿在 success 函数中使用 for (var i in results),因为这会在使用其他查询函数(如 .includeTotalCount())时迭代结果中所含的信息。

在服务器上筛选数据

可在表格引用上使用 where 子句:

table
    .where({ userId: user.userId, complete: false })
    .read()
    .then(success, failure);

也可使用筛选对象的函数。该情况下,this 变量被分配给经过筛选的当前对象。以下代码在功能上等效于上个示例:

function filterByUserId(currentUserId) {
    return this.userId === currentUserId && this.complete === false;
}

table
    .where(filterByUserId, user.userId)
    .read()
    .then(success, failure);

分页浏览数据

使用 take()skip() 方法。例如,如想要将表拆分为 100 行记录:

var totalCount = 0, pages = 0;

// Step 1 - get the total number of records
table.includeTotalCount().take(0).read(function (results) {
    totalCount = results.totalCount;
    pages = Math.floor(totalCount/100) + 1;
    loadPage(0);
}, failure);

function loadPage(pageNum) {
    let skip = pageNum * 100;
    table.skip(skip).take(100).read(function (results) {
        for (var i = 0 ; i < results.length ; i++) {
            var row = results[i];
            // Process each row
        }
    }
}

.includeTotalCount() 方法用于将 totalCount 字段添加到结果对象。如果不分页,totalCount 字段会填充要返回的记录总数。

然后可使用页变量和某些 UI 按钮提供页列表;使用 loadPage() 为每页加载新记录。实现缓存以加快对已加载记录的访问速度。

如何:返回排序后的数据

使用 .orderBy().orderByDescending() 查询方法:

table
    .orderBy('name')
    .read()
    .then(success, failure);

如何:插入数据

使用相应日期创建 JavaScript 对象并异步调用 table.insert():

var newItem = {
    name: 'My Name',
    signupDate: new Date()
};

table
    .insert(newItem)
    .done(function (insertedItem) {
        var id = insertedItem.id;
    }, failure);

成功插入后,插入项随同步操作所需的其他字段一并返回。使用此信息更新自己的缓存,便于后续更新。

Azure 移动应用 Node.js Server SDK 支持用于开发的动态架构。在动态架构中,可通过在插入或更新操作中指定列,以将这些列添加到表中。建议先关闭动态架构,再将应用程序迁移到生产。

如何:修改数据

类似于 .insert() 方法,应创建 Update 对象,然后调用 .update()。Update 对象必须包含要更新的记录的 ID,此 ID 在读取记录或调用 .insert() 时获取。

var updateItem = {
    id: '7163bc7a-70b2-4dde-98e9-8818969611bd',
    name: 'My New Name'
};

table
    .update(updateItem)
    .done(function (updatedItem) {
        // You can now update your cached copy
    }, failure);

如何:删除数据

若要删除记录,请调用 .del() 方法。在对象引用中传递 ID:

table
    .del({ id: '7163bc7a-70b2-4dde-98e9-8818969611bd' })
    .done(function () {
        // Record is now deleted - update your cache
    }, failure);

如何:对用户进行身份验证

Azure 应用服务支持使用各种外部标识提供者(包括 Microsoft 帐户)对应用用户进行身份验证和授权。你可以在表中设置权限,以便将特定操作的访问权限限制给已经过身份验证的用户。你还可以在服务器脚本中使用已经过身份验证的用户的标识来实施授权规则。有关详细信息,请参阅 Get started with authentication(身份验证入门)教程。

在 Apache Cordova 应用中使用身份验证时,以下 Cordova 插件必须可用:

支持两种身份验证流:服务器流和客户端流。服务器流依赖于提供者的 Web 身份验证界面,因此可提供最简便的身份验证体验。客户端流依赖于提供者和设备特定的 SDK,因此允许与设备特定的功能(例如单一登录)进行更深入的集成。

如何:使用提供程序(服务器流)进行身份验证

若要让移动应用管理应用中的身份验证过程,必须向标识提供者注册应用。然后,需要在 Azure App Service 中配置提供者提供的应用程序 ID 和机密。有关详细信息,请参阅向应用程序添加身份验证教程。

注册标识提供者后,只需使用提供者的名称调用 .login() 方法即可。例如,若要使用 microsoftaccount 登录,请使用以下代码。

client.login("microsoftaccount").done(function (results) {
     alert("You are now logged in as: " + results.userId);
}, function (err) {
     alert("Error: " + err);
});

如果使用的标识提供程序不是 microsoftaccount,请将传递给上述 login 方法的值更改为 aad

在这种情况下,由 Azure 应用服务管理 OAuth 2.0 身份验证流程。它显示所选提供者的登录页,并在使用标识提供者成功登录后生成应用服务身份验证令牌。login 函数在完成时返回一个 JSON 对象,该对象分别在 userId 和 authenticationToken 字段中公开用户 ID 和应用服务身份验证令牌。可以缓存此令牌,并在它过期之前重复使用。

如何:使用提供程序(客户端流)进行身份验证

你的应用还能够独立联系标识提供者,然后将返回的令牌提供给应用服务以进行身份验证。使用此客户端流可为用户提供单一登录体验,或者从标识提供者中检索其他用户数据。

Microsoft 帐户示例

以下示例使用 Live SDK,该 SDK 使用 Microsoft 帐户来支持 Windows 应用商店应用程序的单一登录:

WL.login({ scope: "wl.basic"}).then(function (result) {
      client.login(
            "microsoftaccount",
            {"authenticationToken": result.session.authentication_token})
      .done(function(results){
            alert("You are now logged in as: " + results.userId);
      },
      function(error){
            alert("Error: " + err);
      });
});

这个示例将从 Live Connect 获取一个令牌,并通过调用 login 函数将该令牌提供给你的应用服务。

如何:获取已经过身份验证的用户相关信息

可以使用具有任何 AJAX 库的 HTTP 调用从 /.auth/me 终结点检索身份验证信息。确保将 X-ZUMO-AUTH 标头设置为身份验证令牌。身份验证令牌存储在 client.currentUser.mobileServiceAuthenticationToken 中。例如,若要使用提取 API:

var url = client.applicationUrl + '/.auth/me';
var headers = new Headers();
headers.append('X-ZUMO-AUTH', client.currentUser.mobileServiceAuthenticationToken);
fetch(url, { headers: headers })
    .then(function (data) {
        return data.json()
    }).then(function (user) {
        // The user object contains the claims for the authenticated user
    });

提取可作为 npm 包,或供浏览器从 CDNJS 进行下载。也可以使用 jQuery 或其他 AJAX API 提取信息。数据作为 JSON 对象接收。

如何为外部重定向 URL 配置移动应用服务。

有多种类型的 Apache Cordova 应用程序使用环回功能来处理 OAuth UI 流。Localhost 上的 OAuth UI 流会导致问题,因为默认情况下,身份验证服务只知道如何利用服务。有问题的 OAuth UI 流的示例包括:

  • Ripple 模拟器。
  • 使用 Ionic 的实时重新加载。
  • 在本地运行移动后端
  • 在提供身份验证服务以外的其他 Azure App Service 中运行移动后端。

请遵循以下说明将本地设置添加到配置中:

  1. 登录到 Azure 门户
  2. 选择“所有资源”或“应用服务”,然后单击移动应用的名称。
  3. 单击“工具”
  4. 单击“观察”菜单中的“资源浏览器”,然后单击“转到”。会打开新窗口或选项卡。
  5. 在左侧导航栏中,展开站点的“config”、“authsettings”节点。
  6. 单击“编辑”
  7. 查找“allowedExternalRedirectUrls”元素。它可能被设置为 null 或值数组。将该值更改为以下值:

     "allowedExternalRedirectUrls": [
         "http://localhost:3000",
         "https://localhost:3000"
     ],
    

    将 URL 替换为自己服务的 URL。示例包括 "http://localhost:3000" (适用于 Node.js 示例服务)或 "http://localhost:4400" (适用于 Ripple 服务)。但是,这些 URL 是示例,根据不同的情况(包括示例中提到的服务)可能会有差异。

  8. 单击屏幕右上角的“读/写”按钮。
  9. 单击绿色的“PUT”按钮。

此时会保存设置。在保存完设置之前,请不要关闭浏览器窗口。同时将以下环回 URL 添加到应用服务的 CORS 设置:

  1. 登录到 Azure 门户
  2. 选择“所有资源”或“应用服务”,然后单击移动应用的名称。
  3. “设置”边栏选项卡会自动打开。如果没有打开,请单击“所有设置”。
  4. 在“API”菜单下面单击“CORS”。
  5. 在提供的框中输入想要添加的 URL,然后按 Enter。
  6. 根据需要输入其他 URL。
  7. 单击“保存”保存这些设置。

大约需要 10-15 秒时间才能使新设置生效。

如何注册推送通知

安装 phonegap-plugin-push 即可处理推送通知。在命令行中使用 cordova plugin add 命令,或者在 Visual Studio 内通过 Git 插件安装程序,即可轻松添加此插件。Apache Cordova 应用中的以下代码为设备注册推送通知:

    var pushOptions = {
        android: {
            senderId: '<from-gcm-console>'
        },
        ios: {
            alert: true,
            badge: true,
            sound: true
        },
        windows: {
        }
    };
    pushHandler = PushNotification.init(pushOptions);

    pushHandler.on('registration', function (data) {
        registrationId = data.registrationId;
        // For cross-platform, you can use the device plugin to determine the device
        // Best is to use device.platform
        var name = 'gcm'; // For android - default
        if (device.platform.toLowerCase() === 'ios')
            name = 'apns';
        if (device.platform.toLowerCase().substring(0, 3) === 'win')
            name = 'wns';
        client.push.register(name, registrationId);
    });

    pushHandler.on('notification', function (data) {
        // data is an object and is whatever is sent by the PNS - check the format
        // for your particular PNS
    });

    pushHandler.on('error', function (error) {
        // Handle errors
    });

使用通知中心 SDK 从服务器发送推送通知。永远不要直接从客户端发送推送通知。此做法可能会被用于触发针对通知中心或 PNS 的拒绝服务攻击。PNS 可能会因此类攻击而禁止相关流量。

详细信息

可在 API 文档中找到有关 API 的详细信息。