iOS-APNS(推送)

iOS-APNS(Apple Push Notification service)

推送介紹: 在我們手機聯(lián)網(wǎng)的時候愕难,會自動與蘋果服務(wù)器進行一個鏈接惫霸,這個鏈接叫長鏈接葱弟,所以我們才可以接受到推送通知,斷網(wǎng)的情況下是不可能接受到推送通知的硅卢。

(這里補充一個小知識:就是我們平時用的HTTP就是屬于短鏈接妖混,你請求一次,就給你反饋一次相應(yīng)的數(shù)據(jù)或者狀態(tài)信息)


當我們的手機軟件抬旺,已經(jīng)退出了或者程序被殺死了祥楣,但是我們還是會受到推送消息。因為蘋果為我們提供了一個服務(wù)器责鳍,這個服務(wù)器叫“APNS服務(wù)器”兽间。這個服務(wù)器就是專門用來推送通知的。只要你的手機聯(lián)網(wǎng)嘀略,你的手機就會與這個服務(wù)器進行一個長鏈接。

舉個例子:

比如一個xx服務(wù)器想要單獨給使用他們軟件的其中一個用戶推送一個消息咒程,這個消息想想告訴用戶一些信息如:版本更新消息或者購買某一個商品的狀態(tài)信息等等讼育。這個xx服務(wù)器就會把這條消息,和deviceToken信息發(fā)給蘋果的APNS服務(wù)器饥瓷,蘋果APNS服務(wù)器就會根據(jù)這個deviceToken忧饭,找到對應(yīng)的設(shè)備,然后推送給他刺洒。

deviceToken:手機的UDID + APP的BundleID
(每個手機的UDID都不一樣,可以說是手機的生份證)
屏幕快照 2018-04-23 下午7.40.45.png

deviceToken的來源:(上圖)

deviceToken并不是在手機上生成的
是當初手機安裝這個軟件的時候鼎文,它把手機的UDID和安裝這個軟件的BundleID發(fā)送給蘋果的APNS服務(wù)器
蘋果的APNS服務(wù)器就會把接受的UDID和BundleID進行加密生成我們的deviceToken
然后就會把這個deviceToken在返回給我們
我們就可以拿到這個deviceToken傳給xxx軟件的服務(wù)器
這個服務(wù)器就會把deviceToken存到數(shù)據(jù)庫

發(fā)送流程:

服務(wù)器要發(fā)生一條通知消息因俐,首先會去數(shù)據(jù)庫找到,要推送用戶的deviceToken
找到了之后就會把推送的消息和deviceToken一起發(fā)給蘋果的PANS服務(wù)器
然后蘋果的就會根據(jù)這個deviceToken撑帖,進行解析找到相應(yīng)的設(shè)備澳眷,進行推送

簡單來說就是根據(jù)UDID找到你手機 在根據(jù)BundleID,找到手機上對應(yīng)的BundleID

一.獲取deviceToken代碼:

iOS8以前
    /**
     *枚舉類型
     UIRemoteNotificationTypeNone    = 0,   //不接收推送消息
     UIRemoteNotificationTypeBadge   = 1 << 0, 接收圖標數(shù)字
     UIRemoteNotificationTypeSound   = 1 << 1, 接收時的音效
     UIRemoteNotificationTypeAlert   = 1 << 2, 接收消息文字彈窗
     UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3, 接收訂閱消息
     */
    UIRemoteNotificationType  type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
    /**
     當用戶第一次啟動程序的時候就獲取deviceToken
     該方法在iOS8就過期le
     */
    //調(diào)用該方法衷敌,系統(tǒng)就會自動發(fā)送UDID和當前程序的BundleID到蘋果的APNS服務(wù)器
    [application registerForRemoteNotificationTypes:type];

iOS8~iOS10
//ios8以后的
        /**
         UIUserNotificationTypeNone = 0,
         UIUserNotificationTypeBadge = 1 << 0,
         UIUserNotificationTypeSound = 1 << 1,
         UIUserNotificationTypeAlert = 1 << 2
         */
        UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type categories:nil];
        //注冊通知類型
        [application registerUserNotificationSettings:setting];
        //申請使用通知
        [application registerForRemoteNotifications];
iOS10.0后新的推送方式

首先要添加頭文件
import <UserNotifications/UserNotifications.h>
設(shè)置代理<UNUserNotificationCenterDelegate>

 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            
            if (!error) {
                NSLog(@"succeeded!");
            }
        }];

二.獲取到deviceToken后會調(diào)

/**
 獲取到用戶當前程序的deviceToken后會會調(diào)這個方法
 */
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    
    NSLog(@"%@",deviceToken);
    //在這里我們就可以把deviceToken上傳給我我們軟件的服務(wù)器
    //deviceToken:就是我們需要的deviceToken缴罗;
//    NSString *token=[NSString stringWithFormat:@"%@",deviceToken];
//    token=[token stringByReplacingOccurrencesOfString:@"<" withString:@""];
//    token=[token stringByReplacingOccurrencesOfString:@">" withString:@""];
//    token=[token stringByReplacingOccurrencesOfString:@" " withString:@""];
}

三.獲取推送的信息

iOS7以前
/*
 ios7以前蘋果支持多任務(wù), iOS7以前的多任務(wù)是假的多任務(wù)
 而iOS7開始蘋果才真正的推出了多任務(wù)
 接收到遠程服務(wù)器推送過來的內(nèi)容就會調(diào)用
 注意: 只有應(yīng)用程序是打開狀態(tài)(前臺/后臺(程序沒有殺死)), 才會調(diào)用該方法
 如果應(yīng)用程序是關(guān)閉狀態(tài)會調(diào)用didFinishLaunchingWithOptions
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    /*
     如果應(yīng)用程序在后臺 , 只有用戶點擊了通知之后才會調(diào)用
     如果應(yīng)用程序在前臺, 會直接調(diào)用該方法
     即便應(yīng)用程序關(guān)閉也可以接收到遠程通知,但是改方法不會調(diào)用
     */
    NSLog(@"%@", userInfo);
    
}

 如果應(yīng)用程序是關(guān)閉狀態(tài)會調(diào)用didFinishLaunchingWithOptions
我們的推送消息就會放在launchOptions這里面

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 // 1.取出數(shù)據(jù)
    NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
    
    if (userInfo) {
          NSLog(@"%@", userInfo);
     }

  return YES;
}


iOS7~iOS10.0
//接收到遠程服務(wù)器推送過來的內(nèi)容就會調(diào)用
// ios7以后用這個處理后臺任務(wù)接收到得遠程通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{

    NSLog(@"%@", userInfo);
    NSNumber *contentid =  userInfo[@"content-id"];
    if (contentid) {
        //注意: 在此方法中一定要調(diào)用這個調(diào)用block, 告訴系統(tǒng)是否處理成功.
        // 以便于系統(tǒng)在后臺更新UI等操作
         /*
     UIBackgroundFetchResultNewData, 成功接收到數(shù)據(jù)
     UIBackgroundFetchResultNoData, 沒有;接收到數(shù)據(jù)
     UIBackgroundFetchResultFailed 接收失敗
     */completionHandler(UIBackgroundFetchResultNewData);
    }else
    {
        completionHandler(UIBackgroundFetchResultFailed);
    }
    
}
iOS10.0以后有2個方法
/**
 *iOS10.0以后的方法
 */
//App在后臺運行及程序退出殺死 會調(diào)用的方法

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler{
    
    
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    NSLog(@"App在后臺時候-%@", userInfo);
    
    completionHandler();
    
}
// App在前臺時候回調(diào):用戶正在使用狀態(tài)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    
    NSDictionary *userInfo = notification.request.content.userInfo;
    NSLog(@"App在前臺時候回調(diào)-%@", userInfo);
    
    //可以設(shè)置當收到通知后, 有哪些效果呈現(xiàn)(聲音/提醒/數(shù)字角標)
    completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
    
}

在app進入后臺的時候,app會進入休眠的狀態(tài)侧但,不會執(zhí)行任何操作航罗。如果我們想讓app進入后臺后屁药,接受到了通知后,依然進行一些操作(更新界面)就要配置我的的工程

1.開啟多任務(wù)(后臺運行模式)

在iOS7以前雖然有了多任務(wù)酿箭,但是這個功能并不完善,到了iOS7以后缔御,這個多任務(wù)才可以正常使用


29DF90FF-3C22-45AB-8FD4-DB34815D6CEE.png
2.通知的格式也要改一下

后臺推送
支持系統(tǒng):iOS7及以上
推送格式:
{"aps":{"content-available":1"},"content":"hhhh"}

最后附上AppDelegate.m參考

#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>

@interface AppDelegate ()<UNUserNotificationCenterDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
        
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            
            if (!error) {
                NSLog(@"succeeded!");
            }
        }];
        
    } else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){
        
        //ios8以后的
        /**
         UIUserNotificationTypeNone = 0,
         UIUserNotificationTypeBadge = 1 << 0,
         UIUserNotificationTypeSound = 1 << 1,
         UIUserNotificationTypeAlert = 1 << 2
         */
        UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type categories:nil];
        //注冊通知類型
        [application registerUserNotificationSettings:setting];
        //申請使用通知
        [application registerForRemoteNotifications];
        
    }else{
        /**
         *枚舉類型
         UIRemoteNotificationTypeNone    = 0,   //不接收推送消息
         UIRemoteNotificationTypeBadge   = 1 << 0, 接收圖標數(shù)字
         UIRemoteNotificationTypeSound   = 1 << 1, 接收時的音效
         UIRemoteNotificationTypeAlert   = 1 << 2, 接收消息文字彈窗
         UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3, 接收訂閱消息
         */
        UIRemoteNotificationType  type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
        /**
         當用戶第一次啟動程序的時候就獲取deviceToken
         該方法在iOS8就過期le
         */
        //調(diào)用該方法笤成,系統(tǒng)就會自動發(fā)送UDID和當前程序的BundleID到蘋果的APNS服務(wù)器
        [application registerForRemoteNotificationTypes:type];
    }
    
    
    //取出推送通知:
    //當程序被殺死或者退出了眷茁,接受到的推送信息會保留在launchOptions中,當我們重新打開軟件的時候再取出來
    //取出在程序退出的時候接受到的推送消息
    NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
    if (userInfo) {
        NSLog(@"%@", userInfo);
    }
    
    return YES;
}


/**
 獲取到用戶當前程序的deviceToken后會會調(diào)這個方法
 */
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    
    NSLog(@"%@",deviceToken);
    
    //deviceToken:就是我們需要上傳服務(wù)器的deviceToken培遵;

}

/*
 *iOS7以前
 *ios7以前蘋果支持多任務(wù), iOS7以前的多任務(wù)是假的多任務(wù)
 *而iOS7開始蘋果才真正的推出了多任務(wù)
 *接收到遠程服務(wù)器推送過來的內(nèi)容就會調(diào)用
 *注意: 只有應(yīng)用程序是打開狀態(tài)(前臺/后臺(程序沒有殺死)), 才會調(diào)用該方法
 *如果應(yīng)用程序是關(guān)閉狀態(tài)會調(diào)用didFinishLaunchingWithOptions
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    /*
     如果應(yīng)用程序在后臺 , 只有用戶點擊了通知之后才會調(diào)用
     如果應(yīng)用程序在前臺, 會直接調(diào)用該方法
     即便應(yīng)用程序關(guān)閉也可以接收到遠程通知,但是改方法不會調(diào)用
     */
    NSLog(@"%@", userInfo);
    
}
/**
 *ios7以后
 *ios7以后用這個處理后臺任務(wù)接收到得遠程通知
 *接收到遠程服務(wù)器推送過來的內(nèi)容就會調(diào)用
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    
    NSLog(@"%@", userInfo);
    NSNumber *contentid =  userInfo[@"content-id"];
    if (contentid) {
        //注意: 在此方法中一定要調(diào)用這個調(diào)用block, 告訴系統(tǒng)是否處理成功.
        // 以便于系統(tǒng)在后臺更新UI等操作
        /*
         UIBackgroundFetchResultNewData, 成功接收到數(shù)據(jù)
         UIBackgroundFetchResultNoData, 沒有;接收到數(shù)據(jù)
         UIBackgroundFetchResultFailed 接收失敗
         */
        completionHandler(UIBackgroundFetchResultNewData);
    }else
    {
        completionHandler(UIBackgroundFetchResultFailed);
    }
    
}


/**
 *iOS10.0以后的方法
 */
//App在后臺運行及程序退出殺死 會調(diào)用的方法

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler{
    
    
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    NSLog(@"App在后臺時候-%@", userInfo);
    
    completionHandler();
    
}
// App在前臺時候回調(diào):用戶正在使用狀態(tài)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    
    NSDictionary *userInfo = notification.request.content.userInfo;
    NSLog(@"App在前臺時候回調(diào)-%@", userInfo);
    
    //可以設(shè)置當收到通知后, 有哪些效果呈現(xiàn)(聲音/提醒/數(shù)字角標)
    completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
    
}


@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纸俭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌廊宪,老刑警劉巖女轿,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異傅寡,居然都是意外死亡北救,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門托启,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攘宙,“玉大人,你說我怎么就攤上這事蹭劈。” “怎么了多矮?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵哈打,是天一觀的道長讯壶。 經(jīng)常有香客問我患雏,道長,這世上最難降的妖魔是什么丙挽? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任匀借,我火速辦了婚禮,結(jié)果婚禮上凳怨,老公的妹妹穿的比我還像新娘是鬼。我一直安慰自己,他們只是感情好均蜜,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布囤耳。 她就那樣靜靜地躺著,像睡著了一般充择。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宰僧,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天观挎,我揣著相機與錄音,去河邊找鬼。 笑死穗泵,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的现诀。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼坐桩,長吁一口氣:“原來是場噩夢啊……” “哼封锉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起成福,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤奴艾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蕴潦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡忽冻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年甚颂,在試婚紗的時候發(fā)現(xiàn)自己被綠了秀菱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡赶么,死狀恐怖脊串,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情琼锋,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布怖侦,位于F島的核電站,受9級特大地震影響匾寝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜急凰,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一猜年、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧企孩,春花似錦袁稽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莲组。三九已至暖夭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迈着,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工咬清, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奴潘,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓掘剪,卻偏偏與公主長得像奈虾,于是被迫代替她去往敵國和親肆汹。 傳聞我的和親對象是個殘疾皇子予权,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容