一、推送通知
推送通知就是向用戶推送一條信息來通知用戶某件事件,可以在應用退到後臺後,或者關閉後,能夠通過推送一條消息通知用戶某件事情,比如版本更新等等。
推送通知的常用應用場景:
- 一些任務管理APP,會到任務時間即將到達時,通知你該做任務了。
- 健身APP定時提醒你應該健身了。
- 買過電影票,提前半個小時通知你,電影即將開場。
- 當你QQ或微信收到信息時,即使退到後臺,也可以收到信息通知你。
- 電商APP,推送一條消息通知我們有新品上架等等。
推送通知的常用展示樣式:
- 屏幕頂部顯示一塊橫幅
- 在鎖屏界面顯示一塊橫幅
- 更新APP圖標數字
- 播放音效
- 屏幕中間彈出一個UIAlertView
推送通知分爲:
- 本地推送通知:
不需要聯網,在APP代碼中推送的通知,確定知道未來某個時間點應該提醒用戶什麼
【開發人員在APP內部通過代碼發生 = 本地推送通知】 - 遠程推送通知:
需要聯網,是由服務器推送的通知,不確定未來某個時間點應該提醒用戶什麼
【服務器可以確定通知時間和內容 = 遠程推送通知】
使用原則:誰確定通知時間和內容,誰就可以發生。
二、本地推送通知
本地推送通知步驟:
- 在iOS8以後使用本地推送通知,需要得到用戶的許可
- 創建
UILocalNotification
本地通知對象,並設置必要屬性 - 開始本地推送通知:
- 第一種方法,延時推送,根據本地通知對象的
fireDate
設置進行本地推送通知
[[UIApplication shareApplication] scheduleLocalNotification:notification];
- 第二種方法,立刻推送,忽略本地通知對象的
fireDate
設置進行本地推送通知
[[UIApplication shareApplication] presentLocalNotificationNow:notification];
4- 監聽用戶點擊通知:
- APP處於前臺,此時不會彈框通知用戶,但會調用對應的代理方法 :
-(void)application:(UIApplication *)application didReceiveLocalNotification;
- APP處於後臺,屏幕上方會彈出橫幅,用戶點擊橫幅後,會進入前臺,調用上面的代理方法。
- APP已關閉,屏幕上方會彈出橫幅,用戶點擊橫幅後,會啓動APP,調用以下方法:
-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
/* 通過參數launchOptions獲取本地推送通知內容 */
UILocalNotification *local = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
5- 調用UIApplication
的對象方法,取消本地推送通知:
/* 取消指定的本地推送通知 */
-(void)cancelLocalNotification:(UILocalNotification *)notification;
/* 取消全部本地推送通知 */
-(void)cancelAllLocalNotification;
以下是實例代碼:
1. 註冊通知代碼以及UIAlertView顯示通知方法代碼
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//因爲是storyboard啓動,這裏就沒有其他啓動代碼了
//iOS8.0以後,如果需要使用推送通知,需要得到用戶許可
if (application.currentUserNotificationSettings.types == UIUserNotificationTypeNone) {
//註冊通知,有橫幅通知、應用數字通知、應用聲音通知
UIUserNotificationSettings * setting =
[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound
categories:nil];
[application registerUserNotificationSettings:setting];
} else {
//當APP關閉後接收到通知,在啓動中獲取本地推送通知對象
UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
[self showLocalNotification:notification];
}
return YES;
}
/* 彈框UIAlertView顯示本地通知的信息 */
- (void)showLocalNotification:(UILocalNotification *)notification
{
/* 顯示本地通知 */
NSDictionary *userInfo = notification.userInfo;
NSString *title = @"本地通知";
NSString *msg = userInfo[@"msg"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:msg
delegate:nil
cancelButtonTitle:@"取消"
otherButtonTitles:@"確定", nil];
[alert show];
//移除本地通知
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
2. 創建本地通知代碼
/* 創建一個本地通知 */
- (UILocalNotification *)makeLocalNotification{
//創建本地推送通知對象
UILocalNotification *notification = [[UILocalNotification alloc] init];
//設置調用時間
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10.0];//通知觸發的時間,10s以後
notification.repeatInterval = NSCalendarUnitMinute;//每隔多久重複發一次本地通知
//設置通知屬性
notification.alertBody = @"最近添加了諸多有趣的特性,是否立即體驗?";//通知主體
notification.applicationIconBadgeNumber = 1;//應用程序圖標右上角顯示的消息數
notification.alertAction = @"打開應用"; //待機界面的滑動動作提示
notification.alertLaunchImage = @"Default";//通過點擊通知打開應用時的啓動圖片,這裏使用程序啓動圖片
notification.soundName = UILocalNotificationDefaultSoundName;//收到通知時播放的聲音,默認消息聲音
//設置用戶信息
notification.userInfo = @{ @"id":@1,
@"user":@"Kenshin Cui",
@"msg":@"我來了一發本地通知"};//綁定到通知上的其他附加信息
return notification;
}
如果需要每天的中午12點準時本地推送怎麼辦呢?
就像這麼辦,修改fireDate
和repeatInterval
屬性
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyy-MM-dd HH-mm-sss"];
NSDate *resDate = [formatter dateFromString:@"2016-04-09 12-00-00"];
notification.fireDate = resDate;//設定爲明天中午12點觸發通知
//記得設置當前時區,沒有設置的話,fireDate將不考慮時區,這樣的通知會不準確
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.repeatInterval = NSCalendarUnitDay;//每隔一天觸發一次
3. 監聽用戶點擊
/* 註冊本地通知完成會調用,即用戶點擊確定授權後調用 */
- (void)application:(UIApplication *)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
//在這裏我們嘗試發送本地推送通知
if (notificationSettings.types != UIUserNotificationTypeNone) {
UILocalNotification *notification = [self makeLocalNotification];
//延遲調用通知
[application scheduleLocalNotification:notification];
//立刻發送通知
//[application presentLocalNotificationNow:notification];
}
}
/* 應用還在運行,無論前臺還是後臺,都會調用該方法處理通知 */
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
if( notification ) {
[self showLocalNotification:notification];
}
}
/* 應用進入前臺,去除應用邊角數字顯示 */
- (void)applicationWillEnterForeground:(UIApplication *)application {
//去除應用邊角數字
[application setApplicationIconBadgeNumber:0];
}
三、遠程推送通知
iOS遠程消息推送步驟:
- 應用服務提供商從服務器端把要發送的消息和設備令牌(
device token
)發送給蘋果的消息推送服務器APNs。 - APNs根據設備令牌在已註冊的設備(iPhone、iPad、iTouch、Mac等)查找對應的設備,將消息發送給相應的設備。
- 客戶端設備接將接收到的消息傳遞給相應的應用程序,應用程序根據用戶設置彈出通知消息。
下面是更詳細的流程:
所有的蘋果設備,在聯網狀態下,都會和蘋果服務器APNs建立一個長連接
* 長連接:服務器可以向客戶端發送消息,保證數據的即時性,但比較佔用資源
* 短連接:服務器無法主動向客戶端發消息,會話結束後,就立即釋放資源,節省資源
遠程推送通知就是藉助蘋果設備與APNs服務器之間的長連接,藉助APNs服務器講消息發送給客戶端。
遠程推送通知實現的條件:
- 必須有真機,只有真機具備UDID,才能生成
deviceToken
設備令牌 - 需要開發推送Cer證書
證書的申請請參考:iOS學習筆記21-推送證書與祕鑰申請
deviceToken
的生成算法只有Apple掌握,爲了確保算法發生變化後仍然能夠正常接收服務器端發送的通知,每次應用程序啓動都重新獲得deviceToken
遠程推送通知步驟:
- iOS8以後,使用遠程通知,需要請求用戶授權
- 註冊遠程通知成功後會調用以下方法,獲取
deviceToken
設備令牌:
-(void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
3- 把deviceToken
設備令牌發送給服務器,時刻保持deviceToken
是最新的
4- 監聽遠程推送通知:
-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo;
下面是實例代碼:
1. 註冊遠程推送通知代碼:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//iOS8.0以後,如果需要使用本地推送通知,需要得到用戶許可
if (![application isRegisteredForRemoteNotifications]) {
UIUserNotificationSettings * setting =
[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |
UIUserNotificationTypeBadge |
UIUserNotificationTypeSound
categories:nil];
[application registerUserNotificationSettings:setting];
//註冊遠程推送通知
[application registerForRemoteNotifications];
}
return YES;
}
2. 註冊成功調用代碼:
/* 註冊遠程推送通知成功會調用 ,在此接收設備令牌deviceToken */
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[self addDeviceToken:deviceToken];
}
/* 保存deviceToken,並同步服務器上保存的deviceToken,以便能正確推送通知 */
- (void)addDeviceToken:(NSData *)deviceToken
{
NSString *key = @"DeviceToken";
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//取出原來的deviceToken,進行比較
NSData *oldToken = [defaults objectForKey:key];
if ([oldToken isEqualToData:deviceToken]) {
//存入新的deviceToken
[defaults setObject:deviceToken forKey:key];
[defaults synchronize];
//發送網絡請求到服務器,說明deviceToken發生了改變
[self sendDeviceTokenWithOldDeviceToken:oldToken newDeviceToken:deviceToken];
}
}
/* 發送網絡請求到服務器,說明deviceToken發生了改變,服務器那邊也要同步改變 */
- (void)sendDeviceTokenWithOldDeviceToken:(NSData *)oldToken newDeviceToken:(NSData *)newToken
{
//發送到服務器,下面是服務器的一個接口
NSString *urlStr = @"http://192.168.1.101/RegisterDeviceToken.aspx";
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
//POST網絡請求
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
requestM.HTTPMethod = @"POST";
//POST請求的請求體
NSString *bodyStr = [NSString stringWithFormat:@"oldToken=%@&newToken=%@",oldToken,newToken];
requestM.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];
//使用會話來發送網絡請求
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask =
[session dataTaskWithRequest:requestM
completionHandler:^(NSData *data,NSURLResponse *response,NSError *error){
if(!error){
NSLog(@"Send Success !");
} else {
NSLog(@"Send Failure, error = %@",error.localizedDescription);
}
}];
//網絡請求任務啓動
[dataTask resume];
}
3. 監聽遠程推送通知:
/* 收到遠程推送通知時會調用 */
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSString *title = @"遠程推送通知";
NSString *msg = userInfo[@"msg"];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:msg
delegate:nil
cancelButtonTitle:@"取消"
otherButtonTitles:@"確定", nil];
[alert show];
}
四、第三方遠程推送
上面的遠程推送過程如果覺得實現比較麻煩,你可以使用第三方推送,例如:
- 極光推送( JPush ),我只用過這個,界面還不錯,這不是在打廣告!
- 個推
- 騰訊信鴿
具體的集成步驟及使用方法,請查看對應的官方文檔,非常詳細。