本文章是由機器翻譯。

微軟商店

建立內含地理柵欄功能的定位感知應用程式

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

感謝以下的微軟技術專家對本文的審閱:羅伯特 · 格林