iOS遠程推送和本地推送(一)


推送和通知的區別:
  • NSNotification:是看不到的
  • 推送通知:是可以看到的
推送通知分類
  • 本地推送通知
  • 遠程推送通知
推送通知作用

可以讓不在前臺運行的App告知用戶App內部發生了什么事情

推送通知效果
  • 屏幕頂部顯示一個橫幅
  • 屏幕中間彈出一個UIAertView
  • 鎖屏時候也照樣顯示
  • 呈現的通知同時修改應用圖標
  • 用戶接受的推送通知都會展示在通知中心
  • 播放音效
Snip20160425_9.png
手機設置推送通知
Snip20160425_10.png
推送通知的使用細節
  • 發送通知時,如果應用程序正在前臺運行,那么推送通知就不回顯示出來
  • 點擊推送通知默認會打開發送推送通知的應用
  • 不管應用是打開還是關閉,推送通知都可以如期發送

本地通知

什么是本地通知

  • 顧名思義,不需要聯網就能發送的通知,無需服務器.

本地通知使用場景

  • 常用來提醒用戶完成一些定時任務,比如
  • 鬧鐘,清理垃圾,買衣服,看電影,睡覺,運動等

如何發送本地推送通知

推送通知也屬于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;
}
Snip20160425_11.png
  • 我們從中可以出他是一個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:方法中,看看有沒有我們需要信息

Snip20160425_12.png

意思就是說:在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];
    }

運行程序

Snip20160425_13.png

測試點擊通知,進入應用,也沒問題

接下來,我們說說-[UIUserNotificationSettings settingsForTypes:categories:] 中的 categories

  • categories可以讓我們發送通知之前預定義一些通知也就是通知上可以顯示按鈕,他需要是一個裝有UIUserNotificationCategory類的對象的NSSet的對象. 但是官方推薦我們使用它的子類UIMutableUserNotificationCategory,來動態的添加通知的行為按鈕,iOS8支持前臺和后臺的兩種行為.
4月 25, 2016 16:41.gif
  • 通知Action按鈕以長條展示如圖
4月 25, 2016 16:43.gif
  • 注冊分類,并在分類中添加不同的行為 由于注冊用戶通知設置代碼量比較大我們實現一個新的方法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和周圍的信號基站
  • 基于位置的本地通知,只有真機才能測試
  • 基于位置的本地通知,無需編程人員主動獲取用戶位置,我們添加應用調度中,如果用戶手機打開了定位,系統會根據用戶當前的位置來決定是否要給該用戶發送通知.

有關遠程推送的請見下篇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容