Windows 应用商店

将 OneDrive 集成到您的 Windows 应用商店应用中

Tony Champion

下载代码示例

如果您错过了关于云开发的谈话,那么今天您可能无法深入了解云开发。 现在的公有云、私有云、内部云或外部云产品形态各异、大小不一。 但是当谈到用于处理用户文件的面向消费者的应用时,您有可能会关注像 Microsoft OneDrive 这样的云产品。

最近更名的 Microsoft OneDrive 为消费者提供了一种可在任何设备上随处存储、共享和访问个人文件的便利方式。 目前 OneDrive 完全集成到所有 Microsoft 平台中,并且与当前正在使用的大多数其他平台兼容。 可以跨设备轻松共享、同步或访问文档、照片、视频和许多其他类型的文件。 所以,如果您正在构建一款涉及用户文件的应用,那么将 OneDrive 集成到您的应用中应该是一个重要特色。

如果您正在构建 Windows 应用商店应用,您将自动免费获得一定级别的 OneDrive 功能。 在 Windows 8.1 中,您将在包含"文件开启选取器"或"文件保存选取器"合约的实现的文件系统中找到 Windows 应用商店 OneDrive 应用和桌面集成。 这意味着,一旦您使用应用中的文件开启或保存选取器,用户将自动有能力打开文档或将文档保存到他的 OneDrive 帐户。 桌面应用中的开启和保存文件对话框也是如此。

但是,如果我想更好地控制这个交互的工作方式会出现什么情况? 如果您想用另一种不同的格式显示用户数据或在后台处理多个文件的上传或下载,那该怎么办呢? 为了应对这种情况,Microsoft 提供了一个可从任意平台访问的 API 以允许开发人员将 OneDrive 集成到他们的解决方案中。 本篇文章探讨了该 API 并介绍了在您的 Windows 应用商店应用中使用此 API 所涉及的内容。

介绍 Live SDK

Live SDK 推动对 OneDrive 的内容的访问。 Live SDK 的核心是一个基于 JSON 的、在任何平台上都可用的 REST API 的集合。 Live SDK 使用其他平台上的 Windows 应用商店、Windows Phone 应用商店应用和 OAuth 2.0 身份验证的单一登录。 为了帮助开发人员使用 OneDrive 创建成功的应用程序,Microsoft 也发布了针对客户的 SDK。 目前发布的有适用于 Microsoft Windows 和 Windows Phone 平台的 SDK 及适用于 Android 和 iOS 的 SDK。 所有这些 SDK 的链接可在 msdn.microsoft.com/onedrive/dn630256 找到。 也可通过 NuGet (nuget.org/packages/LiveSDK) 添加 Live SDK。

至于 OneDrive,Live SDK 的主要作用是允许以编程方式访问用户帐户内的文件和文件夹。 以下是 SDK 提供的基本服务:

  • 导航文件夹层次结构
  • 创建和删除新文件夹
  • 读取和修改文件夹属性
  • 上传和下载文件
  • 读取和修改文件属性
  • 复制和移动文件和文件夹
  • 获取共享文件和文件夹的链接
  • 设置文件和文件夹的权限

我使用 Visual Studio 2013 更新 2 和 Live SDK 版本 5.6 探索如何使用用 XAML 编写的 Windows 8.1 应用商店应用中的 SDK。 由于适用于大多数平台的针对客户的 SDK 广泛可用,所以可将相同的概念轻松迁移到您所选的语言和平台。

使用 Live SDK 开发应用程序

在您能够使用 Live SDK 开始开发应用程序之前,有几项维护任务需要处理。 因为 Live SDK 不是核心 Windows SDK 的一部分,所以您必须先下载 Live SDK,然后从您的应用程序中为其添加引用。 若要添加引用,只需在 Visual Studio 2013 中右键单击您的解决方案并选择“添加引用”即可。 Live SDK 可在“引用管理器”的“Windows 8.1 扩展”部分中找到,如图 1 所示。

为 Live SDK 添加引用
图 1 为 Live SDK 添加引用

默认情况下,Windows 8.1 应用商店应用在它的 appxmanifest 中应用启用了“Internet (客户端)”功能。 这是使用 Live SDK 时的一项必需功能,并且您的项目也必需将其启用。 为了验证或启用此功能,请在设计器中打开您项目的 appxmanifest 并确保在“功能”选项卡中选中了“Internet (客户端)”。

一旦向您的项目添加了 Live SDK,您将在 Microsoft.Live 命名空间中找到整个 SDK。 但此时使用 SDK 将出现无对象引用错误。 这是因为在可以访问 OneDrive 之前,您必须使用 Live 服务注册应用程序。 根据您进行开发的平台,可通过以下几种方式实现这一目的。 对于 Windows 应用商店应用,您只需将您的应用与 Windows 应用商店应用关联即可。 而最直接的方法就是在 Visual Studio 中使用向导。

若要启动向导,请在“解决方案资源管理器”中,右键单击“应用商店”项目,然后选择“应用商店 | 将应用程序与应用商店关联”。 这将打开向导,其中带有“您需要什么才能继续”的说明。 选择“下一步”,提示您登录与 Windows 应用商店关联的 Microsoft 帐户(若您尚未登录)。 您还可能需要进行第二次验证,比如通过向与您的帐户关联的电话号码发送短消息来接收授权代码。 完成登录过程之后,您将看到与您的帐户关联的所有已保留的应用名称列表,如图 2 所示。 如果这是个新应用,您还可以从此屏幕保留一个新应用名称。 只要您拥有一个要与您的应用关联的名称,选择“下一步”将进入摘要屏幕,单击“关联”即可完成此过程。

将已保留名称与应用关联
图 2 将已保留名称与应用关联

现在您的应用已设置好,准备开始使用 Live SDK。

访问用户的数据

将 OneDrive 集成到您的应用的第一步是获得访问用户信息的功能。 正如前面提到的,Live SDK 使用 0Auth 2.0 进行授权。 但是,除了只验证您的应用外,还有其他几点需要考虑。

合理使用 OneDrive 如果您熟悉开发或开发 Windows 应用商店应用,那您应该知道有相当多的指导原则详细说明了应用中的可做事项和不可做事项。 OneDrive 添加了自己的一套指导原则,也必须将其考虑在内。

上述限制的主要原因是为了避免您在 OneDrive 中破坏用户的信任。 当用户拥有一个存储其个人信息的中央源时,她拥有该源的内在信任,否则将不使用它。 通过使用您的应用访问 OneDrive,用户正将信任扩展到您的应用。 所以,如果您的应用在用户不知情或未经用户同意的情况下开始删除用户的数据,您将破坏这种信任,不仅影响用户对您的应用的看法,而且影响她对 OneDrive 的 看法。 因此,您应该格外留意您的应用与 OneDrive 互动的方式,尤其是执行更新或删除用户信息功能的情况下。 关于这些指导原则的描述可在 bit.ly/1rQ8iXK 找到。

使用单一登录 当在 Windows 应用商店应用中使用 Live SDK 时,Microsoft 建议您使用单一登录 (SSO) 功能。 就像 Live SDK 一样,为您的应用添加 SSO 时应注意其他几点要求,比如隐私声明和帐户设置面板。 为您的应用添加必需组件的步骤的完整详情可在 bit.ly/TJvTxB 找到。

在您的应用准备好 SSO 后,使用 LiveAuthClient 类实例登录用户的帐户。 LiveAuthClient 拥有一个 LoginAsync 方法,它将使用当前登录到 Windows 8.1 设备的 Microsoft 帐户的凭据。 如果登录成功,返回的 LiveLoginResult 对象将包含一个 LiveConnectSession 实例,该实例将用于对 Live SDK 的所有调用。 以下代码将登录用户并返回 Session 对象:

LiveAuthClient authClient = new LiveAuthClient();
LiveLoginResult authResult = 
  await authClient.LoginAsync(new List<string>() {
  "wl.signin",
  "wl.basic", "wl.skydrive", "wl.skydrive_update" });
if (authResult.Status == LiveConnectSessionStatus.Connected)
{
  // 添加代码以处理“会话”属性中保留的会话
}

范围 您可能已经注意到之前代码中使用了像“wl.signin”这样的范围。 当您的应用登录用户的帐户时,必须确认它需要的访问类型。 如果您尝试使用部分未请求访问的 API,则您的尝试将会失败。 对于 Windows 应用程序应用,这与在 appxmanifest 包的功能部分中尝试使用未请求访问的部分 Windows SDK 没有任何差别。

本文中的示例将只使用四个范围。 wl.signin 范围允许您利用应在 Windows 应用商店应用中使用的 SSO 行为。 wl.basic 范围允许访问有关用户的一些基本信息。

对于 OneDrive 应用程序,只有两个其他范围需要您特别注意:wl.skydrive 和 wl.skydrive_update。 正如其名所示,读取和浏览访问用户的 OneDrive 帐户需要 wl.skydrive。 如果您的应用需要下载文件、创建或删除文件夹或更改对象属性的功能,则使用 wl.skydrive_update 范围。 此范围还会授予您对 OneDrive 的读取权限,所以无需将 wl.skydrive 和 wl.skydrive_update 都包含到访问列表中。

为了保持与使用之前名称的应用的向后兼容性,OneDrive 范围名称未更改。 但是,对于看到几个使用 OneDrive 名称的其他范围出现在 API 的未来版本中,我也不会感到意外。

因为 Live SDK 涵盖的范围不仅仅包括 OneDrive,还有许多本文将不讨论的其他范围。 您可以在 msdn.microsoft.com/library/dn631845 找到完整的描述列表。

获得用户许可 用户第一次运行请求访问其 OneDrive 帐户的应用时,会提示他授予该应用对登录调用中提供的范围的访问权限。 图 3 显示了 Windows 应用商店中这类提示的示例。 一旦用户授予权限,只要不更改范围列表,系统将不会再提示他。 如果应用的已更新版本请求 API 的其他功能,系统将再次提示用户授予权限。

请求用户同意访问 OneDrive
图 3 请求用户同意访问 OneDrive

OneDrive 上的对象

OneDrive API 将一切视为对象。 无论是文件夹、照片还是电子表格,存储在 OneDrive 上的所有东西都有一组相似的属性,并且他们共享 API 调用。 每个对象都有属性的集合,并且其中许多都有子对象的集合。 本文重点关注的对象类型为:文件夹、文件、相册和照片。 在 msdn.microsoft.com/library/dn631843 可找到可用对象的完整列表,其中包含可用对象的说明和使用情况。

一旦您的应用从 LiveAuthClient 的 LoginAsync 方法获得了一个 LiveConnectionSession 实例,该会话实例可用于创建 LiveConnectClient 类的实例,其中包含用于与 OneDrive 互动的所有 API 调用。 以下示例显示了 LiveConnectClient 实例的创建过程和在 OneDrive 上对用户根文件夹对象的查询过程,其中可使用 “me/skydrive” 路径检索用户根文件夹对象:

public async Task<object> GetRootFolder()
{
  LiveConnectClient client = new LiveConnectClient(_session);
  LiveOperationResult liveOpResult = 
    await client.GetAsync("me/skydrive");
  dynamic dynResult = liveOpResult.Result;
  return dynResult;
}

此代码在运行时使用动态关键字创建基础 JSON 格式化字符串的类实例。 尽管这个代码使用起来快速方便,但请记住,您可能会碰到一些限制,要求使用更正式的类结构。

从 GetAsync 方法返回的结果将包含请求对象的所有属性。 图 4 显示了一个针对用户的根文件夹返回的 JSON 格式化字符串示例。

图 4 从文件夹对象查询返回的 JSON

{
  "id": "folder.abced3a35e6d1b",
  "from": {
    "name": null,
    "id": null
  },
  "name": "SkyDrive",
  "description": "",
  "parent_id": null,
  "size": 2957188732,
  "upload_location": 
    "https://apis.live.net/v5.0/folder.abced3a35e6d1b/files/",
  "comments_count": 0,
  "comments_enabled": false,
  "is_embeddable": false,
  "count": 25,
  "link": "https://onedrive.live.com?cid=abced3a35e6d1b",
  "type": "folder",
  "shared_with": {
    "access": "Just me"
  },
  "created_time": null,
  "updated_time": "2014-06-13T18:00:54+0000",
  "client_updated_time": "2012-10-22T19:50:04+0000"
}

当在 OneDrive 内进行查询时,创建一个更具体的查询很有用。 例如,执行以下代码将返回根目录中的所有子对象:

LiveOperationResult liveOpResult = await client.GetAsync("me/skydrive/files");

这包括文件夹和文件,并且可能是大量数据。

如果只想查看此目录中的一个照片列表,该怎么办呢? 可使用筛选器查询参数完成。 除了筛选,OneDrive API 还支持多个不同类型的查询参数,例如限制、抵消和偏移。 此参数允许您只获取您所需的数据,不仅限制必须下载的数据,而且限制处理返回数据所需的代码量。

例如,以下查询只在根目录下返回照片列表,免除了编写代码以从文件夹中分离照片的必要:

LiveOperationResult liveOpResult =
  await client.GetAsync("me/skydrive/files?filter=photos");

查询参数及其使用情况的完整列表可在 msdn.microsoft.com/library/dn631842 找到。

对文件夹进行操作

无论您要对哪种类型的文件系统进行操作,逻辑起点都与文件夹结构相关。 在查询文件夹时,您可以使用两种不同类型的标识符:友好路径(如 me/skydrive)或文件夹 id(看上去就像 folder.abcde86dfb3a35e6d1b.ABCDED3A35E6D1B!532)。 如果您要查询文件夹的子对象列表,您可以向路径追加 “/files”。 例如,以下代码将返回指定文件夹 id 的所有文件、文件夹和相册的列表:

LiveOperationResult liveOpResult =
  await client.GetAsync("folder.abcde86dfb3a35e6d1b.ABCDED3A35E6D1B!532/files");

OneDrive 包含两类文件夹对象:文件夹和相册。 用户的根 OneDrive 目录下的相册可以视为特殊类型的文件夹。 相册可以包含照片和视频及文件夹结构和其他文件。

理解文件夹和相册的区别很重要,因为以下查询将只返回您根目录下的文件夹,而忽略所有相册。 这可能产生意想不到的结果:

LiveOperationResult liveOpResult =
  await client.GetAsync("me/skydrive/files?filter=folders");

若要同时返回文件夹和相册,请使用筛选值“folders,albums”。

之前的查询允许您通过获取每个文件夹的子文件夹来浏览用户的 OneDrive 帐户的整个文件夹结构。 本文的关联下载包含示例应用、MyPhotoAlbum 和一个包含两个页面的 XAML Windows 应用商店应用。 第一页 FolderPage 让您浏览您的目录结构并在 GridView 中显示结果。 所有 Live SDK 调用都包装在 OneDriveDataProvider 类中。

图 5 显示了遍历文件夹结构的方法,通过传递当前文件夹 id 并将“folders,albums”作为筛选值来实现。 如果没有文件夹 id,则方法默认为根目录。

图 5 GetFolderItems 方法

public async Task<List<object>> 
  GetFolderItems(string path, string filter)
{
  if (_session == null)
  {
    await InitProvider();
  }
  if (String.IsNullOrEmpty(path))
  {
    path = "me/skydrive";
  }
  if (!String.IsNullOrEmpty(filter))
  {
    filter = "?filter=" + filter;
  }
  LiveConnectClient client = new LiveConnectClient(_session);
  LiveOperationResult liveOpResult =
    await client.GetAsync(path + "/files" + filter);
  dynamic dynResult = liveOpResult.Result;
  return new List<object>(dynResult.data);
}

图 6 显示了 FolderPage 中返回的结果的示例。 选择一个子文件夹,可通过将该子文件夹用作参数而导航至相同的 FolderPage。 这允许导航堆栈保留后退功能以回升文件夹结构。

FolderPage
图 6 FolderPage

如果您已请求使用 wl.skydrive_update 范围更新访问,您也可以使用 API 创建和删除文件夹。 一个文件夹只有三个属性可让您创建或更改:名称、说明和排序依据。 在创建文件夹时,您必须通过路径或 id 指定一个父目录并向 JSON 数组至少提供一个名称。 以下是创建新文件夹所需的 JSON 示例:

{
 "name": "My Favorite Photos",
 "description": "A folder full of my favorite photos."
}

SDK 通过 LiveConnectClient 的 PostAsync 方法创建新文件夹。 图 7 显示了用于创建新文件夹的方法。

图 7 CreateFolder 方法

public async Task<bool> CreateFolder(string path, string name)
{
  try
  {
    var folderData = new Dictionary<string, object>();
    folderData.Add("name", name);
    LiveConnectClient liveClient = new LiveConnectClient(_session);
    LiveOperationResult operationResult =
      await liveClient.PostAsync(path, folderData);
    dynamic result = operationResult.Result;
    return true;
  }
  catch (LiveConnectException exception)
  {
    return false;
  }
}

使用 DeleteAsync 方法将文件夹成功删除,此方法可用来删除文件。 尤为重要的是,切记保持 OneDrive 的完整性并谨慎使用任何删除功能:

LiveOperationResult operationResult = await liveClient.DeleteAsync(path);

处理文件

虽然 GetAsync 方法将返回文件的属性,但不返回文件本身。 从 OneDrive 上获取文件的唯一方法是下载。 Windows 应用商店应用的 Live SDK 通过创建下载后台任务(在不使您的设备停止响应的同时异步处理下载)来进行下载。 以下代码可用于从 OneDrive 下载文件:

try
{
  LiveConnectClient liveClient = new LiveConnectClient(_session);
  LiveDownloadOperation op =
    await liveClient.CreateBackgroundDownloadAsync(filePath);
  var result = await op.StartAsync();
  // 处理结果
}
catch
{
  // 处理错误
}

返回后台下载操作后,必须通过调用 LiveDownload­Operation 实例的 StartAsync 方法开始下载。

与下载文件相似,在 OneDrive 中添加或更新文件的唯一方法是上传。 若要上传文件,您的应用必须请求使用 wl.skydrive_update 范围进行写入访问。 CreateBackgroundUploadAsync 方法采用文件夹路径、文件名以及包含文件和覆盖选项的流。 如果文件已经存在,覆盖选项可以覆盖原始文件,也可以保留原始文件并对正在上传的新文件重命名。 对于文件夹更新功能,在使用此功能时注意不要无意中损坏文件。 以下代码是如何上传文件的一个示例:

try
{
  LiveConnectClient liveClient = new LiveConnectClient(_session);
  LiveUploadOperation op = await liveClient.CreateBackgroundUploadAsync(
    path, filename, fileStream, OverwriteOption.Rename);
  var result = await op.StartAsync();
  // 处理结果
}
catch
{
  // 处理错误
}

在上传文件前,很重要的一点是确保用户有足够的空间来存储新文件。 您可以使用 GetObjectAsync 方法中的路径“me/skydrive/quota”确认可用空间量。 这将返回两个属性、配额和可用空间,您可以通过它们计算用户帐户剩余的字节数。

API 中的其他两个功能在处理文件时也派得上用场。 如果您要创建文件的副本,则可以下载文件,然后使用另一个不同的名称将其上传。 但是,这个非常简单的操作可能会消耗许多带宽。 另外,如果您要复制整个文件夹或将子文件夹移动到不同的父文件夹,又该怎么办呢? 使用下载和上传进行文件操作的代码和带宽将使操作变得非常繁琐。 为了使用这些功能,OneDrive API 具有移动和复制命令:MoveAsync 和 CopyAsync。 两个命令使用两个参数:要移动的对象(文件或文件夹)和目标路径。 图 8 显示了用于复制文件的方法。

图 8 复制文件

public async Task<bool> CopyObject(string path, string destination)
{
  if (_session == null)
  {
    await InitProvider();
  }
  try
  {
    LiveConnectClient liveClient = new LiveConnectClient(_session);
    LiveOperationResult operationResult =
      await liveClient.CopyAsync(path, destination);
    return true;
  }
  catch (LiveConnectException exception)
  {
    return false;
  }
}

总结

一篇文章只能涵盖这么多有关 API 的内容。 Live SDK 包含许多其他功能,尤其是处理照片和视频方面的功能。 如果您正在寻找将 OneDrive 集成到您的解决方案中的办法,探索这些其他功能将非常有帮助。 Microsoft 已经创建了 OneDrive 开发中心,在 dev.onedrive.com 中为您提供了所有 OneDrive API 相关事项的单一访问点。

无论您是在创建 Windows 应用商店应用、Windows Phone 应用商店应用,还是为需要访问用户文件的任何其他平台创建应用,添加 OneDrive 是将您的应用集成到用户日常文件的好方法,通过通过授予用户访问最重要文件的权限来实现。 所以,在您构建强大的 UX 时,请务必将 OneDrive 包括在内。


Tony Champion 是 Champion DS 的总裁、Microsoft MVP,同时也是社区中活跃的演说家、博主和作者。他在 tonychampion.net 拥有一个博客,并可将电子邮件发送至 tony@tonychampion.net 与他联系。

衷心感谢以下 Microsoft 技术专家对本文的审阅:Mimi Sasouvanh
Mimi Sasouvanh 是 Microsoft 操作系统团队内容小组的内容开发人员,从事 OneDrive 开发、Azure 智能系统服务和其他方面的写作。 她在工作之余喜欢陪家人、干园艺活和素描。