教學課程:使用 Azure 通知中樞將推播通知傳送至特定 iOS 裝置
概觀
本教學課程說明如何使用 Azure 通知中樞將即時新聞通知廣播至 iOS 應用程式。 完成時,您將能夠註冊自己所感興趣的即時新聞類別,並僅接收那些類別的推播通知。 此情況為適用於許多應用程式的常見模式,其中必須將通知傳送給先前宣告對該通知感興趣的使用者群組,例如 RSS 閱讀程式、供樂迷使用的應用程式等等。
在通知中樞內建立註冊時,您可以透過包含一或多個 tags 來啟用廣播案例。 當通知傳送至標記時,已註冊該標記的裝置都會收到該通知。 由於標籤只是簡單的字串而已,您無需預先佈建標籤。 如需標記的詳細資訊,請參閱通知中樞路由與標記運算式。
在本教學課程中,您會執行下列步驟:
- 在應用程式中新增類別選項
- 傳送加註標記的通知
- 從裝置傳送通知
- 執行應用程式並產生通知
必要條件
這個主題會以您在教學課程:使用 Azure 通知中樞將通知推播至 iOS 應用程式中所建立的應用程式為基礎。 在開始進行本教學課程之前,您必須先完成教學課程:使用 Azure 通知中樞將通知推播至 iOS 應用程式。
在應用程式中新增類別選項
第一個步驟是在您現有的腳本上新增 UI 元素,以便使用者選取要註冊的類別。 使用者所選取的類別會儲存在裝置上。 啟動應用程式時,您的通知中心內會建立以所選取類別作為標籤的裝置註冊。
在您的 MainStoryboard_iPhone.storyboard 中,從物件程式庫新增下列元件:
具有「即時新聞」文字的標籤,
具有「世界」、「政治」、「商業」、「技術」、「科學」、「體育」等類別文字的標籤,
六個參數 (一個類別一個),預設會將每個參數 [狀態] 設為 [關閉]。
一個標示為「訂閱」的按鈕
您的腳本應如下所示:
在輔助編輯器中,建立所有參數的出口,並將其命名為 "WorldSwitch"、"PoliticsSwitch"、"BusinessSwitch"、"TechnologySwitch"、"ScienceSwitch"、"SportsSwitch"
為按鈕建立名為
subscribe
的動作;您的ViewController.h
應包含下列程式碼:@property (weak, nonatomic) IBOutlet UISwitch *WorldSwitch; @property (weak, nonatomic) IBOutlet UISwitch *PoliticsSwitch; @property (weak, nonatomic) IBOutlet UISwitch *BusinessSwitch; @property (weak, nonatomic) IBOutlet UISwitch *TechnologySwitch; @property (weak, nonatomic) IBOutlet UISwitch *ScienceSwitch; @property (weak, nonatomic) IBOutlet UISwitch *SportsSwitch; - (IBAction)subscribe:(id)sender;
建立稱為
Notifications
的新 Cocoa Touch 類別。 在 Notifications.h 的介面區段中複製下列程式碼:@property NSData* deviceToken; - (id)initWithConnectionString:(NSString*)listenConnectionString HubName:(NSString*)hubName; - (void)storeCategoriesAndSubscribeWithCategories:(NSArray*)categories completion:(void (^)(NSError* error))completion; - (NSSet*)retrieveCategories; - (void)subscribeWithCategories:(NSSet*)categories completion:(void (^)(NSError *))completion;
在 Notifications.m 中新增下列 import 指示詞:
#import <WindowsAzureMessaging/WindowsAzureMessaging.h>
複製 Notifications.m 檔案實作區段中的下列程式碼:
SBNotificationHub* hub; - (id)initWithConnectionString:(NSString*)listenConnectionString HubName:(NSString*)hubName{ hub = [[SBNotificationHub alloc] initWithConnectionString:listenConnectionString notificationHubPath:hubName]; return self; } - (void)storeCategoriesAndSubscribeWithCategories:(NSSet *)categories completion:(void (^)(NSError *))completion { NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults setValue:[categories allObjects] forKey:@"BreakingNewsCategories"]; [self subscribeWithCategories:categories completion:completion]; } - (NSSet*)retrieveCategories { NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; NSArray* categories = [defaults stringArrayForKey:@"BreakingNewsCategories"]; if (!categories) return [[NSSet alloc] init]; return [[NSSet alloc] initWithArray:categories]; } - (void)subscribeWithCategories:(NSSet *)categories completion:(void (^)(NSError *))completion { NSString* templateBodyAPNS = @"{\"aps\":{\"alert\":\"$(messageParam)\"}}"; [hub registerTemplateWithDeviceToken:self.deviceToken name:@"simpleAPNSTemplate" jsonBodyTemplate:templateBodyAPNS expiryTemplate:@"0" tags:categories completion:completion]; }
此類別會使用本機儲存體來儲存和擷取此裝置接收到的新聞類別。 此外,它也包含使用 範本 註冊來註冊這些類別的方法。
在
AppDelegate.h
檔案中,新增Notifications.h
的匯入陳述式,並新增Notifications
類別執行個體的屬性:#import "Notifications.h" @property (nonatomic) Notifications* notifications;
在
AppDelegate.m
的didFinishLaunchingWithOptions
方法中,於方法的開頭處加入程式碼來初始化通知執行個體。
HUBNAME
與HUBLISTENACCESS
(定義於hubinfo.h
中) 的<hub name>
和<connection string with listen access>
預留位置,應已用稍早取得的 DefaultListenSharedAccessSignature 的通知中樞名稱與連接字串所取代self.notifications = [[Notifications alloc] initWithConnectionString:HUBLISTENACCESS HubName:HUBNAME];
注意
因為隨用戶端應用程式散佈的憑證通常不安全,您應只將接聽存取權的金鑰隨用戶端應用程式散佈。 您的應用程式可透過接聽存取權來註冊通知,但無法修改現有的註冊或無法傳送通知。 在安全的後端服務中,會使用完整存取金鑰來傳送通知和變更現有的註冊。
在
AppDelegate.m
的didRegisterForRemoteNotificationsWithDeviceToken
方法中,使用下列程式碼來取代方法中的程式碼,以將裝置權杖傳遞給notifications
類別。notifications
類別會為通知執行與類別之間的註冊。 如果使用者變更類別選取項目,則可以呼叫subscribeWithCategories
方法以回應 [subscribe] \(訂閱\) 按鈕來更新它們。注意
由於 Apple Push Notification Service (APNS) 指派的裝置權杖隨時可能改變,因此您應經常註冊通知以避免通知失敗。 此範例會在應用程式每次啟動時註冊通知。 若是經常執行 (一天多次) 的應用程式,如果距離上次註冊的時間不到一天,則您可能可以略過註冊以保留頻寬。
self.notifications.deviceToken = deviceToken; // Retrieves the categories from local storage and requests a registration for these categories // each time the app starts and performs a registration. NSSet* categories = [self.notifications retrieveCategories]; [self.notifications subscribeWithCategories:categories completion:^(NSError* error) { if (error != nil) { NSLog(@"Error registering for notifications: %@", error); } }];
此時,
didRegisterForRemoteNotificationsWithDeviceToken
方法中不應有任何其他程式碼。完成開始使用通知中樞教學課程時,下列方法應該已出現在
AppDelegate.m
中。 否則,請予以新增。- (void)MessageBox:(NSString *)title message:(NSString *)messageText { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:messageText delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil]; [alert show]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo { NSLog(@"%@", userInfo); [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]]; }
此方法會顯示簡易 UIAlert,以處理應用程式執行時接收到的通知。
在
ViewController.m
中,新增AppDelegate.h
的import
陳述式,並將下列程式碼複製到 XCode 所產生的subscribe
方法中。 此程式碼會更新通知註冊,以使用使用者在使用者介面中所選擇的新類別標記。#import "Notifications.h" NSMutableArray* categories = [[NSMutableArray alloc] init]; if (self.WorldSwitch.isOn) [categories addObject:@"World"]; if (self.PoliticsSwitch.isOn) [categories addObject:@"Politics"]; if (self.BusinessSwitch.isOn) [categories addObject:@"Business"]; if (self.TechnologySwitch.isOn) [categories addObject:@"Technology"]; if (self.ScienceSwitch.isOn) [categories addObject:@"Science"]; if (self.SportsSwitch.isOn) [categories addObject:@"Sports"]; Notifications* notifications = [(AppDelegate*)[[UIApplication sharedApplication]delegate] notifications]; [notifications storeCategoriesAndSubscribeWithCategories:categories completion: ^(NSError* error) { if (!error) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:"Notification" message:"Subscribed" delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil]; [alert show]; } else { NSLog(@"Error subscribing: %@", error); } }];
此方法會建立類別的
NSMutableArray
,並使用Notifications
類別在本機儲存體中儲存清單,並在通知中心註冊對應標記。 變更類別時,系統會使用新類別重新建立註冊。在
ViewController.m
中,於viewDidLoad
方法中新增下列程式碼,以根據先前儲存的類別來設定使用者介面。// This updates the UI on startup based on the status of previously saved categories. Notifications* notifications = [(AppDelegate*)[[UIApplication sharedApplication]delegate] notifications]; NSSet* categories = [notifications retrieveCategories]; if ([categories containsObject:@"World"]) self.WorldSwitch.on = true; if ([categories containsObject:@"Politics"]) self.PoliticsSwitch.on = true; if ([categories containsObject:@"Business"]) self.BusinessSwitch.on = true; if ([categories containsObject:@"Technology"]) self.TechnologySwitch.on = true; if ([categories containsObject:@"Science"]) self.ScienceSwitch.on = true; if ([categories containsObject:@"Sports"]) self.SportsSwitch.on = true;
應用程式現在可以在裝置本機儲存體中儲存一組類別,以用來在每次應用程式啟動時於通知中樞註冊。 使用者可以在執行階段變更選取的類別,然後按一下 subscribe
方法來更新裝置的註冊。 接下來,您會更新應用程式,以直接在應用程式本身傳送即時新聞通知。
(選擇性) 傳送加註標記的通知
如果您無法存取 Visual Studio,可以跳到下一節,並從應用程式本身傳送通知。 您也可以使用通知中樞的 [偵錯] 索引標籤,從 Azure 入口網站 傳送正確的範本通知。
在本節中,您會從 .NET 主控台應用程式將即時新聞以加註標記的範本通知形式傳送。
在 Visual Studio 中,建立新的 Visual C# 主控台應用程式:
- 在主功能表上,選取 [檔案]>[新增]>[專案]。
- 在 [建立新專案] 中,針對 C# 在範本清單中選取 [主控台應用程式 \(.NET Framework\)],接著選取 [下一步]。
- 輸入應用程式的名稱。
- 在 [解決方案] 中,選擇 [新增到解決方案],再選取 [建立] 以建立專案。
選取 [工具]>[NuGet 套件管理員]>[套件管理員主控台],然後在主控台視窗中執行下列命令:
Install-Package Microsoft.Azure.NotificationHubs
此動作會使用 Microsoft.Azure.NotificationHubs 套件來新增對 Azure 通知中樞 SDK 的參考。
開啟 Program.cs 檔案,並新增下列
using
陳述式:using Microsoft.Azure.NotificationHubs;
在
Program
類別中,新增或取代 (如果方法已存在) 下列方法:private static async void SendTemplateNotificationAsync() { // Define the notification hub. NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<connection string with full access>", "<hub name>"); // Apple requires the apns-push-type header for all requests var headers = new Dictionary<string, string> {{"apns-push-type", "alert"}}; // Create an array of breaking news categories. var categories = new string[] { "World", "Politics", "Business", "Technology", "Science", "Sports"}; // Send the notification as a template notification. All template registrations that contain // "messageParam" and the proper tags will receive the notifications. // This includes APNS, GCM/FCM, WNS, and MPNS template registrations. Dictionary<string, string> templateParams = new Dictionary<string, string>(); foreach (var category in categories) { templateParams["messageParam"] = "Breaking " + category + " News!"; await hub.SendTemplateNotificationAsync(templateParams, category); } }
此程式碼會分別將範本通知傳送給字串陣列中的六個標籤。 使用標籤可確保裝置只會收到已登錄類別的通知。
在上述程式碼中,請使用您的通知中樞名稱及通知中樞儀表板的 DefaultFullSharedAccessSignature 連接字串,來取代
<hub name>
和<connection string with full access>
預留位置。在
Main()
方法中新增下列程式碼行:SendTemplateNotificationAsync(); Console.ReadLine();
建置主控台應用程式。
(選擇性) 從裝置傳送通知
通知通常會由後端服務傳送,但您可直接從應用程式傳送即時新聞通知。 若要這樣做,您須更新您在開始使用通知中樞教學課程中所定義的 SendNotificationRESTAPI
方法。
在
ViewController.m
中,以下列方式更新SendNotificationRESTAPI
方法,使其接受參數作為類別標記,並會傳送正確的範本通知。- (void)SendNotificationRESTAPI:(NSString*)categoryTag { NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil delegateQueue:nil]; NSString *json; // Construct the messages REST endpoint NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@/messages/%@", HubEndpoint, HUBNAME, API_VERSION]]; // Generated the token to be used in the authorization header. NSString* authorizationToken = [self generateSasToken:[url absoluteString]]; //Create the request to add the template notification message to the hub NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setHTTPMethod:@"POST"]; // Add the category as a tag [request setValue:categoryTag forHTTPHeaderField:@"ServiceBusNotification-Tags"]; // Template notification json = [NSString stringWithFormat:@"{\"messageParam\":\"Breaking %@ News : %@\"}", categoryTag, self.notificationMessage.text]; // Signify template notification format [request setValue:@"template" forHTTPHeaderField:@"ServiceBusNotification-Format"]; // JSON Content-Type [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"]; //Authenticate the notification message POST request with the SaS token [request setValue:authorizationToken forHTTPHeaderField:@"Authorization"]; //Add the notification message body [request setHTTPBody:[json dataUsingEncoding:NSUTF8StringEncoding]]; // Send the REST request NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response; if (error || httpResponse.statusCode != 200) { NSLog(@"\nError status: %d\nError: %@", httpResponse.statusCode, error); } if (data != NULL) { //xmlParser = [[NSXMLParser alloc] initWithData:data]; //[xmlParser setDelegate:self]; //[xmlParser parse]; } }]; [dataTask resume]; }
在
ViewController.m
中更新Send Notification
動作,如下列程式碼所示。 這會使它個別使用每個標記來傳送通知,並傳送至多個平台。- (IBAction)SendNotificationMessage:(id)sender { self.sendResults.text = @""; NSArray* categories = [NSArray arrayWithObjects: @"World", @"Politics", @"Business", @"Technology", @"Science", @"Sports", nil]; // Lets send the message as breaking news for each category to WNS, FCM, and APNS // using a template. for(NSString* category in categories) { [self SendNotificationRESTAPI:category]; } }
重新建置專案,並確定您沒有建置錯誤。
執行應用程式並產生通知
按 [執行] 按鈕,以建置專案並啟動應用程式。 選取要訂閱的一些即時新聞選項,然後按 [訂閱] 按鈕。 您應該會看到一個對話方塊,表示已訂閱通知。
當您選擇 [訂閱] 時,應用程式會將選取的類別轉換成標籤,並在通知中心內為選取的標籤要求新裝置註冊。
輸入要以即時新聞形式傳送的訊息,然後按下 [傳送通知] 按鈕。 或者,執行.NET 主控台應用程式來產生通知。
每個訂閱即時新聞的裝置都會收到您剛剛傳送的即時新聞通知。
後續步驟
在本教學課程中,您已將廣播通知傳送至註冊相關類別的特定 iOS 裝置。 若要了解如何推送當地語系化的通知,請繼續進行下列教學課程: