iOS推送之本地推送
來自: http://ios.jobbole.com/83949/
寫此文的原因可見此文章的姊妹篇 iOS推送之遠程推送(iOS Notification Of Remote Notification) ,如果你看過了它的姊妹篇,了解過了遠程推送,那么再來看此本地推送,真真是易如反掌啊!
此篇文章的邏輯如下圖所示:
圖0-0 此篇文章的邏輯圖
本地推送介紹
本地推送和遠程推送的功能是一樣的,都是要提醒用戶去做某些事情。但是和遠程推送不同的就是本地推送是不需要設備聯網的,而遠程推送是必需要設備聯網的,因為只有聯網狀態下,才能和蘋果的APNs服務器建立長連接,從而推送消息。本地推送是由App自己設定的,并且發送給安裝此App的這臺設備,屬于一對一的對應關系。
本地推送適合 日歷 to-do list 等類型的App,注意:一個App最多只能設置64個本地推送,當超過此限制的時候,系統會自動忽略多余的本地推送,而保留能最快觸發的64個。循環的本地推送會被系統認為是同一個本地推送。
本地推送應用
iOS8本地推送注冊
iOS8之后推送要求必須注冊App支持的用戶交互類型,注冊代碼和遠程推送注冊代碼相同如下
Objective-C
// iOS8注冊本地通知類型 UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];</pre>
// iOS8注冊本地通知類型 UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; UIUserNotificationSettings *settings = [UIUserNotificationSettingssettingsForTypes:typescategories:nil]; [[UIApplication sharedApplication]registerUserNotificationSettings:settings];</div>基本應用
UILocalNotification的基本屬性
Objective-C
fireDate:啟動時間 timeZone:啟動時間參考的時區 repeatInterval:重復推送時間(NSCalendarUnit類型),0代表不重復 repeatCalendar:重復推送時間(NSCalendar類型) alertBody:通知內容 alertAction:解鎖滑動時的事件 alertLaunchImage:啟動圖片,設置此字段點擊通知時會顯示該圖片 alertTitle:通知標題,適用iOS8.2之后 applicationIconBadgeNumber:收到通知時App icon的角標 soundName:推送是帶的聲音提醒,設置默認的字段為UILocalNotificationDefaultSoundName userInfo:發送通知時附加的內容 category:此屬性和注冊通知類型時有關聯,(有興趣的同學自己了解,不詳細敘述)適用iOS8.0之后region:帶有定位的推送相關屬性,具體使用見下面【帶有定位的本地推送】適用iOS8.0之后 regionTriggersOnce:帶有定位的推送相關屬性,具體使用見下面【帶有定位的本地推送】適用iOS8.0之后</pre>
fireDate:啟動時間 timeZone:啟動時間參考的時區 repeatInterval:重復推送時間(NSCalendarUnit類型),0代表不重復 repeatCalendar:重復推送時間(NSCalendar類型) alertBody:通知內容 alertAction:解鎖滑動時的事件 alertLaunchImage:啟動圖片,設置此字段點擊通知時會顯示該圖片 alertTitle:通知標題,適用iOS8.2之后 applicationIconBadgeNumber:收到通知時App icon的角標 soundName:推送是帶的聲音提醒,設置默認的字段為UILocalNotificationDefaultSoundName userInfo:發送通知時附加的內容 category:此屬性和注冊通知類型時有關聯,(有興趣的同學自己了解,不詳細敘述)適用iOS8.0之后 region:帶有定位的推送相關屬性,具體使用見下面【帶有定位的本地推送】適用iOS8.0之后 regionTriggersOnce:帶有定位的推送相關屬性,具體使用見下面【帶有定位的本地推送】適用iOS8.0之后</div>Example
Objective-C
- (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];
}</pre>
- (void)scheduleNotificationWithItem:(ToDoItem *)iteminterval:(int)minutesBefore { NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar]; NSDateComponents *dateComps = [[NSDateComponents alloc]init]; [dateCompssetDay:item.day]; [dateCompssetMonth:item.month]; [dateCompssetYear:item.year]; [dateCompssetHour:item.hour]; [dateCompssetMinute:item.minute]; NSDate *itemDate = [calendardateFromComponents:dateComps]; UILocalNotification *localNotif = [[UILocalNotification alloc]init]; if (localNotif == nil) return; localNotif.fireDate = [itemDatedateByAddingTimeIntervalInterval:-(minutesBefore*60)]; localNotif.timeZone = [NSTimeZone defaultTimeZone]; localNotif.alertBody = [NSStringstringWithFormat: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 = [NSDictionarydictionaryWithObject:item.eventNameforKey:ToDoItemKey]; localNotif.userInfo = infoDict; // 設置好本地推送后必須調用此方法啟動此推送 [[UIApplication sharedApplication]scheduleLocalNotification:localNotif]; }</div>取消本地推送的方法
Objective-C
// 取消某一個本地推送 [[UIApplication sharedApplication] cancelLocalNotification:notification]; // 取消所有的本地推送 [[UIApplication sharedApplication] cancelAllLocalNotifications];// 取消某一個本地推送 [[UIApplication sharedApplication]cancelLocalNotification:notification]; // 取消所有的本地推送 [[UIApplication sharedApplication]cancelAllLocalNotifications];</div>收到本地通知時的回調方法
application: didFinishLaunchingWithOptions:此方法在程序第一次啟動是調用,也就是說App從Terminate狀態進入Foreground狀態的時候,根據方法內代碼判斷是否有推送消息。
Objective-C
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // userInfo為收到遠程通知的內容 NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; if (userInfo) { // 有推送的消息,處理推送的消息 } return YES; }- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // userInfo為收到遠程通知的內容 NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]; if (userInfo) { // 有推送的消息,處理推送的消息 } return YES; }</div>application: didReceiveLocalNotification:如果App處于Background狀態時,只用用戶點擊了通知消息時才會調用該方法;如果App處于Foreground狀態,會直接調用該方法。
Objective-C
- (void)application:(UIApplication )application didReceiveLocalNotification:(UILocalNotification )notification {}</pre>
- (void)application:(UIApplication *)applicationdidReceiveLocalNotification:(UILocalNotification *)notification { }</div>帶有定位的本地推送
iOS8之后,本地推送可以創建帶有定位的本地推送,當用戶進入這一指定的區域的時候就會發送此推送。并且可以指定此消息是只發送一次,還是每次用戶進入此區域的時候都發送此推送。設置此屬性對應的屬性字段為:regionTriggersOnce。
開啟定位服務
注冊帶有定位的推送必要要求用戶開啟定位功能,授權使用定位服務
Objective-C
// 獲得授權去追蹤用戶的位置 CLLocationManager *locManager = [[CLLocationManager alloc] init]; locManager.delegate = self; [locManager requestWhenInUseAuthorization];// 獲得授權去追蹤用戶的位置 CLLocationManager *locManager = [[CLLocationManager alloc]init]; locManager.delegate = self; [locManagerrequestWhenInUseAuthorization];</div>當你第一次請求使用授權定位服務的時候,系統會詢問用戶是同意還是拒絕。為了提醒用戶,系統會顯示一些在Info.plist中 NSLocationWhenInUseUsageDescription 此key值對應的額外信息。使用定位服務此key值一定要配置。只有用戶同意了此App訪問他的位置信息,此App才會接收到回到方法。
處理定位回調
首先要檢查用戶對定位服務的授權狀態,只有用戶授權了可以訪問用戶的位置信息,才會回調以下方法
Objective-C
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { //檢查狀態判斷App是否授權 if (status == kCLAuthorizationStatusAuthorizedWhenInUse) { // 設置通知 [self startShowingLocationNotifications]; } } // 設置通知
(void)startShowingLocationNotifications {
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]; } // 收到本地通知的時候,回調此方法,處理通知
(void)application:(UIApplication )application didReceiveLocalNotification: (UILocalNotification )notification {
if (notification.region) {
[self tellUserArrivedAtRegion:region];
} }</pre>
- (void)locationManager:(CLLocationManager *)managerdidChangeAuthorizationStatus:(CLAuthorizationStatus)status { //檢查狀態判斷App是否授權 if (status == kCLAuthorizationStatusAuthorizedWhenInUse) { // 設置通知 [self startShowingLocationNotifications]; } } // 設置通知- (void)startShowingLocationNotifications { UILocalNotification *locNotification = [[UILocalNotification alloc]init]; locNotification.alertBody = @"You have arrived!"; locNotification.regionTriggersOnce = YES; locNotification.region = [[CLCircularRegion alloc]initWithCenter:LOC_COORDINATEradius:LOC_RADIUSidentifier:LOC_IDENTIFIER]; [[UIApplication sharedApplication]scheduleLocalNotification:locNotification]; } // 收到本地通知的時候,回調此方法,處理通知
(void)application:(UIApplication )applicationdidReceiveLocalNotification: (UILocalNotification )notification { if (notification.region) { [selftellUserArrivedAtRegion:region]; } }</pre> </div>
本地推送使用注意(本地推送的坑)
本地推送的準確率和到達率都是秒殺遠程推送的,但是本地推送也有一些問題,處理不善的話很容易讓用戶誤解的。本地推送無論是在App處于什么狀態,當有消息的時候,在手機下拉的Notifications中都是會有顯示的。當App不是處于Foreground狀態的時候,都是會有banner通知的,但是當App處于Foreground狀態時,通知還是會一樣發出,而且手機下拉Notifications中會有磁條通知,但是banner并不會出現。這樣就會引起一個時間錯覺問題。而且本地推送手機下拉Notifications中的消息顯示,當用戶打開App的時候不會消失的啊。只有用戶點擊此條消息或者直接給清除掉才會消息的啊。做此功能的時候,一直被說本地推送不準啊,我都同步數據了,為什么還讓同步,經過幾番測試,最終發現原因出于此,不知道算不算系統的一個bug。
Example
我設置一條推送,內容是提醒用戶去同步數據,此推送觸發條件是(每天10:00,并且用戶沒有同步數據),當用戶同步完數據,我就取消這個提醒。假設一用戶在9:55的時候打開App,一直使用到10:05,這時提醒用戶去同步數據的推送消息已經發出,由于App處于Foreground狀態下并沒有出現banner提醒,用戶并不知道有消息提醒,這時他去同步數據,然后退出App,手機下拉Notifications中會有提示去同步數據的這條推送消息啊,這時用戶就會很郁悶。。。他的表情一定是這樣的:
![]()
總結
本地推送相比遠程推送是簡單的多了。但是在項目實際運用中會有各種復雜的邏輯判讀,達到什么條件,什么時間在去推送;這些業務相關邏輯就都需要客戶端去寫了。不比遠程推送,這些業務邏輯是在服務端處理。我們要做的就是收到推送消息,然后再處理就可以了。另外iOS8出的帶有定位的本地推送這個功能自我感覺還是比較好玩的。其中可能還有本篇沒有提到的一些本地推送相關知識,有什么好的想法,也歡迎你私密我一起討論,共同進步。關于遠程推送參看此文姊妹篇 iOS推送之遠程推送(iOS Notification Of Remote Notification)
參考
本文由用戶 pub10 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!相關經驗
相關資訊
sesese色