一.關於推播通知
推播通知,也被叫做遠程通知,是在iOS 3.0以後被引入的功能。是當程式沒有啟動或不在前台運行時,告訴使用者有新訊息的一種途徑,是從外部伺服器發送到應用程式上的。一般說來,當要顯示訊息或下載資料的時候,通知是由遠程伺服器(程式的提供者)發送,然後通過蘋果的推播通知服務(Apple Push Notification Service,簡稱apns)推送到裝置的程式上。
推送的新訊息可能是一條資訊、一項即將到期的議程或是一份遠程伺服器上的新資料。在系統上展現的時候,可以顯示警告資訊或在程式icon上顯示數字,同時,也可以播放警告音。一旦使用者注意到程式有新的資訊、時間或是資料,他們可以運行程式並訪問新的內容。也可以選擇忽略通知,這時程式將不會被啟用。
iPhone, iPad和iPod touch上同一時刻只有一個app在前台運行。大多數程式在後台啟動並執行時候,可以對某些使用者感興趣的內容做出回應(定時、或資料等)。推播通知能讓程式在這些事件發生的時候通知使用者。
作為提供者為程式開發和部署推播通知,必須通過iOS Developer Program Portal獲得SSL認證。每個認證限用於一個程式,使用程式的bundle ID作為標識。認證有兩種用途的:一種是針對sandbox(用於開發與測試),另外一種針對發布產品。這兩種運行環境擁有為各自指定的IP地址並且需要不同的認證。還必須為兩種不同的環境擷取各自的provisioning profiles。
APNS提供了兩項基本的服務:訊息推送和反饋服務。
訊息推送:使用流式TCP通訊端將推播通知作為位元據發送給APNs。訊息推送有分別針對開發與測試用的sandbox、發布產品的兩個介面,每個都有各自的地址和連接埠。不管用哪個介面,都需要通過TLS或SSL,使用SSL認證來建立一個安全的通道。提供者編製通知資訊,然後通過這個通道將其發送給APNs。 註:sandbox: gateway.sandbox.push.apple.com:219 產品介面:gateway.push.apple.com:2195
反饋服務:可以得到針對某個程式的發送失敗記錄。提供者應該使用反饋服務周期性檢查哪些裝置一直收不到通知,不需要重複發送通知到這些裝置,降低推送伺服器的負擔。 註:sandbox:feedback.push.apple.com:2196 產品介面:feedback.sandbox.push.apple.com:2196
二.Apple Push Notification的工作機制
自己的用戶端發送訊息到自己應用軟體的apns,apns發送訊息到你的手機。這個是根據令牌識別的。手機在發送訊息到你的應用軟體。
首先是應用程式註冊訊息推送。
IOS跟APNS Server要deviceToken。應用程式接受deviceToken。
應用程式將deviceToken發送給PUSH服務端程式(Provider)。
服務端程式向APNS服務發送訊息。
APNS服務將訊息發送給iPhone應用程式。
1. Provider是指某個iPhone軟體的Push伺服器,是我們將要開發的伺服器。
2. APNS 是Apple Push Notification Service(Apple Push伺服器)的縮寫,是蘋果的伺服器。
可以分為三個階段:
第一階段:推送伺服器(provider)把要發送的訊息、目的iPhone的標識打包,發給APNS;
第二階段:APNS在自身的登入Push服務的iPhone列表中,尋找有相應標識的iPhone,並把訊息發到iPhone;
第三階段:iPhone把發來的訊息傳遞給相應的應用程式,並且按照設定彈出Push通知。
三 推送之前的配置
在任何iOS應用開發裡面,開發人員總是在團隊裡面扮演某一角色:團隊經理,團隊管理員,和團隊成員。iPhone開發認證和設定檔由不同角色完成。通常團隊經理是團隊裡面唯一可以建立Development SSL認證(沙箱環境)和Distribution SSL認證(產品環境)的人。而團隊經理和團隊管理員都可以建立Development和Distribution的設定檔。團隊成員只能下載並安裝認證和設定檔(!這裡要區別好認證和設定檔的概念:認證,即Certificates,它主要是使用Access Key Chain來產生的一個簽名密鑰。而設定檔,即Provisioning profiles,它主要是根據不同的App來產生的針對性的程式碼簽署檔案。二者區別是一般一個開發人員賬戶只能有一個Certificates(而Development一個,Distribtuion一個),但是可以有多個Provisioning profiles檔案,且這些Provisioning profiles通常建立的時候都使用同一個Certrificates)。以下部分詳細介紹該過程。
注意:iOS Provisioning Portal給所有iOS開發人員。
建立SSL認證和密鑰
在iOS Dev Center的iOS Provisioning Portal裡面,團隊經理選中相應APNs的AppID。他需要完成以下步驟來建立SSL認證:
1.
點擊視窗左邊側邊欄的App IDs。
將會跳轉到一個顯示當前合法應用IDs的頁面。每個應用的ID前麵包含了它的Bundle ID,而在Bundle ID之前包含了蘋果產生的十位字串。團隊管理員必須輸入Bundle ID。對於每個認證,它必須匹配某一特定的Bundle ID,你不能使用“wildcart”的應用ID。即要使用推播通知的應用的Bundle ID不能使用“*”來建立。
2.
找到需要建立SSL認證的應用ID(和Development Provisioning Profile相關),並單擊Configure按鈕。
你必須確保該App ID下面的蘋果推播通知服務欄下面顯示“可用”狀態才能為該應用配置APNs認證。
3.
在App ID配置頁面,檢查已經勾選了“Enable for Apple Push Notification service”複選框,並點擊下面的“Configure”按鈕。
單擊該按鈕將會啟動APNs助理,它會通過一系列步驟來引導完成操作。
4.
第一步要求你啟動Keychain Access應用並產生一個Certificate Signing Request(CSR)檔案。
下面的介紹來自認證助理。當你完成組建CSR後,點擊Keychain Access上面Continue來返回到APNs Assistant。
當你建立一個CSR時,Keychain Access產生一個私人和公有的加密金鑰對。而私人的密鑰會預設被放入你的Login keychain裡面。而公有的密鑰包含CSR會發送到設定管理員。當設定管理員把認證發回給你的時候,認證裡面的其中一個條目將是公有密鑰。
5.
在Submit Certificate Signing Request面板上,單擊Choose File。導航到你之前建立的CSR檔案的地方並選中它。
6.
單擊Generate按鈕。
在顯示Generate Your Certificate面板的同時,Assistant會配置並產生你的用戶端SSL認證。如果產生成功,它將會顯示資訊“Your APNs Certificate has been generated.”。單擊Continue來進入下一步操作。
7.
在下一個面板,單擊Download Now按鈕來下載認證檔案到本地檔案夾。找到檔案下載的地方並雙擊認證檔案(該認證檔案包含一個.cer的副檔名)來把它安裝到你的keychain裡面。當完成後,單擊APNs Assistant上面的Done按鈕。
雙擊載入啟動Keychain Access。確保你已經把剛才的認證安裝到了你用於開發的電腦的login keychain裡面。在Keychain Access裡面,確保你的認證使用的ID匹配你應用的Bundle ID。APNs的SSL認證應該安裝到你的通知服務上面。
當你返回到iOS Dev Center Portal的Configure App ID頁面完成這些步驟後,你的認證應該會變成綠色,並且顯示“Enabled”。
為了給產品環境建立一個認證,重複上述步驟,但記住選中產品認證的應用ID。
團隊經理或團隊管理器接下來必須建立在伺服器用於遠程通知開發的配置認證(Development 或 Distribution)。設定檔就是一個集合,它囊括了和應用相關的開發人員和Team Dev驗證過的裝置並使用這些裝置來測試應用程式。設定檔包含了認證、裝置標示符、應用的Bundle ID、和所有權利,包括<aps-environment>。所有團隊程式需要在運行並測試他們應用代碼的裝置上面安裝該設定檔。
注意:關於建立設定檔的詳細解析參考編程使用者指南。
為了下載並安裝設定檔,團隊程式必須完成以下步驟:
1.
進入iOS Dev Center的Provisioning portal頁面。
2.
建立一個新的設定檔,並包含你註冊用於APNs的App ID。
3.
在你下載這個新的設定檔之前修改任何已存在的設定檔。
你必須修改設定檔的一些細微部分(比如切換選項)來產生一個新的設定檔。如果設定檔並沒有“受損(dirtied)”,你不應該給以該原始設定檔任何推送的權利。
4.
找到檔案的下載目錄,把該設定檔(通常是一個.mobileprovision擴充檔案)拖拉到Xcode或iTunes應用程式的表徵圖上面。
可選的,你也可以把設定檔複製到~/Library/MobileDevice/Provisioning Profiles目錄。如果目前的目錄不存在則產生一個新目錄。
5.
驗證該設定檔的權利是否正確。為此,使用文字編輯器開啟.mobileprovision檔案。該檔案的內容是一個XML的文本。查看在aps-environment鍵的位置的字典值。對於一個開發模式的設定檔,該值應該是development;而對應發布模式的設定檔,該字元值應該是production。
6.
在Xcode的Organizer視窗,查看Provisioning Profiles部分,並確認認證已經安裝到你的裝置上面。
當你編譯該工程的時候,二進位檔案現在使用認證的私人密鑰簽名。
4.2.3
安裝SSL認證和密鑰到你的伺服器上面
你必須安裝SSL發布認證和你之前擷取的私人加密金鑰到需要運行提供者代碼的伺服器上,從該伺服器串連到APNs的沙箱或產品環境。為此,需要完成以下步驟:
1.
開啟Keychain Access實體並單擊左邊面板的My Certificates類別。
2.
找到你將要安裝的認證,並開啟相應內容。
你將會看到認證和私人密鑰。
3.
選中認證和密鑰,選中File > Export Items,並把它們匯出個人資訊分頁檔(.p12)。
4.
如果伺服器採用Buby或Perl語言來實現的話,那麼它們更容易處理個人資訊交換格式的檔案。為了把認證轉換為該格式,需要完成以下步驟:
a)
在Keychain Access裡面,選中相應認證並選擇File > Export Items。選擇個人資訊交換格式選項(.p12)。選擇一個儲存地址,並單擊Save按鈕。
b)
載入終端應用,並輸入如下的命令:
openssl pkcs12 -in CertificateName.p12 -out CertificateName.pem -nodes
5.
拷貝.pem認證檔案到新的電腦並安裝它到合適的地方。
這次準備工作已經完成了。
下面是用戶端的步驟了
一個應用程式必須在裝置(iOS裝置或Mac電腦)上面註冊了蘋果推播通知服務才能接收來自程式提供者的遠程通知。
註冊過程包含以下三個步驟:
一個應用程式必須在裝置(iOS裝置或Mac電腦)上面註冊了蘋果推播通知服務才能接收來自程式提供者的遠程通知。
註冊過程包含以下三個步驟:
1.
程式調用registerForRemoteNotificationTypes:方法。
2.
委託實現application:didRegisterForRemoteNotificationsWithDeviceToken:方法來接收裝置令牌。
3.
把裝置令牌作為非對象(二進位值)傳遞給程式提供者。
1.
程式調用registerForRemoteNotificationTypes:方法。
2.
委託實現application:didRegisterForRemoteNotificationsWithDeviceToken:方法來接收裝置令牌。
3.
把裝置令牌作為非對象(二進位值)傳遞給程式提供者。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[ViewController alloc] init] autorelease];
self.window.rootViewController = self.viewController;
[self.window setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"background.png"]]];
[self.window makeKeyAndVisible];
/** 註冊推播通知功能, */
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
//判斷程式是不是由推送服務完成的
if(launchOptions) {
NSDictionary* pushNotificationKey = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(pushNotificationKey) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"推播通知"
message:@"這是通過推送視窗啟動的程式,你可以在這裡處理推送內容"
delegate:nil
cancelButtonTitle:@"知道了"
otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
returnYES;
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString* token = [NSString stringWithFormat:@"%@",deviceToken];
NSLog(@"apns -> 產生的devToken:%@", token);
//把deviceToken發送到我們的推送伺服器
DeviceSender* sender = [[[DeviceSender alloc]initWithDelegate:self ]autorelease];
[sender sendDeviceToPushServer:token ];
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(@"apns -> 註冊推送功能時發生錯誤, 錯誤資訊:\n %@", err);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(@"\napns -> didReceiveRemoteNotification,Receive Data:\n%@", userInfo);
//把icon上的標記數字設定為0,
application.applicationIconBadgeNumber = 0;
if([[userInfo objectForKey:@"aps"] objectForKey:@"alert"]!=NULL) {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"**推送訊息**"
message:[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]
delegate:self
cancelButtonTitle:@"關閉"
otherButtonTitles:@"處理推送內容",nil];
alert.tag = alert_tag_push;
[alert show];
}
}