教學課程:使用 Azure 通知中樞和 Bing 空間資料來傳送以位置為基礎的推播通知Tutorial: Send location-based push notifications with Azure Notification Hubs and Bing Spatial Data

在本教學課程中,您將學習如何使用 Azure 通知中樞和 Bing 空間資料來傳遞以位置為基礎的推播通知。In this tutorial, you learn how to deliver location-based push notifications with Azure Notification Hubs and Bing Spatial Data.

在本教學課程中,您會執行下列步驟:In this tutorial, you take the following steps:

  • 設定資料來源Set up the data source
  • 設定 UWP 應用程式Set up the UWP application
  • 設定後端Set up the backend
  • 測試通用 Windows 平台 (UWP) 應用程式中的推播通知Test push notifications in the Universal Windows Platform (UWP) app

必要條件Prerequisites

設定資料來源Set up the data source

  1. 登入 Bing 地圖服務開發人員中心Log in to the Bing Maps Dev Center.

  2. 在上方導覽列中,選取 [資料來源] ,然後選取 [管理資料來源] 。In the top navigation bar, select Data sources, and select Manage Data Sources.

  3. 如果您沒有現有的資料來源,您會看到建立資料來源的連結。If you don't have an existing data source, you see a link to create a data source. 選取 [上傳資料以作為資料來源] 。Select Upload data as a data source. 您也可以使用 [資料來源] > [上傳資料] 功能表。You can also use Data sources > Upload data menu.

  4. 使用下列內容,在硬碟上建立 NotificationHubsGeofence.pipe 檔案︰在本教學課程中,您會使用框起舊金山濱水區的範例管道式檔案︰Create a file NotificationHubsGeofence.pipe on your hard drive with the following content: In this tutorial, you use a sample pipe-based file that frames an area of the San Francisco waterfront:

    Bing Spatial Data Services, 1.0, TestBoundaries
    EntityID(Edm.String,primaryKey)|Name(Edm.String)|Longitude(Edm.Double)|Latitude(Edm.Double)|Boundary(Edm.Geography)
    1|SanFranciscoPier|||POLYGON ((-122.389825 37.776598,-122.389438 37.773087,-122.381885 37.771849,-122.382186 37.777022,-122.389825 37.776598))
    

    此管道檔案代表以下實體︰The pipe file represents this entity:

  5. 在 [上傳資料來源] 頁面上,執行下列動作:In the Upload a data source page, do the following actions:

    1. 選取 [管道] 作為 [資料格式] 。Select pipe for Data format.

    2. 瀏覽並選取您在上一個步驟中建立的 NotificationHubGeofence.pipe 檔案。Browse and select the NotificationHubGeofence.pipe file that you created in the previous step.

    3. 選取 [上傳] 按鈕。Select Upload button.

      注意

      您可能會收到提示,要求您為 [主要金鑰] 指定不同於 [查詢金鑰] 的新金鑰。You might be prompted to specify a new key for the Master Key that is different from the Query Key. 請直接透過儀表板建立新的金鑰,然後重新整理資料來源上傳頁面。Simply create a new key through the dashboard and refresh the data source upload page.

  6. 上傳資料檔案後,您必須確實發佈資料來源。Once you upload the data file, you need to make sure that you publish the data source. 選取 [資料來源] -> [管理資料來源] ,如同之前所做的動作。Select Data sources -> Manage Data Sources like you did before.

  7. 在清單中選取您的資料來源,並在 [動作] 資料行中選擇 [發佈] 。Select your data source in the list, and choose Publish in the Actions column.

  8. 切換至 [已發佈的資料來源] 索引標籤,確認在清單中有看到您的資料來源。Switch to the Published Data Sources tab, and confirm that you see your data source in the list.

  9. 選取 [編輯] 。Select Edit. 您一眼就能看到您在資料中引入的位置。You see (at a glance) what locations you introduced in the data.

    此時,入口網站並不會顯示您建立之地理柵欄的邊界,您只需要確認指定的位置位於適當區域內。At this point, the portal does not show you the boundaries for the geofence that you created – all you need is confirmation that the location specified is in the right vicinity.

  10. 現在您已符合資料來源的所有要求。Now you have all the requirements for the data source. 若要取得 API 呼叫之要求 URL 的詳細資料,請在 Bing 地圖服務開發人員中心選擇 [資料來源] ,然後選取 [資料來源資訊] 。To get the details on the request URL for the API call, in the Bing Maps Dev Center, choose Data sources and select Data Source Information.

    我們可以對查詢 URL 端點執行查詢,以檢查裝置目前是否位於某個位置的邊界內。The Query URL is the endpoint against which you can execute queries to check whether the device is currently within the boundaries of a location or not. 若要執行這項檢查,您只要對查詢 URL 執行 GET 呼叫,並附加下列參數︰To perform this check, you just execute a GET call against the query URL, with the following parameters appended:

    ?spatialFilter=intersects(%27POINT%20LONGITUDE%20LATITUDE)%27)&$format=json&key=QUERY_KEY
    

    Bing 地圖服務會自動執行計算,以檢查裝置是否在地理柵欄內。Bing Maps automatically performs the calculations to see whether the device is within the geofence. 一旦您透過瀏覽器 (或 cURL) 執行要求,您將會收到標準 JSON 回應︰Once you execute the request through a browser (or cURL), you get a standard JSON response:

    只有當位置點確實位於指定邊界內時,才會出現此回應。This response only happens when the point is actually within the designated boundaries. 如果不在邊界內,您將會收到空白的 results 貯體︰If it is not, you get an empty results bucket:

設定 UWP 應用程式Set up the UWP application

  1. 在 Visual Studio 中,開始 [空白應用程式 (通用 Windows)] 類型的新專案。In Visual Studio, start a new project of type Blank App (Universal Windows).

    建立好專案之後,您應該就能控管應用程式本身。Once the project creation is complete, you should have the harness for the app itself. 現在讓我們來進行地理柵欄基礎結構的各項設定。Now let’s set up everything for the geo-fencing infrastructure. 由於您會使用 Bing 服務來進行這項解決方案,因此會有可供您查詢特定位置框架的公用 REST API 端點︰Because you are going to use Bing services for this solution, there is a public REST API endpoint that allows you to query specific location frames:

    http://spatial.virtualearth.net/REST/v1/data/
    

    請指定下列參數以讓端點開始運作︰Specify the following parameters to get it working:

    • 資料來源識別碼資料來源名稱 – 在 Bing 地圖服務 API 中,資料來源包含了各種分門別類的中繼資料,例如營業據點和營業時間。Data Source ID and Data Source Name – in Bing Maps API, data sources contain various bucketed metadata, such as locations and business hours of operation.

    • 實體名稱 – 您想要作為通知參考點的實體。Entity Name – the entity you want to use as a reference point for the notification.

    • Bing 地圖服務 API 金鑰 – 您稍早建立 Bing 開發人員中心帳戶時取得的金鑰。Bing Maps API Key – The key that you obtained earlier when you created the Bing Dev Center account.

      現在您已經備妥資料來源,接下來您可以開始處理 UWP 應用程式。Now that you have the data source ready, you can start working on the UWP application.

  2. 啟用應用程式的位置服務。Enable location services for your application. 在 [方案總管] 中開啟 Package.appxmanifest 檔案。Open the Package.appxmanifest file in Solution Explorer.

  3. 在剛剛開啟的 [套件屬性] 索引標籤中,切換至 [功能] 索引標籤,並選取 [位置] 。In the package properties tab that just opened, switch to the Capabilities tab, and select Location.

  4. 在方案中建立名為 Core 的新資料夾,並在其中新增名為 LocationHelper.cs 的新檔案:Create a new folder in your solution named Core, and add a new file within it, named LocationHelper.cs:

    LocationHelper 類別的程式碼可透過系統 API 取得使用者位置:The LocationHelper class has code to obtain the user location through the system API:

    using System;
    using System.Threading.Tasks;
    using Windows.Devices.Geolocation;
    
    namespace NotificationHubs.Geofence.Core
    {
        public class LocationHelper
        {
            private static readonly uint AppDesiredAccuracyInMeters = 10;
    
            public async static Task<Geoposition> GetCurrentLocation()
            {
                var accessStatus = await Geolocator.RequestAccessAsync();
                switch (accessStatus)
                {
                    case GeolocationAccessStatus.Allowed:
                        {
                            Geolocator geolocator = new Geolocator { DesiredAccuracyInMeters = AppDesiredAccuracyInMeters };
    
                            return await geolocator.GetGeopositionAsync();
                        }
                    default:
                        {
                            return null;
                        }
                }
            }
    
        }
    }
    

    若要深入了解如何取得 UWP 應用程式中的使用者位置,請參閱取得使用者的位置To learn more about getting the user’s location in UWP apps, seeGet the user's location.

  5. 若要確認實際上是否能取得位置,請開啟主頁面的程式碼端 (MainPage.xaml.cs)。To check that the location acquisition is actually working, open the code side of your main page (MainPage.xaml.cs). MainPage 建構函式中為 Loaded 事件建立新的事件處理常式。Create a new event handler for the Loaded event in the MainPage constructor.

    public MainPage()
    {
        this.InitializeComponent();
        this.Loaded += MainPage_Loaded;
    }
    

    事件處理常式的實作如下︰The implementation of the event handler is as follows:

    private async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var location = await LocationHelper.GetCurrentLocation();
    
        if (location != null)
        {
            Debug.WriteLine(string.Concat(location.Coordinate.Longitude,
                " ", location.Coordinate.Latitude));
        }
    }
    
  6. 執行應用程式,並允許它存取您的位置。Run the application and allow it to access your location.

  7. 一旦應用程式啟動,您應該就能在 [輸出] 視窗中看到座標︰Once the application launches, you should be able to see the coordinates in the Output window:

    現在您知道能正常取得位置了,接著您可以自由移除 Loaded 事件處理常式,因為我們不會再用到它。Now you know that location acquisition works, you can remove the Loaded event handler if you like because you won’t be using it anymore.

  8. 下一步是擷取位置變更。The next step is to capture location changes. LocationHelper 類別中,新增 PositionChanged 的事件處理常式:In the LocationHelper class, add the event handler for PositionChanged:

    geolocator.PositionChanged += Geolocator_PositionChanged;
    

    實作後將會在 [輸出] 視窗中顯示位置座標︰The implementation shows the location coordinates in the Output window:

    private static async void Geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
    {
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            Debug.WriteLine(string.Concat(args.Position.Coordinate.Longitude, " ", args.Position.Coordinate.Latitude));
        });
    }
    

設定後端Set up the backend

  1. 從 GitHub 下載 .NET 後端範例Download the .NET Backend Sample from GitHub.

  2. 下載完成後,在 Visual Studio 中依序開啟 NotifyUsers 資料夾和 NotifyUsers.sln 檔案。Once the download completes, open the NotifyUsers folder, and then open NotifyUsers.sln file in Visual Studio.

  3. AppBackend 專案設定為 [啟始專案] 並加以啟動。Set the AppBackend project as the StartUp Project and launch it.

    專案已設定為會將推播通知傳送至目標裝置,所以您只需要做兩件事 – 指定用於通知中樞的正確連接字串,並新增邊界識別以便只在使用者位於地理柵欄內時才傳送通知。The project is already configured to send push notifications to target devices, so you need to do only two things – specify right connection string for the notification hub and add boundary identification to send the notification only when the user is within the geofence.

  4. 若要設定連接字串,請開啟 Models 資料夾內的 Notifications.csTo configure the connection string, in the Models folder open Notifications.cs. NotificationHubClient.CreateClientFromConnectionString 函式應該會包含可在 Azure 入口網站內取得之通知中樞的相關資訊 (請查看 [設定] 的 [存取原則] 頁面內部)。The NotificationHubClient.CreateClientFromConnectionString function should contain the information about your notification hub that you can get in the Azure portal (look inside the Access Policies page in Settings). 儲存經過更新的組態檔。Save the updated configuration file.

  5. 為 Bing 地圖服務 API 結果建立模型。Create a model for the Bing Maps API result. 若要這麼做,最簡單的方式是開啟 Models 資料夾,然後選擇 [新增] > [類別] 。The easiest way to do that is to open the Models folder and choose Add > Class. 將它命名為 GeofenceBoundary.csName it GeofenceBoundary.cs. 完成時,從在第一節取得的 API 回應中複製 JSON。Once done, copy the JSON from the API response that you got in the first section. 在 Visual Studio 中,使用 [編輯] > [選擇性貼上] > [將 JSON 貼上為類別] 。In Visual Studio, use Edit > Paste Special > Paste JSON as Classes.

    如此一來,您就能確保物件會確實依其設計目的還原序列化。This way you ensure that the object is deserialized exactly as it was intended. 所產生的類別集應該會類似於下列類別︰Your resulting class set should resemble the following class:

    namespace AppBackend.Models
    {
        public class Rootobject
        {
            public D d { get; set; }
        }
    
        public class D
        {
            public string __copyright { get; set; }
            public Result[] results { get; set; }
        }
    
        public class Result
        {
            public __Metadata __metadata { get; set; }
            public string EntityID { get; set; }
            public string Name { get; set; }
            public float Longitude { get; set; }
            public float Latitude { get; set; }
            public string Boundary { get; set; }
            public string Confidence { get; set; }
            public string Locality { get; set; }
            public string AddressLine { get; set; }
            public string AdminDistrict { get; set; }
            public string CountryRegion { get; set; }
            public string PostalCode { get; set; }
        }
    
        public class __Metadata
        {
            public string uri { get; set; }
        }
    }
    
  6. 接下來,開啟 Controllers > NotificationsController.csNext, open Controllers > NotificationsController.cs. 更新 Post 呼叫以說明目標經緯度。Update the Post call to account for the target longitude and latitude. 若要這麼做,請直接新增下列兩個字串到函式簽章 – latitudelongitudeTo do so, add two strings to the function signature – latitude and longitude.

    public async Task<HttpResponseMessage> Post(string pns, [FromBody]string message, string to_tag, string latitude, string longitude)
    
  7. 在稱為 ApiHelper.cs 的專案內建立新類別 – 您將使用它來連線到 Bing,以確認位置點邊界的交叉點。Create a new class within the project called ApiHelper.cs – you use it to connect to Bing to check point boundary intersections. 實作 IsPointWithinBounds 函式,如下列程式碼所示:Implement a IsPointWithinBounds function as shown in the following code:

    public class ApiHelper
    {
        public static readonly string ApiEndpoint = "{YOUR_QUERY_ENDPOINT}?spatialFilter=intersects(%27POINT%20({0}%20{1})%27)&$format=json&key={2}";
        public static readonly string ApiKey = "{YOUR_API_KEY}";
    
        public static bool IsPointWithinBounds(string longitude,string latitude)
        {
            var json = new WebClient().DownloadString(string.Format(ApiEndpoint, longitude, latitude, ApiKey));
            var result = JsonConvert.DeserializeObject<Rootobject>(json);
            if (result.d.results != null && result.d.results.Count() > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    

    重要

    請務必將 API 端點替換為您稍早從 Bing 開發人員中心取得的查詢 URL (API 金鑰也要如此處理)。Make sure to substitute the API endpoint with the query URL that you obtained earlier from the Bing Dev Center (same applies to the API key).

    如果查詢後有得到結果,這表示指定位置點位於地理柵欄邊界內,因此函式會傳回 trueIf there are results to the query, that means that the specified point is within the boundaries of the geofence, so the function returns true. 如果查詢不到任何結果,Bing 就會告訴您位置點位於查閱框架外部,因此函式會傳回 falseIf there are no results, Bing is telling you that the point is outside the lookup frame, so the function returns false.

  8. NotificationsController.cs 中,於 switch 陳述式前建立檢查︰In NotificationsController.cs, create a check right before the switch statement:

    if (ApiHelper.IsPointWithinBounds(longitude, latitude))
    {
        switch (pns.ToLower())
        {
            case "wns":
                //// Windows 8.1 / Windows Phone 8.1
                var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">" +
                            "From " + user + ": " + message + "</text></binding></visual></toast>";
                outcome = await Notifications.Instance.Hub.SendWindowsNativeNotificationAsync(toast, userTag);
    
                // Windows 10 specific Action Center support
                toast = @"<toast><visual><binding template=""ToastGeneric""><text id=""1"">" +
                            "From " + user + ": " + message + "</text></binding></visual></toast>";
                outcome = await Notifications.Instance.Hub.SendWindowsNativeNotificationAsync(toast, userTag);
    
                break;
        }
    }
    

在 UWP 應用程式中測試推播通知Test push notifications in the UWP app

  1. 在 UWP 應用程式中,您現在應該能夠測試通知了。In the UWP app, you should now be able to test notifications. LocationHelper 類別內建立新函式 SendLocationToBackendWithin the LocationHelper class, create a new function – SendLocationToBackend:

    public static async Task SendLocationToBackend(string pns, string userTag, string message, string latitude, string longitude)
    {
        var POST_URL = "http://localhost:8741/api/notifications?pns=" +
            pns + "&to_tag=" + userTag + "&latitude=" + latitude + "&longitude=" + longitude;
    
        using (var httpClient = new HttpClient())
        {
            try
            {
                await httpClient.PostAsync(POST_URL, new StringContent("\"" + message + "\"",
                    System.Text.Encoding.UTF8, "application/json"));
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }
    }
    

    注意

    POST_URL 設定為已部署的 Web 應用程式所在位置。Set the POST_URL to the location of your deployed web application. 現在您可以在本機加以執行,但是由於您要著手部署公用版本,因此您必須使用外部提供者來進行裝載。For now, it’s OK to run it locally, but as you work on deploying a public version, you need to host it with an external provider.

  2. 註冊 UWP 應用程式以取得推播通知。Register the UWP app for push notifications. 在 Visual Studio 中,選擇 [專案] > [市集] > [將應用程式與市集建立關聯] 。In Visual Studio, choose Project > Store > Associate app with the store.

  3. 一旦您登入開發人員帳戶,請務必選取現有應用程式或建立新應用程式並讓封裝與其建立關聯。Once you sign in to your developer account, make sure you select an existing app or create a new one and associate the package with it.

  4. 移至開發人員中心,然後開啟您建立的應用程式。Go to the Dev Center and open the app that you created. 選擇 [服務] > [推播通知] > [線上服務網站] 。Choose Services > Push Notifications > Live Services site.

  5. 記下網站上的 [應用程式密碼] 和 [套件 SID] 。On the site, take note of the Application Secret and the Package SID. 在 Azure 入口網站中需要用到這兩個項目 – 開啟通知中樞、選擇 [設定] > [Notification Services] > [Windows] (WNS) ,然後在必要欄位中輸入資訊。You need both in the Azure portal – open your notification hub, choose Settings > Notification Services > Windows (WNS) and enter the information in the required fields.

  6. 選擇 [儲存] 。Choose Save.

  7. 在 [方案總管] 中開啟 [參考] ,然後選取 [管理 NuGet 套件] 。Open References in Solution Explorer and select Manage NuGet Packages. 新增 Microsoft Azure 服務匯流排受控程式庫的參考 – 只要搜尋 WindowsAzure.Messaging.Managed 並將它新增至專案即可。Add a reference to the Microsoft Azure Service Bus managed library – simply search for WindowsAzure.Messaging.Managed and add it to your project.

  8. 為了進行測試,可以再次建立 MainPage_Loaded 事件處理常式,並對其新增下列程式碼片段︰For testing purposes, create the MainPage_Loaded event handler once again, and add this code snippet to it:

    var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
    var hub = new NotificationHub("HUB_NAME", "HUB_LISTEN_CONNECTION_STRING");
    var result = await hub.RegisterNativeAsync(channel.Uri);
    
    // Displays the registration ID so you know it was successful
    if (result.RegistrationId != null)
    {
        Debug.WriteLine("Reg successful.");
    }
    

    程式碼會使用通知中樞註冊應用程式。The code registers the app with the notification hub. 現在可以開時進行了!You are ready to go!

  9. LocationHelperGeolocator_PositionChanged 處理常式內,您可以新增一段測試程式碼以強制將位置放在地理柵欄內︰In LocationHelper, inside the Geolocator_PositionChanged handler, you can add a piece of test code that forcefully puts the location inside the geofence:

    await LocationHelper.SendLocationToBackend("wns", "TEST_USER", "TEST", "37.7746", "-122.3858");
    
  10. 因為您不會傳遞實際座標 (目前可能不在邊界內),而是使用預先定義的測試值,因此會在更新時看到通知出現︰Because you are not passing the real coordinates (which might not be within the boundaries at the moment) and are using predefined test values, you see a notification show up on update:

後續步驟Next steps

您可能還需要遵循幾個步驟以確定方案已可用於生產環境。There are a couple of steps that you might need to follow to make the solution production-ready.

  1. 首先,您需要確保地理柵欄是動態的。First, you need to ensure that geofences are dynamic. 這需要對 Bing API 進行一些額外處理,才能在現有資料來源內上傳新邊界。It requires some extra work with the Bing API to be able to upload new boundaries within the existing data source. 如需詳細資訊,請參閱 Bing 空間資料服務 API 文件For more information, see Bing Spatial Data Services API documentation.
  2. 接著,由於您要確保會對正確的參與者進行傳遞,因此您可以透過 標記功能鎖定這些人。Second, as you are working to ensure that the delivery is done to the right participants, you might want to target them via tagging.

在此教學課程所示解決方案所說明的案例中,您可能會有各種不同目標平台,因此這裡並未限制只有系統特有功能才能使用地理柵欄。The solution shown in this tutorial describes a scenario in which you might have a wide variety of target platforms, so it does not limit the geofencing to system-specific capabilities. 也就是說,通用 Windows 平台內建提供了相關功能來 偵測地理柵欄That said, the Universal Windows Platform offers capabilities to detect geofences right out-of-the-box.