推送和通知的區別:
- NSNotification:是看不到的
- 推送通知:是可以看到的
推送通知分類
- 本地推送通知
- 遠程推送通知
推送通知作用
可以讓不在前臺運行的App告知用戶App內部發生了什么事情
推送通知效果
- 屏幕頂部顯示一個橫幅
- 屏幕中間彈出一個UIAertView
- 鎖屏時候也照樣顯示
- 呈現的通知同時修改應用圖標
- 用戶接受的推送通知都會展示在通知中心
- 播放音效
手機設置推送通知
推送通知的使用細節
- 發送通知時,如果應用程序正在前臺運行,那么推送通知就不回顯示出來
- 點擊推送通知默認會打開發送推送通知的應用
- 不管應用是打開還是關閉,推送通知都可以如期發送
本地通知
什么是本地通知
- 顧名思義,不需要聯網就能發送的通知,無需服務器.
本地通知使用場景
- 常用來提醒用戶完成一些定時任務,比如
- 鬧鐘,清理垃圾,買衣服,看電影,睡覺,運動等
如何發送本地推送通知
推送通知也屬于UI的一部分,所以推送通知對象是以UI開頭
- 創建本地通知
// 創建本地通知對象
UILocalNotification *ln = [[UILocalNotification alloc] init];
- 設置本地通知屬性(推薦一個一個屬性測試運行)
// 1.設置通知的內容(如果此屬性不設置是不會發送通知的)
ln.alertBody = @"小明,你媽叫你回家吃飯了!";
// 2.設置通知觸發的開始時間
ln.fireDate = [NSDate dateWithTimeIntervalSinceNow:3];
// 3.設置重復通知的時間,間隔
ln.repeatInterval = NSCalendarUnitSecond;
// 4.設置重復執行使用日歷(用戶設置的日歷)
ln.repeatCalendar = [NSCalendar currentCalendar];
// NSString * const NSGregorianCalendar; 公歷
// NSString * const NSChineseCalendar; 農歷
// ln.repeatCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSChineseCalendar];
// 5.設置應用圖標右上角的數字
ln.applicationIconBadgeNumber = 3;
// 6.設置點擊推送通知進入界面的時候顯示,加載圖片
ln.alertLaunchImage = @"";
// 7 設置通知的音效(只有真機有效)
local.soundName = UILocalNotificationDefaultSoundName;
// 8 設置一些額外信息
local.userInfo = @{@"QQ":@"55555",@"info":@"約了沒"};
// iOS8.0 以后新增屬性
// ************************************
// 1.設置區域,進入或離開某個區域的時候觸發
// CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(40.1,106.1);
// ln.region = [[CLCircularRegion alloc] initWithCenter:coordinate radius:10.0 identifier:@"ab"];
// 2.設置進入或離開某個區域只執行一次
// ln.regionTriggersOnce = YES;
// ***************************************
// iOS8.2 新增屬性
// ln.alertTitle = @"通知標題";
- 使用應用[UIApplication]調度本地通知
// 讓應用調度通知
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
本地推送通知頁面跳轉
無論應用是在前臺,后臺還是已經關閉都能如期接收到本地通知,但是當用戶點擊通知進入應用的時候,我們需要根據不同情況,進行處理
AppDelegate本地通知代理方法
/**
* 一旦接收到本地通知就會調用該方法
* 注意這個方法:應用在前臺也會調用
* @param application 應用
* @param notification 本地通知對象
*/
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// 當應用在前臺時候什么都不做
if (application.applicationState == UIApplicationStateActive) {
return;
}
// 當應用不再前臺的時候才去跳轉,這樣用戶體檢更好
UITabBarController *tbVc = (UITabBarController *)application.keyWindow.rootViewController;
tbVc.selectedIndex = 1;
}
但是當應用已經退出的時候,點擊通知進入本應用時候,不在調用application:didReceiveLocalNotification:的代理方法,難道當應用退出后,用戶再進入應用我們就不再跳轉指定界面了嗎?為了更好用戶體驗,我此時也應該讓應用跳轉到指定的界面,怎么才能實現這個功能呢? 我們知道當應用程序啟動的時候一定會調用application: didFinishLaunchingWithOptions:的代理方法,在這里我們能拿到本地通知信息,也可以跳轉相應的界面
// 如果是點擊本地通知進來的那么launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]就會有內容
if(launchOptions[UIApplicationLaunchOptionsLocalNotificationKey])
{
//頁面跳轉
UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;
tbVc.selectedIndex = 1;
}
一個應用可能要各種不同的通but知,點擊不同的通知可以跳轉不同界面,這個有該怎么做呢?
1.在發送通知時候,設置userInfo屬性
// 7.設置應用信息
ln.userInfo = @{@"pageKey":@"friend"};
2.在AppDelegate本地通知代理方法中進行判斷
/**
* 一旦接收到本地通知就會調用該方法
* 注意這個方法:應用在前臺也會調用
* @param application 應用
* @param notification 本地通知對象
*/
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// 當應用在前臺時候什么都不做
if (application.applicationState == UIApplicationStateActive) {
return;
}
// 當應用不再前臺的時候才去跳轉,這樣用戶體檢更好
// 獲取tabBarController
UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;
// 獲取用戶設置的跳轉頁
NSString *page = notification.userInfo[@"pageKey"];
// 如果是朋友圈
if ([page isEqualToString:@"session"]) {
tbVc.selectedIndex = 1;
}else{
// 否則跳轉到好友
tbVc.selectedIndex = 0;
}
}
- 測試launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]中的內容
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// 獲取UIApplicationLaunchOptionsLocalNotificationKey對應內容
id obj = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
// 獲取控制器(注意此時需要通過self.window,通過application.keyWindow無法獲取到,因為此時的window還沒有成為keyWindow)
UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;
// 獲取索引為0的控制(注意此時tbVc.selectedViewController為nil)
UIViewController *vc = tbVc.viewControllers[0];
// 創建一個文本
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor brownColor];
// 設置text為UIApplicationLaunchOptionsLocalNotificationKey對應的內容
label.text = [obj description] ;
label.frame = CGRectMake(10, 100, 300, 400);
label.numberOfLines = 0;
// 添加到控制器的View上
[vc.view addSubview:label];
return YES;
}
- 我們從中可以出他是一個UILocalNotification對象
- 所以我們取出UILocalNotification對象,剩下的做法與接收到本地通知代理方法中處理相同,所以我們把它提取為一個公用的方法
/**
* 根據通知跳轉到不同頁面
*/
- (void) jumpToPageWithLocalNotification:(UILocalNotification *) notification
{
// 獲取tabBarController
UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;
// 獲取用戶設置的跳轉頁
NSString *page = notification.userInfo[@"pageKey"];
// 如果是朋友圈
if ([page isEqualToString:@"session"]) {
tbVc.selectedIndex = 0;
}else{
// 否則跳轉到好友
tbVc.selectedIndex = 1;
}
}
- 在didReceiveLocalNotification方法中
/**
* 一旦接收到本地通知就會調用該方法
* 注意這個方法:應用在前臺也會調用
* @param application 應用
* @param notification 本地通知對象
*/
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// 當應用在前臺時候什么都不做
if (application.applicationState == UIApplicationStateActive) {
return;
}
// 當應用不再前臺的時候才去跳轉,這樣用戶體檢更好
[self jumpToPageWithLocalNotification:notification];
}
- 在didFinishLaunchingWithOptions方法中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// 如果是點擊本地通知進來的那么launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]就會有內容
UILocalNotification *notifcation = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
// 如果存在通知
if(notifcation){
[self jumpToPageWithLocalNotification:notifcation];
}
return YES;
}
iOS8的不同點
你如果把上面的程序運行在iOS8上,會爆出如下錯誤
][615:7847] Attempting to schedule a local notification {fire date = Monday, July 13, 2015 at 9:02:25 AM China Standard Time, time zone = (null), repeat interval = 0, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Monday, July 13, 2015 at 9:02:25 AM China Standard Time, user info = { pageKey = friend; }} with an alert but haven't received permission from the user to display alerts
也就是在iOS8上要發送本地通知需要 請求用戶權限 如何請求用戶權限呢?一般在新版有變化的地方,在頭文件中都會有相應的說明,所以點擊到scheduleLocalNotification:方法中,看看有沒有我們需要信息
意思就是說:在iOS8.0以后,在調度通知之前你需要使用UIApplication的對象方法registerUseNotificationSetting:來請求用戶授權.
這種請求權限的代碼一般放在didFinishLaunchingWithOptions:方法中,在用戶不卸載的情況下,只需要請求一次,下次在運行就不用請求了!
// 1.如果是iOS8請求用戶權限
if ([UIDevice currentDevice].systemVersion.doubleValue >= 8.0) {
/*
UIUserNotificationType:
UIUserNotificationTypeBadge = 1 << 0, // 接收到通知可更改程序的應用圖標
UIUserNotificationTypeSound = 1 << 1, // 接收到通知可播放聲音
UIUserNotificationTypeAlert = 1 << 2, // 接收到通知課提示內容
如果你需要使用多個類型,可以使用 "|" 來連接
*/
// 向用戶請求通知權限
// categories暫時傳入nil
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
[application registerUserNotificationSettings:setting];
}
運行程序
測試點擊通知,進入應用,也沒問題
接下來,我們說說-[UIUserNotificationSettings settingsForTypes:categories:] 中的 categories
- categories可以讓我們發送通知之前預定義一些通知也就是通知上可以顯示按鈕,他需要是一個裝有UIUserNotificationCategory類的對象的NSSet的對象. 但是官方推薦我們使用它的子類UIMutableUserNotificationCategory,來動態的添加通知的行為按鈕,iOS8支持前臺和后臺的兩種行為.
- 通知Action按鈕以長條展示如圖
- 注冊分類,并在分類中添加不同的行為 由于注冊用戶通知設置代碼量比較大我們實現一個新的方法registerUserNotification
(void) registerUserNotification
{
// 向用戶請求通知權限
/*
UIUserNotificationType:用戶通知的類型
UIUserNotificationTypeBadge = 1 << 0, // 接收到通知可更改程序的應用圖標
UIUserNotificationTypeSound = 1 << 1, // 接收到通知可播放聲音
UIUserNotificationTypeAlert = 1 << 2, // 接收到通知課提示內容
如果你需要使用多個類型,可以使用 "|" 來連接
*/
// 1.設置用戶通知權限類型
UIUserNotificationType types = UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
// 2.創建通知的行為按鈕
// 2.1創建第一個行為
UIMutableUserNotificationAction *action1 = [[UIMutableUserNotificationAction alloc] init];
// 2.1.1 設置行為的唯一標示
action1.identifier = UIMutableUserNotificationActionBackground;
// 2.1.2 設置通知按鈕的的標題
action1.title = @"后臺";
// 以什么樣模式運行應用
// UIUserNotificationActivationModeForeground, // 當應用在前臺的時候觸發
// UIUserNotificationActivationModeBackground // 即使應用不在前臺也觸發
action1.activationMode = UIUserNotificationActivationModeBackground;
// 2.1.3 是否只有鎖屏的鎖屏狀態下才能顯示
action1.authenticationRequired = NO;
// 2.1.4 按鈕的性質
action1.destructive = NO;
// 2.1創建第一個行為
UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];
// 2.1.1 設置行為的唯一標示
action2.identifier =UIMutableUserNotificationActionForeground;
// 2.1.2 設置通知按鈕的的標題
action2.title = @"前臺";
// 以什么樣模式運行應用
// UIUserNotificationActivationModeForeground, // 當應用在前臺的時候觸發
// UIUserNotificationActivationModeBackground // 即使應用不在前臺也觸發
action2.activationMode = UIUserNotificationActivationModeForeground;
// 2.1.3 用戶必須輸入密碼才能執行
action2.authenticationRequired = YES;
// 2.1.4 按鈕的性質(沒有效果)
action2.destructive = YES;
// 3.創建用戶通知分類
UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
// 3.1 設置類別的唯一標識
category.identifier = @"myCategory";
// 3.2 設置通知的按鈕
// Context:
// UIUserNotificationActionContextDefault, //默認上下文(情景)下的英文(通常都是)
// UIUserNotificationActionContextMinimal //通知內容區域受限情況下內容
[category setActions:@[action1,action2] forContext:UIUserNotificationActionContextDefault];
// 4.創建用戶通知的設置信息
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:types categories:[NSSet setWithObject:category]];
// 注冊設置
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];
}
- 在發送本地推送通知時候指定通知的分類標示
// 9.設置通知的類別
ln.category = @"myCategory";
- 監聽點擊通知按鈕的行為,在AppDelegate中實現監聽通知按鈕點擊方法
/**
* 當用戶點擊通知上定制的按鈕執行的行為(注意:不點擊行為按鈕,不會進入該方法)
*
* @param application 應用
* @param identifier 行為標識符
* @param notification 本地通知
* @param completionHandler 完成回調
*/
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler
{
// 處理不同行為
if ([identifier isEqualToString:UIMutableUserNotificationActionBackground]) {
NSLog(@"后臺運行程序");
}else if ([identifier isEqualToString:UIMutableUserNotificationActionForeground]){
NSLog(@"前臺運行程序");
}else{
NSLog(@"其他");
}
/**
You should call the completion handler as soon as you've finished handling the action.
當任務處理完畢時候,你應該盡快的調用completion的block.
*/
// 在當任務完成的時候,調用任務完成的block
completionHandler();
}
iOS8 基于位置的本地通知
什么是基于位置的本地通知
- 基于位置的本地通知就是當用戶進入或離開某個區域,就會給該用戶發送一條本地通知
- 基于位置的本地通知只有在iOS8.0以后才能使用
實現步驟:
在 didFinishLaunchingWithOptions方法中注冊通知權限
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationType types = UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound;
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[application registerUserNotificationSettings:setting];
}
return YES;
}
在發送通知之前要請求使用用戶的位置權限
在info.plist增加 NSLocationWhenInUseUsageDescription 的Key,類型為String,值填寫需要提示內容
定一個 CLLocationManager 類型的屬性
@property (nonatomic, strong) CLLocationManager *locManager;
- 通過懶加載的方式其進行初始化并設置其代理
懶加載位置管理器對象
- (CLLocationManager *)locManager
{
if (_locManager == nil) {
_locManager = [[CLLocationManager alloc] init];
_locManager.delegate = self;
}
return _locManager;
}
- 發送基于位置的推送通知之前首先判斷用戶是否已經擁有了,訪問位置的權限,如果如果沒有請求權限,如果已經有就直接發送推送通知
(IBAction)baseLocationNotification {
// 請求注冊權限 if([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse){ //請求使用用戶位置權限
[self.locManager requestWhenInUseAuthorization];
}else{ // 發送基于位置本地通知
[self scheduleBaseLocationNotification];
}
}
- 監聽用戶授權的改變
- (void) locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
// 發送基于位置通知
[self scheduleBaseLocationNotification];
}
}
- 實現發送基于位置的通知方法
- (void) scheduleBaseLocationNotification
{
// 創建本地通知對象
UILocalNotification *loc = [[UILocalNotification alloc] init];
// 設置通知提示內容
loc.alertBody = @"歡迎來到傳智博客";
// 創建經緯度坐標
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(23.139009,113.363798);
// 設置觸發的區域,當用戶進入或離開這個區域的時候就會觸發
loc.region = [[CLCircularRegion alloc] initWithCenter:coordinate radius:100 identifier:@"loc"];
// 設置是否只觸發一次
// YES 表示只觸發一次(用戶進入或離開這個區域的時候觸發一次) NO 表示可以(用戶每次進入或離開這個區域的時候都會觸發)
loc.regionTriggersOnce = NO;
// 調度通知
[[UIApplication sharedApplication] scheduleLocalNotification:loc];
}
說明
- 基于位置本地通知,提醒做不到非常精確他依賴與GPS和周圍的信號基站
- 基于位置的本地通知,只有真機才能測試
- 基于位置的本地通知,無需編程人員主動獲取用戶位置,我們添加應用調度中,如果用戶手機打開了定位,系統會根據用戶當前的位置來決定是否要給該用戶發送通知.