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

本主题介绍如何帮助用户继续执行他们之前在其电脑上及不同设备的应用中所执行的操作。

注意

从 2021 年 7 月开始,通过其 Microsoft 帐户 (MSA) 跨其 Windows 设备共享了活动历史记录的用户将无法再在时间线中删除新活动。 他们将仍可在其本地电脑上使用时间线并查看其活动历史记录(最近使用的应用、网站和文件的相关信息)。 AAD 连接的帐户将不受影响。

用户活动和时间线

我们每天很可能会使用多台设备。 我们可能会在公共汽车上使用手机,白天工作时会使用电脑,晚上休息娱乐时或许会使用手机或平板电脑。 从 Windows 10 版本 1803 或更高版本开始,创建用户活动会使该活动显示在 Windows 时间线和 Cortana 的“我离开的位置”功能中。 时间线是一个丰富的任务视图,它利用“用户活动”显示你正在执行的操作的时间顺序视图。 它还包括你在各种不同设备上执行的操作。

Windows 时间线 映像

同样,将手机链接到 Windows 电脑,可继续执行之前在 iOS 或 Android 设备上的操作。

可将 UserActivity 看成是用户在应用中正在处理的具体内容。 例如,如果正在使用 RSS 阅读器,则 UserActivity 可以是正在阅读的内容源。 如果正在玩游戏,则 UserActivity 可以是正在玩的级别。 如果正在听音乐,则 UserActivity 可以是正在收听的播放列表。 如果正在处理文档,则 UserActivity 可以是离开文档时的位置,以此类推。 简而言之,UserActivity 表示应用内的一个目标,通过它,用户能够继续执行之前执行的操作。

当通过调用 UserActivity.CreateSession 参与某个 UserActivity 时,系统会创建历史记录,指示该 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 设置为 New
  • 活动的作用域为相应的应用。 不必担心活动 ID 与其他应用中的 ID 产生冲突。

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

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

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

若要使用设计器进行更改,可双击项目中的 Package.appmanifest 文件以启动设计器,选择声明选项卡,并添加协议定义。 目前仅需要填写名称属性。 它应该与我们上面指定的 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