應用程序必須進行適當配置,才可以接受本地或遠程通知。配置過程在iOS
和OS X
略有不同,但基本原理是相同的。在啟動時,您的應用程序注冊接收通知,并與系統配合來配置通知支持。一旦注冊完成,可以開始傳遞給你的應用程序創建的通知。然后,您的應用程序處理這些收到的通知,并提供相應的響應。
在IOS
和tvOS
,注冊通知被分成兩個部分:注冊所支持的用戶交互和注冊通知自己。注冊您的應用程序支持的用戶交互類型來告訴操作系統要如何通知用戶當一個通知到達時。本地或遠程通知都需要此步驟。對于遠程通知,必須執行注冊的第二步來獲得APNs
用于傳送通知的應用程序特定的設備token
。 (對于本地通知,沒有第二個注冊步驟。)在OS X
中,僅支持遠程通知應用程序才需要注冊。
注冊通知支持的用戶交互類型
在iOS8
和更高版本的系統中,使用本地或遠程通知的應用必須注冊該應用程序支持的用戶交互類型。應用程序可以要求圖標badge
,顯示警告信息,或播放聲音。當您請求這些互動類型的時候,應該先查看該用戶已允許什么類型的交互。如果用戶不允許某個特定類型的交互,系統將忽略嘗試以這種方式與用戶進行交互。例如,如果一個通知要顯示警告信息,并播放聲音,而用戶不允許聲音,系統會顯示警告信息,但不播放聲音。
要注冊您的應用程序支持的交互類型,調用registerUserNotificationSettings:
方法。使用setting object
來指定應用程序是否badge
圖標,是否顯示警告信息,或播放聲音。如果你不要求任何交互類型,系統悄悄的推送所有通知到你的應用程序。下面的代碼顯示了支持顯示警報消息,并播放聲音的應用程序的代碼段。
UIUserNotificationType types = (UIUserNotificationType) (UIUserNotificationTypeBadge |
UIUserNotificationTypeSound | UIUserNotificationTypeAlert);
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
除了注冊您的應用程序的交互類型,應用程序可以注冊一個或多個類別。類別都支持本地和遠程通知,并使用它們來標識通知的目的。你的iOS
應用程序可以使用類別標識符來決定如何處理通知。在watchOS
,類別也被用來定制顯示給用戶的通知接口。
從iOS8
開始,你可以選擇通過注冊自定義動作的通知類型創建可以執行動作的通知。當一個可執行的通知到達時,系統會為每個注冊的操作添加按鈕,并添加這些按鈕到通知界面。這些操作按鈕是用戶能夠執行相關通知任務的快捷方式。例如,對于會議的遠程通知邀請可能會提供動作來接受或拒絕該會議。當用戶點擊你的一個動作按鈕,系統會通知你的應用程序,讓你有機會可以執行相應的動作。
當應用程序第一次調用registerUserNotificationSettings:
方法,iOS
設備將提示用戶允許指定的交互。在后續應用啟動中,調用此方法不會提示用戶。調用方法后,iOS
異步的報告結果到application:didRegisterUserNotificationSettings:
方法中。當你第一次注冊你的設置,iOS在調用此方法之前等待用戶的反應,但在隨后的調用將返回現有的用戶設置。
用戶可以通過Setting app
在任何時候改變你的應用程序通知設置。由于設置可以改變,始終調用registerUserNotificationSettings:
在應用啟動時,然后使用application:didRegisterUserNotificationSettings:
方法來獲得結果。如果用戶不允許特定的通知類型,避免使用這些類型來配置你的應用程序的本地和遠程通知。
注冊遠程通知
想要接收遠程通知必須注冊蘋果推送通知服務(APNs
)來獲得一個device token
。在iOS8
和更高版本,注冊包括以下步驟:
- 在注冊應用程序的支持的用戶交互類型。
- 調用
registerForRemoteNotifications
方法來注冊遠程通知。 (在OS X
中,使用registerForRemoteNotificationTypes:
方法來注冊你的應用程序支持交互類型并在同一步中注冊遠程通知。) - 使用應用程序委托
application:didRegisterForRemoteNotificationsWithDeviceToken:
方法來接收提供遠程通知所需要的device token
。使用application:didFailToRegisterForRemoteNotificationsWithError:
方法來處理錯誤。 - 如果注冊成功,發送
device token
到用于生成遠程通知的服務器
iOS
注意:如果蜂窩或Wi-Fi連接不可用,無論是application:didRegisterForRemoteNotificationsWithDeviceToken:
方法或者application:didFailToRegisterForRemoteNotificationsWithError:
方法都不會被調用。對于Wi-Fi
連接,這有時會發生在設備不能超過配置端口連接到APNs
。如果發生這種情況,用戶可以通過連接到另一個不屏蔽所需端口的Wi-Fi
網絡,或者等iPhone
或iPad
的蜂窩數據服務變得可用。在這兩種情況下,該設備應能夠建立連接,然后委托方法被調用。
device token
是將通知推送到到特定設備上的應用程序的關鍵。Device token
可以改變,所以應用需要在每次啟動時重新注冊,并把接收到的token
回傳到你的服務器。如果無法更新設備token
,遠程通知可能不會被傳遞到設備。當用戶將備份數據恢復到新設備或電腦,或重新安裝操作系統時設備token
總是會改變。當將數據遷移到新的設備或計算機,用戶必須啟動應用程序一次,從而遠程通知可以傳送到該設備。
永遠不要緩存設備token
;總是從系統中獲得token
。如果您的應用程序之前注冊過遠程通知,再調用registerForRemoteNotifications
方法不會產生任何額外的開銷,iOS
會立即返回現有的設備token
到應用程序委托。此外,iOS會隨時調用你的委托方法當設備token
變化的時候,而不是僅僅只在你的應用程序注冊或重新注冊遠程通知的時候。
下面的代賣顯示了如何在iOS
應用中注冊遠程通知。應用程序注冊支持的動作類型后,下面的方法調用registerForRemoteNotifications
方法。在接收到設備token
后,委托方法調用自定義代碼來發送token
到服務器。在OS X
中,注冊交互類型的方法是不同的,但是用于處理注冊的委托方法是類似的。
- (void)applicationDidFinishLaunching:(UIApplication *)app {
UIUserNotificationType types = UIUserNotificationTypeBadge |
UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings
settingsForTypes:types categories:nil]; [[UIApplication sharedApplication]
registerUserNotificationSettings:mySettings];
// Register for remote notifications.
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
// Handle remote notification registration.
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
const void *devTokenBytes = [devToken bytes];
self.registered = YES; [self sendProviderDeviceToken:devTokenBytes]; // custom method
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(@"Error in registration. Error: %@", err);
}
在application︰ didFailToRegisterForRemoteNotificationsWithError︰
方法中,你應該適當地處理錯誤對象和禁用與遠程通知相關的任何功能。因為通知無論如何都不會被送達,這簡直不能更棒,因為不需要處理和顯示這些通知。
注冊可以執行動作的通知類型
可以執行動作的通知可以讓你在標準的本地和遠程通知界面上添加自定義的動作按鈕。可動作的通知給用戶一種快速且簡單的方式執行和通知相關的任務來響應通知。在iOS8
之前,通知只有一種默認的動作。在iOS8
之后,在鎖屏界面,在通知中心的通知橫幅和通知條目上都可以有一個或兩個自定義的動作按鈕。modal alert
甚至能顯示四個按鈕。當用戶點擊了其中的自定義按鈕,iOS
會通知你的應用來讓你執行該按鈕相關的任務。
注意:
OS X
并沒有這種可以執行動作的通知。
定義你的可執行動作的通知
自定義動作的配置取決于定義一個或多個類別的通知。每個類別代表應用會收到的一種類型的通知,你必須定義你的應用所支持的類別。對于每個類別中,可以定義收到該類型的通知時,用戶可能采取的動作。然后,使用iOS的registerUserNotificationSettings
注冊類別,動作和應用支持的交互類型。
每個自定義動作包括按鈕標題和iOS要顯示給用戶的信息當用戶選擇該按鈕時。通過創建UIMutableUserNotificationAction類的實例并適當配置其屬性來產生一個動作。下面的代碼創建一個單一的“accept”動作。
UIMutableUserNotificationAction *acceptAction = [[UIMutableUserNotificationAction alloc] init];
// The identifier that you use internally to handle the action. acceptAction.identifier = @"ACCEPT_IDENTIFIER";
// The localized title of the action button.
acceptAction.title = @"Accept";
// Specifies whether the app must be in the foreground to perform the action. acceptAction.activationMode = UIUserNotificationActivationModeBackground;
// Destructive actions are highlighted appropriately to indicate their nature. acceptAction.destructive = NO;
// Indicates whether user authentication is required to perform the action. acceptAction.authenticationRequired = NO;
創建任何自定義操作對象后,分配這些對象到UIUserNotificationCategory
用于定義你的應用的通知類別。如果在啟動時配置通知類別,通常創建UIMutableUserNotificationCategory
類的一個實例。分配類別標識符到新的實例并使用setActions:forContext:
方法來與該類別的自定義動作聯系起來。上下文參數,可以讓你對不同的系統界面制定不同的動作。默認的上下文情況支持在modal alert
時顯示四個動作。最小的context
只支持兩個動作,在鎖屏界面,通知橫幅,和通知中心中。
下面的例子顯示了一個邀請的類別,其中包括來自上面代碼中的accept
按鈕和兩個額外的動作。在這個例子中,最小的上下文僅顯示接受和拒絕按鈕。如果沒有指定最小上下文的動作,那么最前面的兩個按鈕就會被顯示。按鈕的順序決定了它們在屏幕上顯示的順序。
// First create the category
UIMutableUserNotificationCategory *inviteCategory = [[UIMutableUserNotificationCategory alloc] init];
// Identifier to include in your push payload and local notification
inviteCategory.identifier = @"INVITE_CATEGORY";
// Set the actions to display in the default context
[inviteCategory setActions:@[acceptAction, maybeAction, declineAction] forContext:UIUserNotificationActionContextDefault];
// Set the actions to display in a minimal context
[inviteCategory setActions:@[acceptAction, declineAction] forContext:UIUserNotificationActionContextMinimal];
創建完通知動作類別后必須注冊這些類別。應用可以注冊任意數量的類別,但是每個列別必須是唯一的。
NSSet *categories = [NSSet setWithObjects:inviteCategory, alarmCategory, ...
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:categories];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
通知的類型和動作的類別都是使用UIUserNotificationSettings
的類方法settingsForTypes:categories:
來注冊,只是一個的categories
參數為nil
。
觸發可動作的通知
為了顯示你定義好的可動作的通知,你必須推送一個遠程通知或者觸發一個本地通知。在遠程通知的情況下你必須在payload中包括類別的標識符(Code2-1)。對類別的支持是你的應用程序和推送服務器之間的合作完成的。當你的服務器想推送一個通知給用戶,它可以在payload中添加合適的類別值。如果iOS得到一個有類別值的推送通知,它會在應用中搜索注冊過的有一樣值的類別,如果找到匹配的就會顯示響應的動作按鈕。
推送的payload的大小被HTTP/2提供的API限制,在2015年12月是4KB。(在2014年,Apple在遺留的二進制接口中把payload的大小限制從256字節提高到2KB)
Code2-1:
{
"aps": {
"alert": "You're invited!",
"category": "INVITE_CATEGORY"
}
}
在本地通知的情況下,你像平常一樣創建通知,設置動作類別,然后觸發通知。代碼如下:
UILocalNotification *notification = [[UILocalNotification alloc] init];
. . .
notification.category = @"INVITE_CATEGORY";
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
處理可動作通知
如果你的應用不是在前臺運行,當用戶滑動或者點擊通知時,iOS
會在前臺啟動你的應用然后調用application:didFinishLaunchingWithOptions:
并在options
字典中包括本地或遠程通知。在遠程通知的情況下,系統還會調用application:didReceiveRemoteNotification:fetchCompletionHandler:
。
如果你的應用已經在前臺,iOS
就不會顯示這個通知。相反,iOS
會調用application:didReceiveLocalNotification:
或者application:didReceiveRemoteNotification:fetchCompletionHandler:
。(如果你沒有實現application:didReceiveRemoteNotification:fetchCompletionHandler:
,iOS會調用application:didReceiveRemoteNotification:
)
最后,為了能在iOS8
或之后的系統里處理自定義動作,你必須實現下面兩個方法中的至少一個:application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
,application:handleActionWithIdentifier:forLocalNotification:completionHandler:
。這兩張情況下你都能得到動作標識符,可以用它來確定用戶點擊的哪個動作。你也會得到本地或遠程通知,你可以用它來獲得任何關于這個動作的信息。最后系統會傳遞給你一個completion handler
,當你處理完這個動作之后你必須調用這個handler
。下面代碼顯示了一個自定義動作處理的方法:
- (void)application:(UIApplication *) application
handleActionWithIdentifier: (NSString *) identifier
// either forLocalNotification: (NSDictionary *) notification or
forRemoteNotification: (NSDictionary *) notification
completionHandler: (void (^)()) completionHandler {
if ([identifier isEqualToString: @"ACCEPT_IDENTIFIER"]) {
[self handleAcceptActionWithNotification:notification];
}
// Must be called when finished
completionHandler();
}
觸發本地通知
在iOS
中,你創建一個UILocalNotification
的實例然后使用UIApplication
的scheduleLocalNotification:
方法來設置通知的觸發。在OS X
中,你創建一個NSUserNotification
的實例,然后NSUserNotificationCenter
負責設置傳遞它。(OS X
應用也可以實現NSUserNotificationCenterDelegate
協議來自定義NSUserNotificationCenter
的行為。)
在iOS中創建和觸發本地通知需要你執行以下步驟:
- 在iOS8或更高的系統版本中,需要注冊通知類型。(在OS X和早期的iOS版本中,你只需要為遠程通知注冊通知類型)。如果你已經注冊了通知類型,則可以使用
currentUserNotificationSettings
來獲取用戶在應用中接受的通知類型。 - 創建一個
UILocalNotification
實例。 - 設置一個系統觸發通知的日期和時間。這就是
fireDate
屬性。
如果你設置timeZone
屬性為當前語言環境的NSTimeZone
實例,那么系統會自定調整觸發時間當設備進入到不同的時區。
你也可以設置固定時間間隔來觸發本地通知(每日,每周,每月,等等) - 適當的配置
alert
,icon badge
,sound
。這樣系統觸發通知時就會使用這些配置來展示通知的界面。-
alert
有message
,動作按鈕的title
,和slider
(alertAction
)屬性。給它們指定一個本地化的字符串值。如果通知可以在Apple Watch
上顯示,也給alertTitle
屬性設置一個值。 - 使用
applicationIconBadgeNumber
屬性來給應用的圖標上設置一個badge number
. - 給
soundName
屬性設置值來播放聲音。你可以直接設置應用程序的資源包中的一個非本地化的文件名來設置屬性值,也可以使用UILocalNotificationDefaultSoundName
來獲得默認的系統聲音。播放聲音應該和其他兩種中至少一種同時作用,而不應該僅僅只是單獨播放聲音。
-
- 另外你也可以使用
userInfo
屬性為通知添加自定義的數據。例如:當一個CloudKit
記錄更改后所觸發的通知中就包括這條紀錄的標識符,因此handler
就能夠得到這條紀錄并更新它。 - 另外在iOS8之后的系統中,本地通知也可以使用自定義可動作的通知,因此你的應用可以執行相應的動作來響應用戶交互。
- 安排本地通知的交付給系統。
使用scheduleLocalNotification:
來交付通知給系統。系統使用UILocalNotification
實例中的fire date
來觸發通知。或者你也可以使用presentLocalNotificationNow:
來立即觸發這個通知。
下面的代碼模擬一個to-do list
的應用在待辦事件即將到來前通知用戶。有幾個地方需要注意,alertBody
,alertAction
,alertTitle
屬性都是主bundle
中的本地化字符串。它也在userInfo
屬性中添加了待辦事項的名字。
- (void)scheduleNotificationWithItem:(ToDoItem *)item interval:(int)minutesBefore {
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:item.day];
[dateComps setMonth:item.month];
[dateComps setYear:item.year];
[dateComps setHour:item.hour];
[dateComps setMinute:item.minute];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = [itemDate dateByAddingTimeIntervalInterval:- (minutesBefore*60)];
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"%@ in %i minutes.", nil), item.eventName, minutesBefore];
localNotif.alertAction = NSLocalizedString(@"View Details", nil);
localNotif.alertTitle = NSLocalizedString(@"Item Due", nil);
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 1;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:item.eventName forKey:ToDoItemKey];
localNotif.userInfo = infoDict;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
你可以通過調用cancelLocalNotification
來取消特定的通知,也可以使用cancelAllLocalNotifications
來取消所以的本地通知。這兩張手動取消通知的方法都會關閉正在顯示的通知。
應用也會發現本地通知非常有用當它們在后臺運行的時候,當有用戶感興趣的新消息,數據和其他的一些東西出現時。這種情況下,應用可以使用presentLocalNotificationNow:
來立即觸發一個本地通知。(iOS
允許應用在后臺允許一小段時間)
處理本地和遠程通知
當通知被交付時而應用不再前臺運行時。這種情況下,系統顯示這個通知,顯示一個alert
,badge app icon
,或者播放一個聲音,顯示一個或多個動作按鈕讓用戶點擊。
用戶點擊iOS8系統通知中一個動作按鈕。這種情況下,iOS調用application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
或者application:handleActionWithIdentifier:forLocalNotification:completionHandler:
。在上面兩種情況下,你都能得到按鈕的標識符以此來判斷用戶點擊的哪個按鈕。你也可以得到本地或者遠程的通知,來獲取你需要的數據。
用戶點擊了默認的動作按鈕或者點擊了應用的圖片。如果默認的動作按鈕被用戶點擊,系統會啟動應用程序然后調用application:didFinishLaunchingWithOptions:
傳入通知的payload
或者本地通知對象。雖然application:didFinishLaunchingWithOptions:
這個方法里不是處理通知的最佳時機,但是在這里獲取通知的payload
可以讓你有機會在handler
方法調用之前開始處理和通知相關的操作。
對于遠程通知,系統也會調用application:didReceiveRemoteNotification:fetchCompletionHandler:
如果在OS X上用戶點擊了應用圖標,應用會調用applicationDidFinishLaunching:
方法,然后應用代理可以獲得遠程通知。如果在iOS上點擊應用圖標,應用也會調用相同的方法,但是并不能獲取通知內容。
當通知被交付時應用程序在前臺運行。應用會調用application:didReceiveRemoteNotification:fetchCompletionHandler:
或者application:didReceiveLocalNotification:
。(如果application:didReceiveRemoteNotification:fetchCompletionHandler:
方法沒有實現,系統會調用application:didReceiveRemoteNotification:
這個方法).在OS X中,系統會調用application:didReceiveRemoteNotification:
方法。
應用程序可以使用傳入的遠程通知的payload
或者在iOS中使用UILocalNotification
的實例來幫助設置上下文處理通知相關的操作。在理想的情況下,應用代理在不同的平臺執行下面的操作來傳遞遠程和本地通知:
- 對于OS X,應用代理會遵循
NSApplicationDelegate
協議,實現application:didReceiveRemoteNotification:
方法 - 對于iOS,應用代理會遵循
UIApplicationDelegate
代理,實現application:didReceiveRemoteNotification:fetchCompletionHandler:
或者application:didReceiveLocalNotification:
方法。為了響應通知動作,實現application:handleActionWithIdentifier:forLocalNotification:completionHandler:
或者application:handleActionWithIdentifier:forRemoteNotification:completionHandler:
下面的代碼實現了application:didFinishLaunchingWithOptions:
方法來處理本地通知。它從options
字典中使用UIApplicationLaunchOptionsLocalNotificationKey
鍵得到了一個UILocalNotification
的實例。從UILocalNotification
實例的userInfo
字典中訪問到to-do
事項并設置應用的初始上下文。
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
NSString *itemName = [localNotif.userInfo objectForKey:ToDoItemKey];
[viewController displayItem:itemName]; // custom method
app.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber-1;
}
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
遠程通知的實現也是類似的,除了你必須在每個平臺定義一個常量作為鍵來訪問通知的payload
以外:
- 在iOS中,在應用代理的
application:didFinishLaunchingWithOptions:
方法中使用UIApplicationLaunchOptionsRemoteNotificationKey
鍵來獲取options
字典中的通知的payload
。 - 在OS X中,在應用代理的
applicationDidFinishLaunching:
方法中使用NSApplicationLaunchUserNotificationKey
鍵從傳入的NSNotification
對象的userInfo
屬性中獲取payload
字典。
payload
是一個字典包含通知的alert
消息,badge number
,和聲音等等。它也能包含應用程序用來設置初始的用戶界面時的自定義數據。
重要提示:遠程通知的交付沒有保證,所以你不應該使用通知來傳遞敏感數據或不能用其他方式獲得得數據。
當在應用代理的方法中處理遠程通知時,應用代理會執行額外的任務。在應用啟動后,代理應該和服務器連接然后下載數據。
注意:客戶端應用應該總是和服務器異步或者在次要線程通信。
下面的代碼顯示了應用在前臺運行時application:didReceiveLocalNotification:
方法的實現。
- (void)application:(UIApplication *)app didReceiveLocalNotification: (UILocalNotification *)notif {
NSString *itemName = [notif.userInfo objectForKey:ToDoItemKey];
[viewController displayItem:itemName]; // custom method
app.applicationIconBadgeNumber = notification.applicationIconBadgeNumber - 1;
}
如果你想在應用在前臺運行時獲取遠程通知,你應該實現application:didReceiveRemoteNotification:fetchCompletionHandler:
方法。
觸發基于位置的本地通知
在iOS8
和之后的系統中,可以創建基于地理位置的本地通知。當用戶到達特定的地理位置區域時可以觸發本地通知。UILocalNotification
對象可以用一個Core Location region
實例來配置。當用戶進入或者離開時會觸發相應的本地通知。你可以配置只觸發一次或者在用戶每次進入或離開時都觸發本地通知。
注冊基于位置的本地通知
基于地理位置的本地通知需要應用支持Core Location
。你必須配置一個CLLocationManager
和對應的代理,然后向用戶請求定位服務。代碼如下:
CLLocationManager *locMan = [[CLLocationManager alloc] init];
// Set a delegate that receives callbacks that specify if your app is allowed to track the user's location
locMan.delegate = self;
// Request authorization to track the user’s location and enable location-based local notifications
[locMan requestWhenInUseAuthorization];
當你第一次申請定位服務時,iOS
會請求用戶同意或者拒絕應用的定位服務。iOS
會使用Info.plist
文件中NSLocationWhenInUseUsageDescription
鍵所對應的文本來顯示說明文字。如果要啟動定位服務一定要包含這個鍵,否則iOS
不會啟動定位服務。
當應用在后臺或者被掛起時,用戶可能也可以看到基于地理位置的本地通知。然而,應用并不會收到任何回調,直到用戶與alert
交互應用才被允許獲取用戶的位置。
處理地理位置回調
在應用啟動時,你應該檢查位置通知的授權狀態以此開啟或者關閉位置通知。你必須處理的從Core Location
返回的代理回調是locationManager:didChangeAuthorizationStatus:
,這個方法里面會告訴你授權的狀態。首先,通過回調中kCLAuthorizationStatusAuthorizedWhenInUse
檢查授權狀態--這意味著你的應用被允許來跟蹤用戶的位置。然后你就可以開始安排你的本地通知了。
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
// Check status to see if the app is authorized
BOOL canUseLocationNotifications = (status ==
kCLAuthorizationStatusAuthorizedWhenInUse);
if (canUseLocationNotifications) {
[self startShowingLocationNotifications]; // Custom method defined below
}
}
下面的代碼展示了如何創建一個基于地理位置的通知。就像普通的本地通知一樣,你首先得創建一個UILocalNotification
對象然后設置它的類型,這個例子中是一個alert
。
- (void)startShowingNotifications {
UILocalNotification *locNotification = [[UILocalNotification alloc] init];
locNotification.alertBody = @“You have arrived!”;
locNotification.regionTriggersOnce = YES;
locNotification.region = [[CLCircularRegion alloc] initWithCenter:LOC_COORDINATE radius:LOC_RADIUS
identifier:LOC_IDENTIFIER];
[[UIApplication sharedApplication] scheduleLocalNotification:locNotification];
}
假設應用不在前臺運行當用戶到達上面代碼指定的區域時,iOS會顯示一個警告:"你已經到了"。下面一行指定當用戶進入或離開此區域時警報只在第一次顯示。這是默認的行為。但是如果對于應用來說必須每次都顯示,就可以把它設置為NO
。
然后,你創建了一個CLCircularRegion
對象,并把它設置到UILocalNotification
對象的origin
屬性。這個例子中我們使用了CLCircularRegion
但是你也可以使用CLBeaconRegion
或者任何CLRegion
的子類。
最后,在UIApplication
上調用scheduleLocalNotification
來派發這個通知。
處理基于位置的通知
假設應用被掛起時用戶進入了上面指定的位置,一個顯示"你來了"的警報會顯示出來。你可以在application:didFinishLaunchingWithOptions:
方法里面處理本地通知,或者當用戶進入指定的區域時你的應用在前臺運行,你的應用代理會收到application:didReceiveLocalNotification:
消息。
處理位置通知的邏輯對于application:didFinishLaunchingWithOptions:
和application:didReceiveLocalNotification:
非常相似。這兩個方法都會提供一個有origin
屬性的本地通知,如果origin
屬性不為nil
,那么這就是一個位置通知。代碼如下:
- (void)application:(UIApplication *)application didReceiveLocalNotification: (UILocalNotification *)notification {
CLRegion *region = notification.region;
if (region) {
[self tellFriendsUserArrivedAtRegion:region];
}
}
最后,請記住當用戶取消應用的定位授權時application:didReceiveLocalNotification:
方法不會被調用。
準備自定義的警報聲音
對于iOS中的遠程通知,你可以指定自定義的聲音當iOS顯示本地或遠程通知時播放這個聲音。聲音文件可以在應用的主bundle
中,也可以在應用的數據容器的Library/Sound
文件夾中。
自定義的聲音由iOS的音頻硬件播放出來,所以必須是下面的格式:
Linear PCM
MA4(IMA/IDPCM)
μLaw
aLaw
你可以使用aiff
,wav
,caf
打包聲音文件。然后在Xcode
中添加這些聲音文件到bundle
或者到Library/Sound
目錄。
你可以使用afconvert
來轉換不同的音頻文件。例如,可以使用下面的命令來把16
位的linear PCM
的系統聲音Submarine.aiff
轉化為CAF
文件格式的IMA4
音頻:
afconvert /System/Library/Sounds/Submarine.aiff ~/Desktop/sub.caf -d ima4 -f caff -v
可以通知把聲音文件在Quick Player
中打開然后使用Show Movie Inspector
來檢查音頻的格式。
自定義的聲音不能超過30s,如果超過這個限制,iOS不會使用這個音頻文件而使用默認的系統聲音來播放。
傳給服務器當前設備的語言選項
如果應用程序不使用遠程通知的aps
字典中的loc-key
和loc-args
來獲取本地化的警告消息,那么服務器需要提前本地化通知中的警報消息。要做到這一點,服務器需要知道設備的當前語言選項。然后應用需要傳給服務器一個當前語言的標示,如en
或者fr
。
下面的代碼展示了如何獲取當前的語言并回穿給服務器。在iOS中,NSLocale
的preferredLanguages
屬性一個只包含一個對象的數組:一個NSString
對象表示當前的語言選項。UTF8String
使用utf-8
編碼把該字符串轉換成c
字符串。
NSString *preferredLang = [[NSLocale preferredLanguages] objectAtIndex:0];
const char *langStr = [preferredLang UTF8String];
[self sendProviderCurrentLanguage:langStr]; // custom method
}
應用需要在用戶每次改變語言設置時都把語言選項發送給服務器。通過監聽NSCurrentLocaleDidChangeNotification
通知然后在回調中得到語言標示然后傳給服務器,可以做到這一點。
如果設備的語言并不是應用支持的語言,服務器需要一種廣泛使用的語言來本地化警告消息文本,如英語或西班牙語。