即便跨设备,也继续用户活动

本主题介绍如何帮助用户恢复他们在电脑上的应用和跨设备执行的操作。

注释

从 2021 年 7 月开始,通过Microsoft帐户(MSA)跨 Windows 设备同步活动历史记录的用户将不再可以选择在时间线中上传新活动。 他们仍然可以使用时间线,并查看其本地电脑上的活动历史记录(有关最近的应用、网站和文件的信息)。 与 AAD 连接的帐户不会受到影响。

用户活动和时间线

我们每天的时间分布在多个设备上。 我们可能会在公共汽车上使用手机,白天使用电脑,然后在晚上使用手机或平板电脑。 从 Windows 10 版本 1803 或更高版本开始,创建 用户活动 会使该活动显示在 Windows 时间线和 Cortana 的“继续之前所做的工作”功能中。 时间线是一个功能丰富的任务视图,它利用用户活动来以时间顺序显示你所处理的内容。 它还可以包括您在不同设备上正在处理的内容。

Windows 时间线图像

同样,将手机链接到 Windows 电脑允许你继续在 iOS 或 Android 设备上执行操作。

UserActivity 视为用户在应用中处理的特定内容。 例如,如果您使用 RSS 阅读器,则 UserActivity 可能是您正在阅读的源。 如果你正在玩游戏,UserActivity 可能是你当前正在玩的关卡。 如果您正在使用音乐应用收听音乐,那么 UserActivity 可能是您正在收听的播放列表。 如果你正在处理文档,UserActivity 可能是你上次工作到的位置,等等。 简而言之,UserActivity 表示应用中的目标,使用户能够恢复他们正在执行的操作。

通过调用 UserActivity.CreateSessionUserActivity 互动时,系统会创建一条历史记录,指示该 UserActivity的开始和结束时间。 随着时间推移,您再次参与该 UserActivity 时,系统会为其记录多条历史记录。

将用户活动添加到应用

UserActivity 是 Windows 中的用户参与单位。 它具有三个部分:用于激活活动所属的应用的 URI、描述活动的视觉对象和元数据。

  1. ActivationUri 用于恢复具有特定上下文的应用程序。 通常,此链接采用方案(例如,“my-app://page2?action=edit”)或 AppUriHandler(例如,http://contoso.com/page2?action=edit)的协议处理程序形式。
  2. VisualElements 公开一个类,该类允许用户使用标题、说明或自适应卡片元素直观地标识活动。
  3. 最后,内容部分 是您可以存储活动元数据的地方,这些元数据用于在特定上下文中对活动进行分组和检索。 这通常以 https://schema.org 数据的形式呈现。

若要向应用添加 UserActivity,请执行以下操作:

  1. 在应用内用户上下文发生更改时生成 UserActivity 对象(例如页面导航、新游戏级别等)
  2. 使用最少的必填字段集填充 UserActivity 对象:ActivityIdActivationUriUserActivity.VisualElements.DisplayText
  3. 将一个自定义协议处理程序添加到您的应用,以便 UserActivity重新激活它。

UserActivity 只需几行代码即可集成到应用中。 例如,假设在 MainPage 类中的 MainPage.xaml.cs 文件内有这段代码(注意:假定为 using Windows.ApplicationModel.UserActivities;):

UserActivitySession _currentActivity;
private async Task GenerateActivityAsync()
{
    // Get the default UserActivityChannel and query it for our UserActivity. If the activity doesn't exist, one is created.
    UserActivityChannel channel = UserActivityChannel.GetDefault();
    UserActivity userActivity = await channel.GetOrCreateUserActivityAsync("MainPage");
 
    // Populate required properties
    userActivity.VisualElements.DisplayText = "Hello Activities";
    userActivity.ActivationUri = new Uri("my-app://page2?action=edit");
     
    //Save
    await userActivity.SaveAsync(); //save the new metadata
 
    // Dispose of any current UserActivitySession, and create a new one.
    _currentActivity?.Dispose();
    _currentActivity = userActivity.CreateSession();
}

上面的 GenerateActivityAsync() 方法中的第一行获取用户的 UserActivityChannel。 这是此应用的活动将发布到的源。 下一行查询名为 MainPage的活动的通道。

  • 每次用户位于应用中的特定位置时,你的应用都应以相同的 ID 为活动命名。 例如,如果应用基于页面,请使用页面的标识符;如果应用是基于文档的,请使用文档的名称(或名称的哈希)。
  • 如果源中存在具有相同 ID 的现有活动,则会从 UserActivity.State 设置为 已发布的通道返回该活动。 如果没有具有该名称的活动,则返回的新活动会将 UserActivity.State 设置为
  • 活动的范围限定于您的应用程序。 无需担心活动 ID 与其他应用中的 ID 相撞。

获取或创建 UserActivity后,请指定其他两个必填字段:UserActivity.VisualElements.DisplayTextUserActivity.ActivationUri

接下来,通过调用 SaveAsync,最后 CreateSession来保存 UserActivity 元数据,这将返回 UserActivitySessionUserActivitySession 是一个对象,可用于管理用户何时实际与 UserActivity进行互动。 例如,当用户离开页面时,应在 Dispose() 上调用 。 在上面的示例中,我们还在调用 Dispose()之前对 _currentActivity 调用 CreateSession()。 这是因为我们将 _currentActivity 设为页面的一个成员字段,并且我们希望在启动新的活动之前停止任何现存的活动(注意:?空条件运算符,它会在执行成员访问之前测试是否为 null)。

由于在这种情况下,ActivationUri 是自定义方案,因此还需要在应用程序清单中注册协议。 这在 Package.appmanifest XML 文件中完成,或使用设计器完成。

若要使用设计器进行更改,请双击项目中的 Package.appmanifest 文件以启动设计器,选择 声明 选项卡,并添加 协议 定义。 目前,需要填写的唯一属性是 Name。 它应与上面指定的 URI 匹配,my-app

现在,我们需要编写一些代码,告诉应用在协议激活应用时该怎么办。 我们将替代 App.xaml.cs 中的 OnActivated 方法,以便将 URI 传递到主页,如下所示:

protected override void OnActivated(IActivatedEventArgs e)
{
    if (e.Kind == ActivationKind.Protocol)
    {
        var uriArgs = e as ProtocolActivatedEventArgs;
        if (uriArgs != null)
        {
            if (uriArgs.Uri.Host == "page2")
            {
                // Navigate to the 2nd page of the  app
            }
        }
    }
    Window.Current.Activate();
}

此代码的作用是检测应用是否已通过协议激活。 如果是这样,系统会检查应用被激活的原因并确定应当采取的措施以继续该任务。 作为一个简单的应用程序,当应用程序启动时,此应用恢复的唯一活动是将你放在次要页面上。

使用自适应卡片改进时间线体验

用户活动显示在 Cortana 和时间线中。 当活动显示在时间轴上时,我们使用 自适应卡片框架 来显示它们。 如果未为每个活动提供自适应卡片,时间线将根据应用程序名称和图标、标题字段和可选说明字段自动创建一个简单的活动卡片。 下面是自适应卡片有效负载及其生成的卡片示例。

自适应卡片 ]

自适应卡片载荷 JSON 字符串示例:

{ 
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", 
  "type": "AdaptiveCard", 
  "version": "1.0",
  "backgroundImage": "https://winblogs.azureedge.net/win/2017/11/eb5d872c743f8f54b957ff3f5ef3066b.jpg", 
  "body": [ 
    { 
      "type": "Container", 
      "items": [ 
        { 
          "type": "TextBlock", 
          "text": "Windows Blog", 
          "weight": "bolder", 
          "size": "large", 
          "wrap": true, 
          "maxLines": 3 
        }, 
        { 
          "type": "TextBlock", 
          "text": "Training Haiti’s radiologists: St. Louis doctor takes her teaching global", 
          "size": "default", 
          "wrap": true, 
          "maxLines": 3 
        } 
      ] 
    } 
  ]
}

将自适应卡片有效负载作为 JSON 字符串添加到 UserActivity,如下所示:

activity.VisualElements.Content = 
Windows.UI.Shell.AdaptiveCardBuilder.CreateAdaptiveCardFromJson(jsonCardText); // where jsonCardText is a JSON string that represents the card

跨平台和服务间集成

如果应用运行跨平台(例如在 Android 和 iOS 上),或者在云中维护用户状态,可以通过 Microsoft Graph发布 UserActivities。 使用 Microsoft 帐户对应用程序或服务进行身份验证后,只需执行两个简单的 REST 调用即可生成 活动历史记录 的对象,并使用上述数据。

概要

可以使用 UserActivity API 使应用显示在时间线和 Cortana 中。

关键 API