天天看點

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

在多數移動應用中任何時候都隻能有一個應用程式處于活躍狀态,如果其他應用此刻發生了一些使用者感興趣的那麼通過通知機制就可以告訴使用者此時發生的事情。ios中通知機制又叫消息機制,其包括兩類:一類是本地通知;另一類是推送通知,也叫遠端通知。兩種通知在ios中的表現一緻,可以通過橫幅或者彈出提醒兩種形式告訴使用者,并且點選通知可以會打開應用程式,但是實作原理卻完全不同。今天就和大家一塊去看一下如何在ios中實作這兩種機制,并且在文章後面會補充通知中心的内容避免初學者對兩種概念的混淆。

<a href="http://www.cnblogs.com/kenshincui/p/4168532.html#localnotification">本地通知</a>

<a href="http://www.cnblogs.com/kenshincui/p/4168532.html#pushnotification">推送通知</a>

<a href="http://www.cnblogs.com/kenshincui/p/4168532.html#certificate">補充--ios開發證書、秘鑰</a>

<a href="http://www.cnblogs.com/kenshincui/p/4168532.html#notificationcenter">補充--通知中心</a>

目 錄

本地通知是由本地應用觸發的,它是基于時間行為的一種通知形式,例如鬧鐘定時、待辦事項提醒,又或者一個應用在一段時候後不使用通常會提示使用者使用此應用等都是本地通知。建立一個本地通知通常分為以下幾個步驟:

建立uilocalnotification。

設定處理通知的時間firedate。

配置通知的内容:通知主體、通知聲音、圖示數字等。

配置通知傳遞的自定義資料參數userinfo(這一步可選)。

調用通知,可以使用schedulelocalnotification:按計劃排程一個通知,也可以使用presentlocalnotificationnow立即調用通知。

下面就以一個程式更新後使用者長期沒有使用的提醒為例對本地通知做一個簡單的了解。在這個過程中并沒有牽扯太多的界面操作,所有的邏輯都在appdelegate中:進入應用後如果沒有注冊通知,需要首先注冊通知請求使用者允許通知;一旦調用完注冊方法,無論使用者是否選擇允許通知此刻都會調用應用程式的- (void)application:(uiapplication *)application didregisterusernotificationsettings:(uiusernotificationsettings *)notificationsettings代理方法,在這個方法中根據使用者的選擇:如果是允許通知則會按照前面的步驟建立通知并在一定時間後執行。

appdelegate.m

請求獲得使用者允許通知的效果:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

應用退出到後彈出通知的效果:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

鎖屏狀态下的通知效果(從這個界面可以看到alertaction配置為“打開應用”):

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

注意:

在使用通知之前必須注冊通知類型,如果使用者不允許應用程式發送通知,則以後就無法發送通知,除非使用者手動到ios設定中打開通知。

本地通知是有作業系統統一排程的,隻有在應用退出到背景或者關閉才能收到通知。(注意:這一點對于後面的推送通知也是完全适用的。 )

通知的聲音是由ios系統播放的,格式必須是linear pcm、ma4(ima/adpcm)、µlaw、alaw中的一種,并且播放時間必須在30s内,否則将被系統聲音替換,同時自定義聲音檔案必須放到main boundle中。

本地通知的數量是有限制的,最近的本地通知最多隻能有64個,超過這個數量将被系統忽略。

如果想要移除本地通知可以調用uiapplication的cancellocalnotification:或cancelalllocalnotifications移除指定通知或所有通知。

從上面的程式可以看到userinfo這個屬性我們設定了參數,那麼這個參數如何接收呢?

在ios中如果點選一個彈出通知(或者鎖屏界面滑動檢視通知),預設會自動打開目前應用。由于通知由系統排程那麼此時進入應用有兩種情況:如果應用程式已經完全退出那麼此時會調用- (bool)application:(uiapplication *)application didfinishlaunchingwithoptions:(nsdictionary *)launchoptions方法;如果此時應用程式還在運作(無論是在前台還是在背景)則會調用-(void)application:(uiapplication *)application didreceivelocalnotification:(uilocalnotification *)notification方法接收消息參數。當然如果是後者自然不必多說,因為參數中已經可以拿到notification對象,隻要讀取userinfo屬性即可。如果是前者的話則可以通路launchoptions中鍵為uiapplicationlaunchoptionslocalnotificationkey的對象,這個對象就是發送的通知,由此對象再去通路userinfo。為了示範這個過程在下面的程式中将userinfo的内容寫入檔案以便模拟關閉程式後再通過點選通知打開應用擷取userinfo的過程。

上面的程式可以分為兩種情況去運作:一種是啟動程式關閉程式,等到接收到通知之後點選通知重新進入程式;另一種是啟動程式後,進入背景(其實在前台也可以,但是為了明顯的體驗這個過程建議進入背景),接收到通知後點選通知進入應用。另種情況會分别按照前面說的情況調用不同的方法接收到userinfo寫入本地檔案系統。有了userinfo一般來說就可以根據這個資訊進行一些處理,例如可以根據不同的參數資訊導航到不同的界面,假設是更新的通知則可以導航到更新内容界面等。

和本地通知不同,推送通知是由應用服務提供商發起的,通過蘋果的apns(apple push notification server)發送到應用用戶端。下面是蘋果官方關于推送通知的過程示意圖:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

推送通知的過程可以分為以下幾步:

應用服務提供商從伺服器端把要發送的消息和裝置令牌(device token)發送給蘋果的消息推送伺服器apns。

apns根據裝置令牌在已注冊的裝置(iphone、ipad、itouch、mac等)查找對應的裝置,将消息發送給相應的裝置。

用戶端裝置接将接收到的消息傳遞給相應的應用程式,應用程式根據使用者設定彈出通知消息。

當然,這隻是一個簡單的流程,有了這個流程我們還無從下手編寫程式,将上面的流程細化可以得到如下流程圖(圖檔來自網際網路),在這個過程中會也會提到如何在程式中完成這些步驟:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

1.應用程式注冊apns推送消息。

說明:

a.隻有注冊過的應用才有可能接收到消息,程式中通常通過uiapplication的registerusernotificationsettings:方法注冊,ios8中通知注冊的方法發生了改變,如果是ios7及之前版本的ios請參考其他代碼。

b.注冊之前有兩個前提條件必須準備好:開發配置檔案(provisioning profile,也就是.mobileprovision字尾的檔案)的app id不能使用通配id必須使用指定app id并且生成配置檔案中選擇push notifications服務,一般的開發配置檔案無法完成注冊;應用程式的bundle identifier必須和生成配置檔案使用的app id完全一緻。

2.ios從apns接收device token,在應用程式擷取device token。

a.在uiapplication的-(void)application:(uiapplication *)application didregisterforremotenotificationswithdevicetoken:(nsdata *)devicetoken代理方法中擷取令牌,此方法發生在注冊之後。

b.如果無法正确獲得device token可以在uiapplication的-(void)application:(uiapplication *)application didfailtoregisterforremotenotificationswitherror:(nserror *)error代理方法中檢視詳細錯誤資訊,此方法發生在擷取device token失敗之後。

c.必須真機調試,模拟器無法擷取device token。

3.ios應用将device token發送給應用程式提供商,告訴伺服器端目前裝置允許接收消息。

a.device token的生成算法隻有apple掌握,為了確定算法發生變化後仍然能夠正常接收伺服器端發送的通知,每次應用程式啟動都重新獲得device token(注意:device token的擷取不會造成性能問題,蘋果官方已經做過優化)。

b.通常可以建立一個網絡連接配接發送給應用程式提供商的伺服器端, 在這個過程中最好将上一次獲得的device token存儲起來,避免重複發送,一旦發現device token發生了變化最好将原有的device token一塊發送給伺服器端,伺服器端删除原有令牌存儲新令牌避免伺服器端發送無效消息。

4.應用程式提供商在伺服器端根據前面發送過來的device token組織資訊發送給apns。

a.發送時指定device token和消息内容,并且完全按照蘋果官方的消息格式組織消息内容,通常情況下可以借助其他第三方消息推送架構來完成。

5.apns根據消息中的device token查找已注冊的裝置推送消息。

a.正常情況下可以根據device token将消息成功推送到用戶端裝置中,但是也不排除使用者解除安裝程式的情況,此時推送消息失敗,apns會将這個錯誤消息通知伺服器端以避免資源浪費(伺服器端此時可以根據錯誤删除已經存儲的device token,下次不再發送)。

下面将簡單示範一下推送通知的簡單流程:

首先,看一下ios用戶端代碼:

ios用戶端代碼的代碼比較簡單,注冊推送通知,擷取device token存儲到偏好設定中,并且如果新擷取的device token不同于偏好設定中存儲的資料則發送給伺服器端,更新伺服器端device token清單。

其次,由于device token需要發送給伺服器端,這裡使用一個web應用作為伺服器端接收device token,這裡使用了asp.net程式來處理令牌接收注冊工作,當然你使用其他技術同樣沒有問題。下面是對應的背景代碼:

這個過程主要就是儲存device token到資料庫中,當然如果同時傳遞舊的裝置令牌還需要先删除就的裝置令牌,這裡簡單的在資料庫中建立了一張device表來儲存裝置令牌,其中記錄了應用程式id和裝置令牌。

伺服器端消息發送應用運作效果:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

ios用戶端接收的消息的效果:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

到目前為止通過伺服器端應用可以順利發送消息給apns并且ios應用已經成功接收推送消息。

ios開發過程中如果需要進行真機調試、釋出需要注冊申請很多證書,對于初學者往往迷惑不解,再加上今天的文章中會牽扯到一些特殊配置,這裡就簡單的對ios開發的常用證書和秘鑰等做一說明。

ios常用的證書包括開發證書和釋出證書,無論是真機調試還是最終釋出應用到app store這兩個證書都是必須的,它是ios開發的基本證書。

a.開發證書:開發證書又分為普通開發證書和推送證書,如果僅僅是一般的應用則前者即可滿足,但是如果開發推送應用則必須使用推送證書。

b.釋出證書:釋出證書又可以分為普通釋出證書、推送證書、pass type id證書、站點釋出證書、voip服務證書、蘋果支付證書。同樣的,對于需要使用特殊服務的應用則必須選擇對應的證書。

app id,應用程式的唯一辨別,對應ios應用的bundle identifier,app id在蘋果開發者中心中分為通配應用id和明确的應用id,前者一般用于普通應用開發,一個id可以适用于多個不同辨別的應用;但是對于使用消息推送、passbook、站點釋出、icloud等服務的應用必須配置明确的應用id。

udid,用于辨別每一台硬體裝置的标示符。注意它不是device token,device token是根據udid使用一個隻有apple自己才知道的算法生成的一組标示符。

provisioning profiles,平時又稱為pp檔案。将udid、app id、開發證書打包在一起的配置檔案,同樣分為開發和釋出兩類配置檔案。

在申請開發證書時必須要首先送出一個秘鑰請求檔案,對于生成秘鑰請求檔案的mac,如果要做開發則隻需要下載下傳證書和配置簡介即可開發。但是如果要想在其他機器上做開發則必須将證書中的秘鑰導出(導出之後是一個.p12檔案),然後導入其他機器。同時對于類似于推送伺服器端應用如果要給apns發送消息,同樣需要使用.p12秘鑰檔案,并且這個秘鑰檔案需要是推送證書導出的對應秘鑰。

對于很多初學者往往會把ios中的本地通知、推送通知和ios通知中心的概念弄混。其實二者之間并沒有任何關系,事實上它們都不屬于一個架構,前者屬于uikit架構,後者屬于foundation架構。

通知中心實際上是ios程式内部之間的一種消息廣播機制,主要為了解決應用程式内部不同對象之間解耦而設計。它是基于觀察者模式設計的,不能跨應用程式程序通信,當通知中心接收到消息之後會根據内部的消息轉發表,将消息發送給訂閱者。下面是一個簡單的流程示意圖:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心

了解通知中心需要熟悉nsnotificationcenter和nsnotification兩個類:

nsnotificationcenter:是通知系統的中心,用于注冊和發送通知,下表列出常用的方法。

方法

說明

- (void)addobserver:(id)observer selector:(sel)aselector name:(nsstring *)aname object:(id)anobject

添加監聽,參數:

observer:監聽者

selector:監聽方法(監聽者監聽到通知後執行的方法)

  name:監聽的通知名稱

object:通知的發送者(如果指定nil則監聽任何對象發送的通知)

- (id &lt;nsobject&gt;)addobserverforname:(nsstring *)name object:(id)obj queue:(nsoperationqueue *)queue usingblock:(void (^)(nsnotification *note))block

name:監聽的通知名稱

queue:操作隊列,如果制定非主隊線程隊列則可以異步執行block

block:監聽到通知後執行的操作

- (void)postnotification:(nsnotification *)notification

發送通知,參數:

notification:通知對象

- (void)postnotificationname:(nsstring *)aname object:(id)anobject

aname:通知名稱

anobject:通知發送者

- (void)postnotificationname:(nsstring *)aname object:(id)anobject userinfo:(nsdictionary *)auserinfo

auserinfo:通知參數

- (void)removeobserver:(id)observer

移除監聽,參數:

observer:監聽對象

- (void)removeobserver:(id)observer name:(nsstring *)aname object:(id)anobject

nsnotification:代表通知内容的載體,主要有三個屬性:name代表通知名稱,object代表通知的發送者,userinfo代表通知的附加資訊。

雖然前面的文章中從未提到過通知中心,但是其實通知中心我們并不陌生,前面文章中很多内容都是通過通知中心來進行應用中各個元件通信的,隻是沒有單獨拿出來說而已。例如前面的文章中讨論的應用程式生命周期問題,當應用程式啟動後、進入背景、進入前台、獲得焦點、失去焦點,視窗大小改變、隐藏等都會發送通知。這個通知可以通過前面nsnotificationcenter進行訂閱即可接收對應的消息,下面的示例示範了如何添加監聽獲得uiapplication的進入背景和獲得焦點的通知:

主界面kcmainviewcontroller.m:

登入界面kcloginviewcontroller.m:

運作效果:

iOS開發系列--通知與消息機制概述本地通知推送通知補充--iOS開發證書、秘鑰補充--通知中心
通過上面的介紹大家應該可以發現其實通知中心是一種低耦合設計,和前面文章中提到的代理模式有異曲同工之妙。相對于後者而言,通知中心可以将一個通知發送給多個監聽者,而每個對象的代理卻隻能有一個。當然代理也有其優點,例如使用代理代碼分布結構更加清晰,它不像通知一樣随處都可以添加訂閱等,實際使用過程中需要根據實際情況而定。

繼續閱讀