本文旨在對 iOS 推送進行一個完整的剖析,若是你以前對推送一無所知,那麼在你認真地閱讀了全文後必將變成一個推送老手,你將會對其中的各類細節和原理有充分的理解。如下是 pikacode 使用 iOS 推送的一些經驗,歡迎互相交流,指出錯漏之處。ios
推送服務能夠說是全部 App 的標配,不管是哪一種類型的 App,推送都從很大程度上決定了 App 的 打開率、使用率、存活率 。所以,熟知並掌握推送原理及方法,對每個開發者來講都是必備技能,對每個依賴 App 的公司來講都相當重要。git
從 iOS 10 新增的 UserNotifications Framework
能夠發現,Apple 整合了原有散亂的 API,而且增長了許多強大的功能。以 Apple 官方的角度來看,也必然是至關重視推送服務對 App 的影響、以及對 Apple iOS 生態圈長遠發展的影響。github
badge
[如下簡稱角標] 等都會由系統來控制和展現)。在代碼中註冊推送服務:json
#ifdef __IPHONE_8_0
if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge| UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
}
#else
UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
#endif複製代碼
若是註冊成功,則能夠在 AppDelegate.m
的以下方法中獲取到 deviceToken
,它是對 該手機+該App 組合的一個惟一標識,當使用遠程推送時,只需將推送消息發給指定的 deviceToken
便可使推送信息傳達給指定手機的指定 App 上。所以若是你使用第三方,就須要在這個方法裏將 deviceToken
傳給第三方。(在 iOS 9 爲了更好的保護用戶隱私,會出現屢次重複刪除/安裝 App 致使 deviceToken
不斷變化的狀況。有時會出現一條推送手機會收到 2 次的問題,屬於 iOS 9 系統問題)。服務器
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[JPUSHService registerDeviceToken:deviceToken];//將 deviceToken 傳給極光推送
}複製代碼
若是以上步驟均成功,此時你可以取到第三方提供的設備註冊 id。可否取到該 id 值,能夠做爲判斷設備是否可以成功推送的標準(見 Tip 6 - Registration ID)。由於當你取到該值時必然:微信
deviceToken
(APNs 能識別你的設備了)。deviceToken
傳給第三方,成功在第三方生成了惟一標識註冊 id(第三方能將你的設備信息傳給 APNs 了)。didReceiveRemoteNotification
Remote Notification
,系統將推送傳到 didReceiveRemoteNotification:fetchCompletionHandler:
(見 Tip 5 - 後臺推送),不然此時代碼中收不到推送。didFinishLaunchingWithOptions
。遠程推送通知,分爲 普通推送/後臺推送/靜默推送 3 種類型。存在延遲問題(因爲 Tip 1 第 2 點,APNs 的不穩定及高峯時段的巨量請求所致)。app
普通推送性能
didReceiveRemoteNotification
(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:
(iOS 7 after)獲取通知內容(前臺展現橫幅的方法看這裏)。didFinishLaunchingWithOptions
獲取通知內容。通知內容相似以下:fetch
{
"_j_msgid" = 200806057; // 第三方附帶的 id,用於統計點擊
aps = {
alert = "顯示內容";
badge = 1; // App 角標,可推送 n、+n、-n 來實現角標的固定、增長、減小
sound = default; // 推送聲音,默認系統三全音,如需使用本身的聲音,須要將聲音文件拖拽&拷貝至 Xcode 工程目錄任意位置,並在推送時指定其文件名
};
key1 = value1; // 自定義字段,可設置多組,用於處理內部邏輯
key2 = value2;
}複製代碼
後臺推送ui
"content-available" = 1;
alert
、badge
、sound
中 至少 1 個字段
。didReceiveRemoteNotification
(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:
(iOS 7 after) 獲取通知內容。didReceiveRemoteNotification:fetchCompletion Handler:
獲取通知內容 // 獲取狀況中與普通推送的惟一不一樣點,此時 iOS 系統容許開發者在 App 處於後臺的狀況下,執行一些代碼,大概提供幾分鐘的時間,能夠用來偷偷的刷新 UI、切換頁面、下載更新包等等操做。didFinishLaunchingWithOptions
獲取通知內容。通知內容相似以下:
{
"_j_msgid" = 2090737306;
aps = {
alert = "顯示內容";
badge = 1;
"content-available" = 1; // 必帶字段
sound = default;
};
key1 = value1;
}複製代碼
靜默推送
"content-available" = 1;
,所以靜默必然是後臺的。alert
、badge
、sound
。didReceiveRemoteNotification
(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:
(iOS 7 after) 獲取通知內容。didReceiveRemoteNotification:fetchCompletion Handler:
獲取通知內容 //獲取狀況中與普通推送的惟一不一樣點,此時 iOS 系統容許開發者在 App 處於後臺的狀況下,執行一些代碼,大概提供幾分鐘的時間,能夠用來偷偷的刷新 UI、切換頁面、下載更新包等等操做。{
"_j_msgid" = 3938587719;
aps = {
alert = "";
"content-available" = 1; // 必帶字段
};
key1 = value1;
}複製代碼
別名、標籤、Registration ID 均是第三方提供的用於更方便地指定推送目標的功能。
NSUserDefaults
,本次剔除不須要的 tag 後,再從新設置。deviceToken
提供給第三方以後,其服務器會自動生成的指向該手機的惟一 id。通知 | 消息 | |
---|---|---|
送達時間 | 可能存在幾秒延遲 | 幾乎無延遲 |
獲取時機 | 處於前臺或後臺能獲取內容 | 僅處於前臺能獲取內容 |
離線內容 | 保留『一段時間』,過時會拋棄,沒法查詢歷史內容 | 始終保留,可查詢所有歷史內容 |
系統展現 | 會展現(靜默推送或App處於前臺不展現) | 不展現 |