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都不一樣,可以說是手機的生份證)
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.png2.通知的格式也要改一下
后臺推送
支持系統(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