Xamarin 中的 watchOS 主动建议

本文介绍如何使用 watchOS 3 应用中的“主动建议”让系统主动向用户自动呈现有用的信息,从而提高参与度。

作为 watchOS 3 的新功能,“主动建议”通过在适当的时候主动向用户自动呈现有用的信息,为用户提供了与 Xamarin.iOS 应用互动的新方法。

关于主动建议

作为 watchOS 3 的新功能,NSUserActivity 包含一个 MapItem 属性,允许应用提供可在其他上下文中使用的位置信息。 例如,如果应用显示酒店评论并提供 MapItem 位置,则如果用户切换到地图应用,其刚刚查看的酒店的位置就会可用。

应用使用一系列技术(例如 NSUserActivity、MapKit、媒体播放器和 UIKit)向系统公开此功能。 此外,通过为应用提供主动建议支持,可以免费获取更深入的 Siri 集成。

基于位置的建议

NSUserActivity 类是 watchOS 3 的新功能,它包含一个 MapItem 属性,允许开发人员提供可在其他上下文中使用的位置信息。 例如,如果应用显示餐厅评论,开发人员可以将 MapItem 属性设置为用户在应用中查看的餐厅位置。 如果用户切换到地图应用,则餐厅的位置将自动可用。

如果应用支持应用搜索,则可以使用 CSSearchableItemAttributesSet 类的新地址组件来指定用户可能想要访问的位置。 通过设置 MapItem 属性,其他属性会自动填充。

除了设置地址组件属性的 LatitudeLongitude 外,建议应用也提供 NamedLocationPhoneNumbers 属性,以便 Siri 可以启动对位置的调用。

上下文 Siri 提醒

允许用户使用 Siri 快速发出提醒,以便稍后在应用中查看他们当前正在查看的内容。 例如,如果他们正在应用中查看餐厅评论,则可以调用 Siri 并说“回家后提醒我”。Siri 会生成提醒,其中包含指向应用中评论的链接。

实现主动建议

向 Xamarin.iOS 应用添加主动建议支持通常与实现几个 API 或扩展应用可能已实现的一些 API 一样简单。

主动建议主要通过三种方式与应用配合使用:

  • NSUserActivity - 可帮助系统了解用户当前在屏幕上使用的信息。
  • 位置建议 - 如果应用提供或使用基于位置的信息,这些 API 扩展提供了跨应用共享此信息的新方法,

并且通过实现以下内容在应用中受支持:

  • 上下文 Siri 提醒 - iOS 10 中扩展了 NSUserActivity,允许 Siri 快速发出提醒,以便稍后查看用户当前在应用中查看的内容。
  • 位置建议 - iOS 10 增强了 NSUserActivity,以捕获应用内查看的位置,并在系统中的许多位置推广它们。
  • 上下文 Siri 请求 - NSUserActivity 为 Siri 提供应用内呈现的信息的上下文,以便用户可以通过从应用内调用 Siri 来获得方向或拨打电话。

所有这些功能都有一个共同点,它们都以一种形式或另一种形式使用 NSUserActivity 来提供其功能。

NSUserActivity

如上所述,NSUserActivity 可帮助系统了解用户当前在屏幕上使用的信息。 NSUserActivity 是一种轻型状态缓存机制,用于在用户浏览应用时捕获用户的活动。 例如,看看餐厅应用:

餐厅应用

通过以下交互:

  1. 当用户使用应用时,会创建一个 NSUserActivity,以便稍后重新创建应用的状态。
  2. 如果用户搜索餐厅,则会遵循相同的创建活动模式。
  3. 同样,当用户查看结果时。 在最后一种情况下,用户正在查看位置,在 iOS 10 中,系统更了解某些概念(如位置或通信交互)。

仔细看看最后一个屏幕:

NSUserActivity 有效负载

在这里,应用正在创建一个 NSUserActivity 并且已填充了信息,以便稍后重新创建状态。 该应用还包含一些元数据,例如位置的名称和地址。 创建此活动后,应用会让 iOS 知道它代表用户的当前状态。

然后,应用决定是否无线会 Handoff 播发该活动,将其保存为位置建议的临时值,或添加到设备上的聚焦索引,以便在搜索结果中显示。

有关 Handoff 和聚焦搜索的详细信息,请参阅我们的 Handoff 简介iOS 9 新搜索 API 指南。

创建活动

在创建活动之前,需要创建一个活动类型标识符来标识它。 活动类型标识符是添加到应用的 Info.plist 文件的 NSUserActivityTypes 数组中的一个短字符串,用于唯一识别给定的用户活动类型。 对于应用支持并向应用搜索公开的每个活动,数组中都会有一个条目。 有关更多详细信息,请参阅创建活动类型标识符参考

看看一个活动示例:

// Create App Activity
var activity = new NSUserActivity ("com.xamarin.platform");

// Define details
var info = new NSMutableDictionary ();
info.Add(new NSString("link"),new NSString("http://xamarin.com/platform"));

// Populate Activity
activity.Title = "The Xamarin Platform";
activity.UserInfo = info;

// Enable capabilities
activity.EligibleForSearch = true;
activity.EligibleForHandoff = true;
activity.EligibleForPublicIndexing = true;

// Inform system of Activity
activity.BecomeCurrent();

使用活动类型标识符创建新活动。 接下来,将创建定义活动的一些元数据,以便以后可以还原此状态。 然后,为活动提供有意义的标题并附加到用户信息。 最后,启用某些功能,并将活动发送到系统。

通过进行以下更改,可以进一步增强上面的代码,以包括为活动提供上下文的元数据:

...

// Provide context
var attributes = new CSSearchableItemAttributeSet ("com.xamarin.location");
attributes.ThumbnailUrl = myThumbnailURL;
attributes.Keywords = new string [] { "software", "mobile", "language" };
activity.ContentAttributeSet = attributes;

// Inform system of Activity
activity.BecomeCurrent();

如果开发人员的网站能够显示与应用相同的信息,则应用可以包含 URL,并且内容可以显示在未安装应用的其他设备上(通过 Handoff):

// Restore on the web
activity.WebPageUrl = new NSUrl("http://xamarin.com/platform");

还原活动

若要响应用户点击应用的搜索结果 (NSUserActivity),请编辑 AppDelegate.cs 文件并替代 ContinueUserActivity 方法。 例如:

public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{

    // Take action based on the activity type
    switch (userActivity.ActivityType) {
    case "com.xamarin.platform":
        // Restore the state of the app here...
        break;
    }

    return true;
}

确保这是与上面创建的活动相同的活动类型标识符 (com.xamarin.platform)。 应用使用存储在 NSUserActivity 中的信息将状态还原回用户离开的位置。

创建活动的好处

通过上面提供的最少量代码,应用现在可以利用三个新的 iOS 10 功能:

  • Handoff
  • 聚焦搜索
  • 上下文 Siri 提醒

以下部分将介绍如何启用另外两项新的 iOS 10 功能:

  • 位置建议
  • 上下文 Siri 请求

基于位置的建议

以上面的餐厅搜索应用为例。 如果它已实现 NSUserActivity 并正确填充了所有元数据和属性,则用户将能够执行以下操作:

  1. 在应用中找到一家想要与朋友见面的餐厅。
  2. 如果用户切换到“地图”应用,则餐厅的地址将自动建议为目的地。
  3. 这甚至适用于第三方应用(支持 NSUserActivity),因此用户可以切换到拼车应用,餐厅的地址也会自动建议为目的地。
  4. 它还为 Siri 提供上下文,因此用户可以在餐厅应用中调用 Siri 并询问“获取路线…”,Siri 将提供用户正查看的餐厅的路线。

以上所有功能都有一个共同点,它们都指示了建议最初的来源。 在上面的例子中,它是一个虚构的餐厅评论应用。

watchOS 3 经过增强,可通过对现有框架进行多项小型修改和添加,为应用启用此功能:

  • NSUserActivity 具有用于捕获在应用内查看的位置信息的其他字段。
  • 对 MapKit 和 CoreSpotlight 进行了一些添加以捕获位置。
  • 系统中的 Siri、地图、多任务处理和其他应用都添加了位置感知功能。

若要实现基于位置的建议,请从上面显示的相同活动代码开始:

// Create App Activity
var activity = new NSUserActivity ("com.xamarin.platform");

// Define details
var info = new NSMutableDictionary ();
info.Add(new NSString("link"),new NSString("http://xamarin.com/platform"));

// Populate Activity
activity.Title = "The Xamarin Platform";
activity.UserInfo = info;

// Enable capabilities
activity.EligibleForSearch = true;
activity.EligibleForHandoff = true;
activity.EligibleForPublicIndexing = true;

// Provide context
var attributes = new CSSearchableItemAttributeSet ("com.xamarin.location");
attributes.ThumbnailUrl = myThumbnailURL;
attributes.Keywords = new string [] { "software", "mobile", "language" };
activity.ContentAttributeSet = attributes;

// Restore on the web
activity.WebPageUrl = new NSUrl("http://xamarin.com/platform");

// Inform system of Activity
activity.BecomeCurrent();

如果应用使用 MapKit,则只需将当前映射 MKMapItem 添加到活动即可:

// Save MKMapItem location
activity.MapItem = myMapItem;

如果应用未使用 MapKit,则可以采用应用搜索并为位置指定以下新属性:

// Provide context
var attributes = new CSSearchableItemAttributeSet ("com.xamarin.location");
...

attributes.NamedLocation = "Apple Inc.";
attributes.SubThoroughfare = "1";
attributes.Thoroughfare = "Infinite Loop";
attributes.City = "Cupertino";
attributes.StateOrProvince = "CA";
attributes.Country = "United States";
attributes.Latitude = 37.33072;
attributes.Longitude = 122.029674;
attributes.PhoneNumbers = new string[]{"(800) 275-2273"};
attributes.SupportsPhoneCalls = true;
attributes.SupportsNavigation = true;

详细看看上述代码。 首先,每个实例都需要位置的名称:

attributes.NamedLocation = "Apple Inc.";

然后,基于文本的实例(如 QuickType 键盘)需要基于文本的说明:

attributes.SubThoroughfare = "1";
attributes.Thoroughfare = "Infinite Loop";
attributes.City = "Cupertino";
attributes.StateOrProvince = "CA";
attributes.Country = "United States";

纬度和经度是可选的,但请确保将用户路由到应用要向其发送的确切位置:

attributes.Latitude = 37.33072;
attributes.Longitude = 122.029674;

通过设置电话号码,应用可以访问 Siri,因此用户可以通过说“给这个地方打电话”之类的话从应用调用 Siri:

attributes.PhoneNumbers = new string[]{"(800) 275-2273"};

最后,应用可以指示实例是否适合导航和电话呼叫:

attributes.SupportsPhoneCalls = true;
attributes.SupportsNavigation = true;

活动最佳做法

Apple 建议在处理活动时采用以下最佳做法:

  • 使用 NeedsSave 进行延迟有效负载更新。
  • 确保保持对当前活动的强引用。
  • 仅传输包含足够信息以还原状态的小型有效负载。
  • 通过使用反向 DNS 表示法指定活动类型标识符,确保它们是唯一的和描述性的。

使用位置建议

下一部分将介绍使用来自系统其他部分(如“地图”应用)或其他第三方应用的位置建议。

路线规划应用和位置建议

本部分将介绍如何直接从路线规划应用中使用位置建议。 若要使路线规划应用添加此功能,开发人员将按如下所示利用现有的 MKDirectionsRequest 框架:

  • 在多任务处理中推广应用。
  • 将应用注册为路线规划应用。
  • 处理使用 MapKit MKDirectionsRequest 对象启动应用。
  • 让 watchOS 能够学习根据用户参与度推荐应用。

当应用使用 MapKit MKDirectionsRequest 对象启动时,它应该自动开始向用户提供前往请求位置的路线,或者提供一个用户界面,让用户可以轻松地开始获取路线。 例如:

using System;
using Foundation;
using UIKit;
using MapKit;
using CoreLocation;

namespace MonkeyChat
{
    [Register ("AppDelegate")]
    public class AppDelegate : UIApplicationDelegate, IUISplitViewControllerDelegate
    {
        ...

        public override bool OpenUrl (UIApplication app, NSUrl url, NSDictionary options)
        {
            if (MKDirectionsRequest.IsDirectionsRequestUrl (url)) {
                var request = new MKDirectionsRequest (url);
                var coordinate = request.Destination?.Placemark.Location?.Coordinate;
                var address = request.Destination.Placemark.AddressDictionary;
                if (coordinate.IsValid()) {
                    var geocoder = new CLGeocoder ();
                    geocoder.GeocodeAddress (address, (place, err) => {
                        // Handle the display of the address

                    });
                }
            }

            return true;
        }
    }
}

详细看看此代码。 它测试它是否是有效的目的地请求:

if (MKDirectionsRequest.IsDirectionsRequestUrl(url)) {

如果是,则从 URL 创建 MKDirectionsRequest

var request = new MKDirectionsRequest(url);

可以向应用发送没有地理坐标的地址,这是 watchOS 3 中的新功能,但这会导致开发人员需要对地址进行编码:

var geocoder = new CLGeocoder();
geocoder.GeocodeAddress(address, (place, err)=> {
    // Handle the display of the address

});

总结

本文介绍了主动建议,并介绍了开发人员如何使用它们来驱动适用于 watchOS 的 Xamarin.iOS 应用的流量。 它介绍了实现主动建议的步骤并提供了使用指南。