此文章由机器翻译。

微软商店

使用地理围栏构建能感知位置的应用程序

Tony Champion

下载代码示例

不断增加的移动设备通过推动位置感知应用程序的创建。应用程序知道和反应到用户的位置的机会几乎是无限的。Windows 8 包括地理位置从一开始,为开发人员提供简单的方法来确定设备的当前的位置。Windows 模拟器甚至包括用于测试此功能的支持。与 Windows 8.1 地理围墙的概念已经扩展到这些 Api。

一个地点坐标是一个定义的区域,周围与 Windows 可以注册,所以应用程序可以接收通知,当设备进入或离开该区域的 GPS 位置。让我们说你打很多房子电话的服务技术,使在某一天的人员。如果该应用程序,用于管理您的约会可以自动向房主发送一条短信,你五分钟的路程的时候吗?或者,假设一个游乐园想宣布存在的字符,但仅限于某些附近的字符的范围内的人,以限制可能出现的人的数目。可能性是无穷无尽的。

这篇文章将探讨使用 Windows 8.1 中的 geofences。然而,地理围墙 API 也同 Windows Phone 8.1,这意味着你可以在这两个平台上执行相同的功能。您将学习如何将 geofences 添加到您的基于位置的应用程序,以及如何处理事件时应用程序是在前景,以及如何处理的通知,该应用程序时在后台。

添加地理位置的支持

因为 geofences 是Windows SDK中的地理定位 API 的一部分,必须向您的应用程序添加对此 API 支持之前您可以使用它。幸运的是,Windows 应用商店应用程序需要很少的设置,使用地理位置。事实上,唯一的要求是包 appxmanifest 必须包括定位能力。若要添加此,在设计器中打开该解决方案的 appxmanifest 和"位置"签到功能选项卡,如中所示图 1

启用定位能力
图 1 启用定位能力

一旦此功能已添加到项目中,应用程序就能够通过地理位置 API 访问 Windows 位置服务,如果授予用户的权限。这种能力也将权限部分添加到应用程序的设置的魅力,使用户可以启用和禁用对该设备的位置的访问,如中所示图 2

权限设置
图 2 权限设置

除了个别应用程序级别上的位置服务访问权限授予,Windows 可以禁用整个设备的定位服务。位置服务启用默认情况下,在 Windows 中,但用户或系统管理员可以自由地更改此去控制面板 |硬件和声音 |位置设置。

因为有几个不同的场景可能会影响应用程序的访问设备的位置,它是重要的您的应用程序知道对此访问权限的更改时。SDK 允许应用程序监视其位置服务通过在 Windows.Devices.Enumeration 命名空间中的 DeviceAccessInformation 类中公开事件的访问。通过 CreateFromDeviceClass,以指定要在其的信息的硬件设备 DeviceClass 枚举的静态方法创建 DeviceAccessInformation 类的一个实例。定位服务,此值是 DeviceClass.Location。 在创建后的 DeviceAccessInformation 实例,可以确定从应用属性的当前访问级别和侦听通过 AccessChanged 事件,更改其访问权限如下所示:

DeviceAccessInformation deviceAccess =
  DeviceAccessInformation.CreateFromDeviceClass(DeviceClass.Location);
DeviceAccessStatus currentStatus = deviceAccess.CurrentStatus;
// Setup geolocation based on status
// Listen for access changes
deviceAccess.AccessChanged += deviceAccess_AccessChanged;

应用属性与 AccessChanged 事件均得到一个 DeviceAccessStatus 枚举,描述当前的访问级别。图 3 显示了可用的值和它们的定义。

图 3 AccessChanged 事件

private void deviceAccess_AccessChanged(
  DeviceAccessInformation sender, DeviceAccessChangedEventArgs args)
{
  switch (args.Status)
  {
    case DeviceAccessStatus.Allowed:
      // Access to the device is allowed
      break;
    case DeviceAccessStatus.DeniedByUser:
      // Denied by user when prompted or thru Permissions settings
      break;
    case DeviceAccessStatus.DeniedBySystem:
      // Denied at the system level from the Control Panel
      break;
    case DeviceAccessStatus.Unspecified:
      // Unknown reason for access to the device
      break;
  }
}

确定位置

如果你要建立一个使用一个地点坐标的位置感知应用程序,你需要能够确定用户的位置。虽然这不一定需要执行 geofences,您将看到它派上用场的地点坐标事件在验证时的本文中稍后。

Windows SDK公开尝试通过几种方法确定设备的当前的 GPS 位置定位器类。Windows.Devices.Geolocation 命名空间中,可以发现定位器和位置的所有类。在第一次使用定位器类必须在 UI 线程的应用程序,因为 Windows 会提示用户输入使用定位服务的权限。每设备只有一次提示用户,他们可以更改此设置在任何时候通过使用的权限设置描述早些时候。因此,如果用户阻止原始请求或禁用设置魅力的许可,不能以编程方式更改回来的访问,必须依靠 UI 通知,提示用户改变它自己。

要确定设备的当前的位置,定位器具有一个 GetGeopositionAsync 方法,返回一个 Geoposition 对象。此对象包含一个坐标系实例坐标属性包含由位置服务返回的信息中。可以说是信息在一个坐标系类中的三个最重要的棋子是经度,纬度和海拔的当前的 GPS 位置。在 Windows 8.1,这些载于点属性,它是一个 Geopoint 实例。坐标系类的纬度、 经度和海拔高度属性是有向后兼容,但点属性应该用于前进。

有几个其他宝贵件坐标系类中的信息,是有帮助的 geofences 处理。最重要的是精度属性,定义 GPS 精度在米。定位器类使用 Windows 位置服务来确定当前所在的位置。位置服务使用几种不同的方法来做到这一点。最准确的方法是当该设备已启用 GPS 无线电和接收信号。如果这不是可用的位置服务将尝试使用该设备的 Wi-Fi 连接的位置。最后,它将尝试使用 IP 解析,如果该设备不会积极的 Wi-Fi 连接不太准确的方法。显然,目前的定位精度是 geofences 在您的应用程序的有效性的一个重要因素,应考虑到。例如,IP 解析只可以精确到 10 英里范围内。这真的不会帮助很多如果您使用 geofences 在游乐园里。用的一种装置的精度范围很重要,请考虑您要确定地点坐标是否有效的位置精度与地点的坐标大小。

时间戳属性是在确定如何旧的数据非常有用的。当处理 geofences,时间可能非常重要。如果你在你的游乐园有 geofences,例如,您的应用程序可能会使用不同的工作流,如果用户输入了停车场在半夜与营业期间。图 4 显示了示例获取当前用户的设备的位置。

图 4 得到 Geoposition

Geolocator geo = new Geolocator();
try
{
  Geoposition pos = await geo.GetGeopositionAsync();
  double longitude = pos.Coordinate.Point.Position.Longitude;
  double latitude = pos.Coordinate.Point.Position.Latitude;
  double altitude = pos.Coordinate.Point.Position.Altitude;
  double accuracy = pos.Coordinate.Accuracy;
  DateTimeOffset timestamp = pos.Coordinate.Timestamp;
}
catch (Exception ex)
{
  // Handle errors like unauthorized access to location services
}

创建 Geofences

目前有四个不同的构造函数的地点坐标类使您可以定义的位置和行为的一个地点坐标。所有地理围墙结构发现 Windows.Devices.Geolocation.Geofencing 命名空间中。它是重要的是知道如何你想要在创建它之前, 的行为,因为公开的属性都是只读的地点坐标实例。因此,如果你不指定的东西在施工过程中,你将会必须要替换一个新地点坐标,如果你想要对其进行修改。

您需要创建一个地点坐标类的最低信息是唯一字符串标识符和一个定义形状的地点坐标,由 IGeoshape 接口的实现。在 Windows 8.1 中支持的唯一形状是 Geocircle,这由一个中心位置和半径以米为单位。随着地点坐标,这些值必须在施工进行定义,之后不能更改。半径可以在任何地方从.1 米到.25 地球的周长,应足以处理您的应用程序需要的任何大小。下面的示例演示如何在当前的设备具有半径 50 米的位置创建一个地点坐标:

Geolocator geo = new Geolocator();
try {
  Geoposition pos = await geo.GetGeopositionAsync();
  Geocircle shape = new Geocircle(pos.Coordinate.Point.Position, 50.0);
  Geofence geofence = new Geofence("myUniqueId", shape);
}
catch (Exception) { }

Windows 可以监视与一个地点坐标的几个不同的设备交互。默认情况下,它将监视时设备进入和退出的地点坐标定义的区域。此外,您可以指定通知,当一个地点坐标从被监视。这是一项要求进入或退出状态进行监测,这样你就不能监控只有去除一个地点坐标,其中,要诚实,不会对您的应用程序非常有用,放在第一位。监视状态可以定义使用的 MonitoredGeofence 组合­枚举,并存储在 MonitoredStates 属性中。

一个地点坐标还可以是一个单或多使用实体。它会被视为用于一旦所有的受监视的州都有发生。因此,如果你指定了进入和退出的国家,必须输入该设备,然后离开之前被认为是地点坐标指定的区域使用。除非另外指定,监测将继续下去,直到地点坐标被删除。SingleUse 属性标识是否地点坐标设置供单人使用。以下基于前面的示例中,并显示第二地点坐标构造函数:

MonitoredGeofenceStates monitor = MonitoredGeofenceStates.Entered |
                                  MonitoredGeofenceStates.Exited |
                                  MonitoredGeofenceStates.Removed;
bool singleUse = true;
Geofence geofence = new Geofence("myUniqueId", shape, monitor, singleUse);

默认情况下,设备必须边界监测一边保持 10 秒钟,然后应用程序会收到通知。这可以防止系统发射多个事件,如果设备是右侧边缘和来回移动。此值是 DwellTime,并且可以设置为任何时间跨度大于 0。 相同的 DwellTime 将用于进出该地区。因此,如果您需要不同的值,你将会必须创建两个 geofences,一个用于输入,另一个用于退出。下面使用通过将 DwellTime 设置为 20 秒的三个构造函数:

TimeSpan dwellTime = new TimeSpan(0, 0, 20);
Geofence geofence = new Geofence("myUniqueId", shape, monitor,
  singleUse, dwellTime);

最后一个构造函数允许您设置的开始时间和持续时间地点坐标。一旦开始时间是在过去,一个地点坐标将变得活跃。默认情况下,开始时间设置为 0 或处理日期时间上课时间的开端。如果一个地点坐标创建开始时间在过去,与该设备已定义的区域内,将报告输入状态,一旦 DwellTime 过去。配合开始时间,您可以定义持续多长时间地点坐标将积极从开始时间的时间。如果持续时间设置为 0 (默认值),只要它注册要监视地点坐标仍处于活动状态。当设置的持续时间值时,应用程序将通知过期日如果选中删除监视器状态。这是最后一个构造函数,它将开始时间设置为午夜,Jan。 1,2015 年期间,和一个 365 天的工期:

DateTime startTime = new DateTime(2015, 1, 1);
TimeSpan duration = new TimeSpan(365, 0, 0, 0, 0);
Geofence geofence = new Geofence(
  "myUniqueId", shape, monitor, singleUse, 
  dwellTime, startTime, duration);

在前景中使用 Geofences

在创建一个地点坐标后下, 一步是注册它要监视使您的应用程序可以接收有关它的通知。这是通过一个 GeofenceMonitor 实例处理。每个应用程序都可以通过 GeofenceMonitor.Current 的静态属性访问单个 GeofenceMonitor。 GeofenceMonitor 维护所有注册 geofences 在 Geofences 属性,它是 IList < 地点坐标 > 的列表。添加和删除从该列表中的 geofences 是一样容易使用 IList 方法你习惯,例如,添加和删除。一旦应用程序注册一个地点坐标,它已保存到磁盘。这意味着你只需要注册地点坐标一次,甚至之间的应用程序使用。如果您尝试注册地点坐标与一个重复的 id,将生成一个错误,所以它是一个好的政策,以验证 id 不存在登记之前:

IEnumerable<Geofence> existing =
  GeofenceMonitor.Current.Geofences.Where(g => g.Id == geofence.Id);
if (existing.Count() == 0)
{
  GeofenceMonitor.Current.Geofences.Add(geofence);
}
else
{
  // Handle duplicate entry
}

一旦地点坐标已添加到 GeofenceMonitor,您将收到有关它根据已选定的监控状态的通知。这些通知是通过 GeofenceMonitor 的 GeofenceStateChanged 事件处理的:

GeofenceMonitor.Current.GeofenceStateChanged += GeofenceStateChanged;

当引发 GeofenceStateChanged 事件时,受影响的 geofences 不会发送在 args 属性中,是很常见的大多数更改的事件处理程序中。若要获取关于发生了什么变化通知,你调用当前的 GeofenceMonitor 的 ReadReports 方法。这将返回最近监视器的集合通知,降序排序时间戳,该应用程序发生了。每个通知是由一个 GeofenceStateChangeReport 类表示的。

GeofenceStateChangeReport 具有一个引用其状态已更改,地点坐标的地点坐标属性和一个 Geopostion 属性,提供设备负责状态正在发生变化的位置。它也有一个 NewState 属性,它是标识哪些监测的状态被触发 GeofenceState 枚举。最后,还有一个 RemovalReason 属性,它是一个可以使用或过期的 GeofenceRemovalReason enum。默认值用于任何事件,并不意味着地点坐标已被删除。它只是提供去除原因,如果删除了 NewState 值。

由 Windows 控制经由 ReadReports 的报告数目。不能保证将存储多少报告或多长的时间,所以如果您需要维护任何信息,你需要在应用程序中保持一个单独的副本。图 5 是一个处理 GeofenceStateChanged 事件的例子。

图 5 GeofenceStateChanged 事件处理程序

void Current_GeofenceStateChanged(GeofenceMonitor sender, object args)
{
  IReadOnlyList<GeofenceStateChangeReport> reports =
    GeofenceMonitor.Current.ReadReports();
  foreach (GeofenceStateChangeReport report in reports)
  {
    switch (report.NewState)
    {
      case GeofenceState.Entered:
        // Handle entered state
        break;
      case GeofenceState.Exited:
        // Handle exited state
        break;
      case GeofenceState.Removed:
        if (report.RemovalReason == GeofenceRemovalReason.Used)
        {
          // Removed because it was single use
        }
        else
        {
          // Removed because it was expired
        }
        break;
    }
  }
}

在背景中使用 Geofences

开发人员必须考虑的其他问题之一是 Windows 应用商店应用程序的生命周期。如果应用程序不在屏幕上可见的 Windows 将挂起的同时保持它在内存中,以帮助保持性能和电池寿命的应用。这意味着您的应用程序将不再运行。在大多数情况下这不是令人担忧,因为如果用户不直接与应用程序进行交互,并无为的程序来做。

然而,在某些情况下,应用程序仍需要继续执行某些任务,即使应用程序没有运行的能力。Windows 解决这个问题与后台任务的概念。后台任务是代码的在对预定义的系统事件的响应中执行的一个小单位。有十几个不同的事件,您的应用程序可以注册一个后台任务,和听 geofences 就是其中之一。

添加一个后台任务

所有后台任务是通过创建实现 IBackgroundTask 接口位于 Windows.ApplicationModel.Background 命名空间中的密封的类都实现的。此接口定义一个单独的运行方法,必须得到执行。执行 IBackgroundTask 的任何类必须存在于 Windows 运行时组件,并且不会执行,如果他们是你的主要应用程序项目的一部分。它是常见的做法,把所有后台任务的应用程序都放在一个单一的 Windows 运行时组件。

若要创建一个后台任务,请将 Windows 运行时组件项目添加到解决方案中。对这个新项目的引用添加到主应用程序项目上,因此当您注册该任务应用程序的类结构的可见性。图 6 说明响应地点坐标状态更改的后台任务。

图 6 后台任务

public sealed class MyBackgroundTask : IBackgroundTask
{
  public void Run(IBackgroundTaskInstance taskInstance)
  {
    BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
    var reports = GeofenceMonitor.Current.ReadReports();
    foreach (var report in reports)
    {
      // Handle each report
    }
    deferral.Complete();
  }
}

注册一个后台任务

一旦你已经创建了一个后台任务下, 一步是向 Windows 注册该后台任务。作为提供位置服务,用户必须授予您使用后台任务的应用程序权限。您可以提示用户通过 RequestAccessAsync BackgroundExecutionManager 类的静态方法。如果用户已经回答了提示,则此方法将返回在应用程序上运行后台任务的当前状态。

通过 BackgroundTaskBuilder 的实例来完成的实际注册。它需要三条信息,才能有效。首先是应用程序的唯一名称。第二是采用后台任务类的完整名称的字符串,包括命名空间中的 TaskEntryPoint 属性。

最后一条信息定义要为其注册的事件的类型。这是通过创建一个触发器和使用 BackgroundTaskBuilder 的 SetTrigger 方法。每个后台任务可以只是一个单一的触发器。如果你想要使用相同的后台任务的多个触发器,您必须创建并注册多个后台任务。为了跟踪地点坐标变化,创建一个 LocationTrigger 实例,在 LocationTriggerType.Geofence 枚举值传递给构造函数。目前地理围墙是在 Windows 中提供的只有基于位置的触发器。最终的结果是,您创建的 IBackgroundTask Run 方法将被每一次到一个注册地点坐标的状态的变化。图 7 演示如何注册地点坐标后台任务。

图 7 册后台任务

private async void RegisterBackgroundTask(object sender, RoutedEventArgs e)
{
  BackgroundAccessStatus accessStatus =
    await BackgroundExecutionManager.RequestAccessAsync();
  if(accessStatus ==
    BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity ||
   accessStatus ==
     BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity)
  {
    BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
    taskBuilder.Name = "MyGeoBackground";
    taskBuilder.TaskEntryPoint = 
      "WindowsRuntimeComponent1.MyBackgroundTask";
    LocationTrigger trigger = new LocationTrigger(LocationTriggerType.Geofence);
    taskBuilder.SetTrigger(trigger);
    taskBuilder.Register();
  }
}

要使您的应用程序要运行后台任务的最后一步是添加一个后台任务声明中包 appxmanifest。在 appxmanifest 设计器中选择声明选项卡,从添加声明下拉列表中,选择背景任务然后单击添加按钮。在详细信息窗格中,选择位置,为其财产和为切入点,把你的 BackgroundTaskBuilder TaskEntryPoint 的类名。一旦你这样做,你会看到一个红色的"X",在应用程序选项卡。一些后台任务要求您的应用程序添加到锁定屏幕为任务,以运行,顺序和位置的后台任务是这样一项任务。第一步是对徽章,徽章和瓷砖文本应用程序窗格中设置锁定屏幕通知。下一步是,用户可以将应用程序添加到他的锁定屏幕。BackgroundExecution­Mananger.Request­前面讨论过的 AccessAsync 方法会将应用程序添加到锁定屏幕,如果用户批准它。然而,您需要编写代码来通知用户,在事件在用户删除该应用程序从锁定屏幕在稍后的日期,因为 Windows 只会提示用户将添加该应用程序一个单一的时间。

您的应用程序现在将回应地点坐标状态更改在背景中。它是重要的是要记住这会发生即使当前正在运行您的应用程序,所以您的应用程序工作流应考虑,如果您还在监视 geofences 在 UI 更新的应用前景。

更深层次的 Windows 8.1 中的后台任务说明,请参阅向"支持您的应用程序与背景任务 (XAML)"在 bit.ly/1i9AH8X

总结

新动态添加任何位置感知的应用程序,通过让您的应用程序响应更改预定义的 GPS coor 接近 Geofences­dinates。这使您可以轻松地提供您的应用程序可以与全球各地的热点问题。不仅可以您的应用程序响应这些 geofences 时它正在运行,而利用后台任务它可以仍然是响应应用程序已经暂停,或甚至不运行时。与较小的启用 GPS 设备变得越来越流行,添加到您的应用程序的位置感知功能可以提供好的用户体验,和我,举例来说,迫不及待想看到什么获取创建的下一步。


Tony Champion 是冠军 DS 总统,是微软最有价值球员,是活跃在扬声器、 博客写手,以及作者社区。他认为在一个博客 tonychampion.net ,可以达到在 tony@tonychampion.net

衷心感谢以下 Microsoft 技术专家对本文的审阅:罗伯特 · 格林