詳解APNS蘋果訊息推送通知
蘋果訊息通知什麼?
如下圖如示
就是APP的服務端在使用者未開啟APP程序時,還能發通知給使用者APP的服務技術
相關概念
Provider:提供推送的第三方服務系統
Device:蘋果裝置,例如iphone和ipad等
APNS:蘋果推送訊息服務,屬於蘋果的服務
APP:安裝在蘋果裝置上的應用程式
DeviceToken:裝置的標識,用於確定接收通知的裝置及APP
Payload:推送訊息的傳輸形式
總體示意圖
從上圖可以看出Provider與APNS之間是要建立連線的,APNS和Device之間也是要建立連線的,這兩個連線都是加密的,採用的TLS的方式,加密用的證書是在蘋果官方網站上購買生成的,這個證書分兩種,一種是“開發者證書”,使用開發者證書的APP可以釋出在APPSTORE上面,開發者證書的使用費是每年99美元,另一種是“企業證書”,使用企業證書的APP只能發在企業內部市場,不能發在APPSTORE上,企業證書的年費是299美元,企業證書對安裝人數是沒有限制的,但開發者證書對APP的安裝人數是有限制的,但從APPSTORE上安裝則沒有限制。
安全連線的建立方式如圖:
如何獲取確定接收者的DeviceToken?
Provider如何取得DeviceToken呢?具體如圖所示:
獲取是由APP通過註冊服務後取得DeviceToken,然後傳給Provider。由於這個DeviceToken是會變的,所以最好是APP在每次啟動時都能註冊一下,獲取最新的DeviceToken
IOS下的註冊獲取DeviceToken的程式碼官方給出如下:
- (void)applicationDidFinishLaunching:(UIApplication *)app {// other setup tasks here.... [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)]; } // Delegation methods - (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken { const void *devTokenBytes = [devToken bytes]; self.registered = YES; [self sendProviderDeviceToken:devTokenBytes]; // custom method } - (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { NSLog(@"Error in registration. Error: %@", err); }
如何傳送通知訊息?
Provider和APNS之間是一個安全的Socket連線,傳輸的是規定格式的二進位制資料,如下形式當然,這個就是TCP報文,然而具體的報文又有好幾種,有傳送普通訊息的傳輸形式,有獲取錯誤響應的傳輸形式,還有獲取反饋的報文形式等,對於普通的發訊息的報文格式如圖如示:
最前面1個位元組是命令型別,2-3位元組是DeviceToken的長度,後面是DeviceToken的具體值,後面是訊息的長度和訊息的具體內容。發完訊息後,在關閉Socket前還可以檢視錯誤的響應,以便確認訊息是否成功地發給APNS,錯誤響應的報文如下:
命令為8的表示是錯誤響應的報文,Status是錯誤碼,Identifier是用於定位具體的哪條推送訊息,這個是增強型通知裡的傳入的值,首先看下蘋果都有哪些返回錯誤碼:
再看下Identifier傳入使用的增強型的通知報文格式:
官方給出傳送普通訊息的C++程式碼如下:
static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength){
bool rtn = false;
if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength){
uint8_t command = 0; /* command number */
char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint16_t) +
DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
/* message format is, |COMMAND|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
char *binaryMessagePt = binaryMessageBuff;
uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
uint16_t networkOrderPayloadLength = htons(payloadLength);
/* command */
*binaryMessagePt++ = command;
/* token length network order */
memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* device token */
memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
binaryMessagePt += DEVICE_BINARY_SIZE;
/* payload length network order */
memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* payload */
memcpy(binaryMessagePt, payloadBuff, payloadLength);
binaryMessagePt += payloadLength;
if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
rtn = true;
}
return rtn;
}
傳送增強的通知訊息的程式碼:
static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength){
bool rtn = false;
if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength){
uint8_t command = 1; /* command number */
char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
/* message format is, |COMMAND|ID|EXPIRY|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD|*/
char *binaryMessagePt = binaryMessageBuff;
uint32_t whicheverOrderIWantToGetBackInAErrorResponse_ID = 1234;
uint32_t networkOrderExpiryEpochUTC = htonl(time(NULL)+86400); // expire
message if not delivered in 1 day
uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
uint16_t networkOrderPayloadLength = htons(payloadLength);
/* command */
*binaryMessagePt++ = command;
/* provider preference ordered ID */
memcpy(binaryMessagePt, &whicheverOrderIWantToGetBackInAErrorResponse_ID,
sizeof(uint32_t));
binaryMessagePt += sizeof(uint32_t);
/* expiry date network order */
memcpy(binaryMessagePt, &networkOrderExpiryEpochUTC, sizeof(uint32_t));
binaryMessagePt += sizeof(uint32_t);
/* token length network order */
memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* device token */
memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
binaryMessagePt += DEVICE_BINARY_SIZE;
/* payload length network order */
memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* payload */
memcpy(binaryMessagePt, payloadBuff, payloadLength);
binaryMessagePt += payloadLength;
if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
rtn = true;
}
return rtn;
}
角標(Badge)是什麼?
還有一個重要的概念是角標,如下:
這個角標是推送訊息裡傳的,可以指定,這個要看具體的業務怎麼定了,用於提醒使用者未讀訊息個數。
結尾
瞭解了以上原理和過程,相信用什麼語言都可以寫Provider程式了,本人基於java語言也簡單寫了個demo,可以支援多個應用的推送,等完善了就可以放github了相關推薦
詳解APNS蘋果訊息推送通知
蘋果訊息通知什麼? 如下圖如示 就是APP的服務端在使用者未開啟APP程序時,還能發通知給使用者APP的服務技術 相關概念 Provider:提供推送的第三方服務系統 Device:蘋果裝置,例如iphone和ipad等 APNS:蘋果推送訊息服務,屬於蘋果的服務 APP
Android安卓狀態列訊息推送通知(Notification)
我從不猜測,猜測是一個很壞的習慣——會影響正常的邏輯推理能力。 ——阿瑟·柯南·道爾 《福爾摩斯探案集》 近日,在做安卓專案開發的時候涉及到狀態列通知的需求,查了資料,總結一個簡
iOS 推送通知:本地通知(UILocalNotification)和遠端通知(APNs)詳解
——本地推送通知 推送通知的作用? 在App退到後臺或者完全退出時,可以使用通知來告訴使用者某件事情,比如推送新的聊天訊息、新聞等 通知對應的效果: 在主螢幕的頂端會出現通知訊息 當手機鎖屏時出現在鎖屏介面,可以通過滑動開啟該App, 在通知中心中
蘋果推送通知服務(APNs)程式設計
iPhone 對於應用程式在後臺執行有諸多限制(除非你越獄)。因此,當用戶切換到其他程式後,原先的程式無法保持執行狀態。對於那些需要保持持續連線狀態的應用程式(比如社群網路應用),將不能收到實時的資訊。 為解決這一限制,蘋果推出了APNs(蘋果推送通知服務)。APNs
IOS APNS訊息推送框架介紹(pushy)以及詳細使用方法
最近公司需要做IOS訊息推送的功能,我負責後臺推送,IOS端資料處理以及回撥我不負責,本篇文章主要介紹基於java的apns訊息推送,使用框架為pushy。 宣告:我先前也沒有接觸過這個IOS推送,自己研究了兩天,通過百度,對比各個框架的優缺點,最後選擇了這個框架,有說的不對的地方,還
NodeJs 實現IOS APNS 訊息推送服務
公司的專案要求接入伺服器自己接入原生的ISO 推送服務,不再接第三方的SDK,網上也有很多例子講解什麼是APNS ,如何獲取證書,怎麼接入,剛開始還是聽順利的,就是在獲取pem證書上面有些小問題,不過後來ios開發還是解決了,最後他自己做了一個獲取證書的總結。 我做的就是nodejs 服
iOS整合極光推送 通知 和 自定義訊息
支援的版本 r1.2.5 以後。 功能說明 只有在前端執行的時候才能收到自定義訊息的推送。 從jpush伺服器獲取使用者推送的自定義訊息的內容、標題、附件欄位等。 實現方法 獲取iOS的推送內容需要在delegate類中註冊通知並實現回撥方法。 1、在方法-
java伺服器端呼叫JPush極光推送api推送通知訊息
呼叫JPush推送的api,官網上已經有很詳細的說明了,我只是寫了一個小的demo測試下了! 在極光推送的官網註冊帳號,獲得應用標識(AppKey) , API MasterSecret , apk應用,將apk安裝在手機上並執行, 後臺測試程式碼: package com.zensoftware.
ActiveMQ基本詳解與總結& 訊息佇列-推/拉模式學習 & ActiveMQ及JMS學習
ActiveMQ基本詳解與總結 MQ簡介: MQ全稱為Message Queue, 訊息佇列(MQ)是一種應用程式對應用程式的通訊方法。應用程式通過寫和檢索出入列隊的針對應用程式的資料(訊息)來通訊,而無需專用連線來連結它們。訊息傳遞指
Android訊息推送(廣播機制)+通知
Android廣播機制使用了觀察著模式; (1) 通知 1) 獲取狀態通知欄管理 NotificationManager 是一個系統Service,所以必須通過getSystemService(NO
iOS開發 - ANPs推送通知 標簽: 推送通知ANPs遠程推送、本地推送
control con 垃圾 pre 條件 %20 常用 建立連接 mod iOS開發 - ANPs推送通知 標簽: 推送通知ANPs遠程推送本地推送 2015-05-03 14:12 3510人閱讀 評論(0) 收藏 舉報 本文章已收錄於: iOS知識庫
在Android應用程序中實現推送通知
xamarin android 幾乎每一個應用程序的一個重要特性是支持推送通知的能力。使用推送通知,您可以更新用戶,而不需要應用程序在任何時候運行或輪詢服務器, 避免潛在的電池電量不足。 隨著火力點雲信息的介紹(FCM),谷歌使得在Android應用程序中實現推送通知變
背水一戰 Windows 10 (121) - 後臺任務: 推送通知
target 聲明 測試 show null result href -c Coding [源碼下載] 背水一戰 Windows 10 (121) - 後臺任務: 推送通知 作者:webabcd介紹背水一戰 Windows 10 之 後臺任務 推送通知
從構建分布式秒殺系統聊聊WebSocket推送通知
shadow [1] 小夥伴 ref 相關 消費 png 重試 們的 前言 秒殺架構到後期,我們采用了消息隊列的形式實現搶購邏輯,那麽之前拋出過這樣一個問題:消息隊列異步處理完每個用戶請求後,如何通知給相應用戶秒殺成功? 場景映射 首先,我們舉一個生活中比較常見的例子:我
Android 基於Netty的訊息推送方案之物件的傳遞(四)
在上一篇文章中《Android 基於Netty的訊息推送方案之字串的接收和傳送(三)》我們介紹了Netty的字串傳遞,我們知道了Netty的訊息傳遞都是基於流,通過ChannelBuffer傳遞的,那麼自然,Object也需要轉換成ChannelBuffer來傳遞。好在Netty本身已經給我們寫好了
Android 基於Netty的訊息推送方案之字串的接收和傳送(三)
在上一篇文章中《Android 基於Netty的訊息推送方案之概念和工作原理(二)》 ,我們介紹過一些關於Netty的概念和工作原理的內容,今天我們先來介紹一個叫做ChannelBuffer的東東。 ChannelBuffer Netty中的訊息傳遞,都必須以位元
Android 基於Netty的訊息推送方案之概念和工作原理(二)
上一篇文章中我講述了關於訊息推送的方案以及一個基於Netty實現的一個簡單的Hello World,為了更好的理解Hello World中的程式碼,今天我來講解一下關於Netty中一些概念和工作原理的內容,如果你覺得本篇文章有些枯燥,請先去閱讀《Android 基於Netty的訊息推送方案之Hell
android 實現mqtt訊息推送,以及不停斷線重連的問題解決
前段時間專案用到mqtt的訊息推送,整理一下程式碼,程式碼的原型是網上找的,具體哪個地址已經忘記了。 程式碼的實現是新建了一個MyMqttService,全部功能都在裡面實現,包括連伺服器,斷線重連,訂閱訊息,處理訊息,釋出訊息等基本操作。 首先新增依賴: dependencies { &
基於Netty實現的Android 訊息推送(即時通訊)的解決方案
根據Netty框架實現訊息推送(即時聊天)功能. Netty框架,TCP長連線,心跳,阻塞訊息佇列,執行緒池處理訊息傳送, 基於Google ProtoBuf自定義的訊息協議, TCP粘包/拆包.... 客戶端通過TCP連線到伺服器,並建立TCP長連線;當伺服器端收到新訊息後通過TCP連線推送給
百度雲訊息推送
import com.baidu.yun.core.log.YunLogEvent; import com.baidu.yun.core.log.YunLogHandler; import com.baidu.yun.push.auth.PushKeyPair; import com.baidu.yun