什么是消息推送
舉一個常見的例子,我們的手機上經常會有彈出一些信息,例如QQ信息、微信信息等等,這就是常見的消息推送。
例如:
消息推送的類型:
- 在屏幕頂部顯示一塊橫幅(顯示具體內容)
- 在屏幕中間彈出一個UIAlertView(顯示具體內容)
- 在鎖屏界面顯示一塊橫幅(鎖屏狀態下,顯示具體內容)
- 更新app圖標的數字(說明新內容的數量)
- 播放音效(提醒作用)
這是我們常見的推送消息的樣式,我們可以在手機上自定義接收的消息如何展示。
在一些軟件中,如果用戶不小心關閉了我們的推送服務,我們也可以這樣提示用戶怎么打開允許接收推送服務(iOS8以后)。
注意:
-
發出推送通知時,如果當前程序正運行在前台,那么推送通知就不會被呈現出來
-
點擊推送通知后,默認會自動打開發出推送通知的app
-
不管app打開還是關閉,推送通知都能如期發出
消息推送和平常的從服務器獲取數據有什么不同?
- 當我們從服務器獲取數據的時候,我們會
主動向服務器
發送消息,然后服務器才會給我們發送我們需要的信息;而消息推送是當我們不在聊天狀態下,甚至是連QQ軟件都沒有打開的情況下,服務器主動向我們
發送消息,告訴我們一些信息。
當然了,消息推送和通知(NSNotification)可不一樣,雖然它們的使用類名看起來有點相似。
- NSNotification是抽象的,不可見的
- 消息推送是可見(肉眼可見的)
本地推送
在iOS中,推送分為本地推送和遠程推送,本地推送不需要網絡(不需要服務器的支持),常見的應用場景例如:
-
事件提醒類的軟件,到了我們自定義的時間,就會彈出一些信息告訴我們該干什么了。
-
記賬類軟件,會提醒我們的一些花銷等等。
我們先來學習一下本地推送
相關使用的類(重要)
- 創建本地推送通知對象
UILocalNotification *ln = [[UILocalNotification alloc] init];
- 設置本地推送通知屬性
//推送通知的觸發時間(何時發出推送通知)
@property(nonatomic,copy) NSDate *fireDate;
//推送通知的具體內容
@property(nonatomic,copy) NSString *alertBody;
//在鎖屏時顯示的動作標題(完整標題:“滑動來” + alertAction)
@property(nonatomic,copy) NSString *alertAction;
//音效文件名
@property(nonatomic,copy) NSString *soundName;
//app圖標數字
@property(nonatomic) NSInteger applicationIconBadgeNumber;
//每隔多久重復發一次推送通知
@property(nonatomic) NSCalendarUnit repeatInterval;
//點擊推送通知打開app時顯示的啟動圖片
@property(nonatomic,copy) NSString *alertLaunchImage;
//附加的額外信息
@property(nonatomic,copy) NSDictionary *userInfo;
//時區
@property(nonatomic,copy) NSTimeZone *timeZone;
(一般設置為[NSTimeZone defaultTimeZone] ,跟隨手機的時區)
//調度本地推送通知(調度完畢后,推送通知會在特地時間fireDate發出)
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
//獲得被調度(定制)的所有本地推送通知
@property(nonatomic,copy) NSArray *scheduledLocalNotifications;
(已經發出且過期的推送通知就算調度結束,會自動從這個數組中移除)
//取消調度本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification;
- (void)cancelAllLocalNotifications;
//立即發出本地推送通知
- (void)presentLocalNotificationNow:(UILocalNotification *)notification;
- 用戶點擊推送消息進入app時的調用方法
//當用戶點擊本地推送通知,會自動打開app,這里有2種情況
//app並沒有關閉,一直隱藏在后台
//讓app進入前台,並會調用AppDelegate的下面方法(並非重新啟動app)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
//app已經被關閉(進程已死)
//啟動app,啟動完畢會調用AppDelegate的下面方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
//launchOptions參數通過UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知對象
//當點擊通知進入app時,launchOptions參數才會有值,當正常啟動app時,launchOptions為null
注意:
在iOS 8.0中,如果要使用本地通知,需要得到用戶的許可
在didFinishLaunchingWithOptions方法中添加如下代碼:
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[application registerUserNotificationSettings:settings];
實例:
//在需要的地方注冊本地消息推送
// 1.創建本地通知
UILocalNotification *localNote = [[UILocalNotification alloc] init];
// 2.設置本地通知的信息
// 2.1.設置提示信息
localNote.alertBody = @"吃飯了嗎?";
// 2.2.設置通知彈出的時間
localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
// 2.3.設置滑塊顯示的文字
localNote.alertAction = @"快點";
// 2.4.是否讓上面的文字生效
localNote.hasAction = NO;
// 2.5.設置通知中心的標題
localNote.alertTitle = @"你大哥";
// 2.6.設置通知的聲音
localNote.soundName = @"buyao.wav";
// 2.7.設置應用程序圖標右上角的數字
localNote.applicationIconBadgeNumber = 10;
// 3.調度通知
//調度前要先把原來的通知取消
UIApplication *app = [UIApplication sharedApplication];
[app cancelAllLocalNotifications];
[app scheduleLocalNotification:localNote];
在appdelegate類中實現相應的跳轉方法
#import "AppDelegate.h"
#define IS_iOS8 ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/*
UIUserNotificationTypeNone = 0, 不發出通知
UIUserNotificationTypeBadge = 1 << 0, 改變應用程序圖標右上角的數字
UIUserNotificationTypeSound = 1 << 1, 播放音效
UIUserNotificationTypeAlert = 1 << 2, 是否運行顯示橫幅
*/
[application setApplicationIconBadgeNumber:0];
if (IS_iOS8) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
}
// 如果是正常啟動應用程序,那么launchOptions參數是null
// 如果是通過其他方式啟動應用程序,那么launchOptions就有值,里面存儲的是通知的內容
if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
// 當被殺死狀態收到本地通知時執行的跳轉代碼
[self jumpToSession];
}
return YES;
}
//程序沒有關閉時,點擊通知進入app才會調用,如果將程序完全退出,點擊通知進入app時只會調用上面的方法,不會調用這個方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// 在這里寫跳轉代碼
// 如果是應用程序在前台,依然會收到通知,但是收到通知之后不應該跳轉
if (application.applicationState == UIApplicationStateActive) return;
if (application.applicationState == UIApplicationStateInactive) {
// 當應用在后台收到本地通知時執行的跳轉代碼
[self jumpToSession];
}
}
- (void)jumpToSession
{
UILabel *redView = [[UILabel alloc] init];
redView.backgroundColor = [UIColor redColor];
redView.frame = CGRectMake(0, 100, 300, 400);
redView.numberOfLines = 0;
// redView.text = [NSString stringWithFormat:@"%@", launchOptions];
[self.window.rootViewController.view addSubview:redView];
}
@end
遠程推送
先介紹一下iOS中遠程推送的原理:
我們先要明確一點,所有的iOS設備收到的遠程推送消息都是通過蘋果的服務器發出來的。我們自己公司的服務器或者第三方的推送服務器都是將要發送給我們的推送消息先推給蘋果的服務器,然后再由蘋果的服務器發送給我們。
如下圖:
所以,我們的蘋果設備在聯網的情況下,都會默認和蘋果的服務器保持一個長連接(這里不解釋長連接的概念,你可以理解成是有一條線一直在兩者之間聯系着,為了保持服務器不斷開和我們設備的聯系,我們的設備默認每隔一段時間會向服務器發送心跳包(一個很小的文件),來告訴蘋果服務器不要和我們的設備斷開連接)。
原理圖講解
下面詳細解釋一下iOS中的遠程推送原理
上圖中1-8的步驟就可以很好的解釋遠程推送的過程了,而客戶端需要做的只有幾個步驟:
-
1:發送設備的UDID和
應用的Bundle Identifier
給APNs服務器 -
2:經蘋果加密生成一個
deviceToken -
3:發送當前用戶的deviceToken
和用戶的標志(比如id或者qq)到自己公司的服務器或者第三方推送服務器 -
4:監聽通知的點擊事件
其余的步驟由服務器端實現:
-
4:自己的服務器或者第三方推送服務器將客戶端發送過來的用戶信息保存在自己的服務器中
-
5:有人發送消息的時候,從服務器中(根據deviceToken)查詢要發給誰
-
6:查詢到要發送給某人以后,將信息發送給蘋果服務器
-
7:蘋果服務器根據得到的deviceToken和信息,查到要接受信息的設備和app,將信息發送給用戶。
調試iOS的遠程推送功能, 必備條件:
1.真機
2.調試推送需要的證書文件
1> aps_development.cer : 某台電腦就能調試某個app的推送服務
2> iphone5_qq.mobileprovision : 某台電腦就能利用某台設備調試某個程序
三.發布具有推送服務的app,需要的證書文件
1> aps_production.cer : 如果發布的程序中包含了推送服務,就必須安裝這個證書
2> qq.mobileprovision : 某台電腦就能發布某個程序
實際操作
下面就開始真正的使用一下遠程推送功能吧。
證書配置01 – 創建App ID
配置明確的App ID
大概步驟如下:
先選擇明確的App ID
配置遠程推送的調試證書
配置遠程推送的發布證書(使用第二種方法配置)
新建項目,將Bundle ID改成和上面配置的成相同名字。
如果還是不行,檢查這里
將配置好的證書下載后安裝。
接下來就可以開始處理遠程推送的消息了:
- 1、向蘋果注冊我們的設備,並獲取到deviceToken
注意:
在iOS7和iOS8中的注冊方法不一樣
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 請求獲取DeviceToken
if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
// 1.獲取發送通知的權限
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
// 2.注冊遠程通知
[application registerForRemoteNotifications];
} else {
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
}
return YES;
}
//獲取到deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"%@", deviceToken);
}
- 2、處理遠程通知的消息
這里有兩個方法,注意兩者的區別,更具需要調用
//這個方法可以處理當用戶點擊消息進入前台做一些操作
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(@"%@", userInfo);
}
//這個方法可以實現在用戶手機收到消息就可以在后台進行一些操作,例如更新UI
//不過,這個方法要先設置后台模式,方法如下:
/*
1.開啟后台模式
2.調用completionHandler,告訴系統你現在是否有新的數據更新
3.userInfo添加一個字段:"content-available" : "1" : 只要添加了該字段,接受到通知都會在后台運行
*/
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
UIView *redView = [[UIView alloc] init];
redView.frame = CGRectMake(100, 100, 100, 100);
redView.backgroundColor = [UIColor redColor];
[self.window.rootViewController.view addSubview:redView];
completionHandler(UIBackgroundFetchResultFailed);
}
添加后台模式方法:
測試工具介紹
下面介紹一種測試遠程通知的工具PushMeBaby
- PushMeBaby是一款用來測試ANPs的開源Mac項目
- 它充當了服務器的作用,用法非常簡單
- 它負責將內容提交給蘋果的APNs服務器,蘋果的APNs服務器再將內容推送給用戶的設備
- PushMeBaby的主頁
https://github.com/stefanhafeneger/PushMeBaby
使用步驟:
- 注釋掉不要的錯誤
-
填寫必要信息
-
deviceToken:用於找到設備的令牌
-
payload:推送的內容
-
- 將推送的調試證書改為名apns.cer,添加到PushMeBaby項目中
- command + R啟動程序,然后點擊Push
接下來就可以在設備上接收到遠程推送通知
常用的第三方推送(極光推送)
什么是JPush
一套遠程推送解決方案,支持android和iOS兩個平台
它能夠快捷地為iOS App增加推送功能,減少集成APNs需要的工作量、開發復雜度
更多的信息,可以參考JPush官方網站:https://www.jpush.cn
集成iOS SDK的步驟可以參考
http://docs.jpush.cn/pages/viewpage.action?pageId=2621727