使用推送通知

推送通知可讓遠端通知提供者將通知傳送到行動裝置上執行的應用程式。AIR 3.4 支援使用 Apple Push Notification service (APNs) 之 iOS 裝置的推送通知。

備註: 若要為 AIR for Android 應用程式啟用推送通知,請使用原生擴充功能,例如 as3c2dm ,由 Adobe 資訊傳播者 Piotr Walczyszyn 所開發。

本節的其餘部分說明如何在 AIR for iOS 應用程式中啟用推送通知。

備註: 此討論內容假設您擁有 Apple 開發人員 ID、熟悉 iOS 開發工作流程,並且曾經在 iOS 裝置上部署至少一個應用程式。

推送通知概觀

Apple Push Notification service (APNs) 可讓遠端通知提供者將通知傳送到 iOS 裝置上執行的應用程式。APNs 支援下列通知類型:

  • 警告

  • Badges

  • 聲音

如需 APNs 的完整資訊,請參閱 developer.apple.com

在您的應用程式中使用推送通知會牽涉到多個層面:

  • 用戶端應用程式 - 註冊推送通知、與遠端通知提供者通訊,以及接收推送通知。

  • iOS - 管理用戶端應用程式與 APNs 之間的互動。

  • APNs - 在用戶端註冊期間提供 tokenID,並且將通知從遠端通知提供者傳遞至 iOS。

  • 遠端通知提供者 - 將 tokenId 與用戶端的應用程式資訊和推送通知儲存至 APNs。

註冊工作流程

向伺服器端服務註冊推送通知的工作流程如下:

  1. 用戶端應用程式要求 iOS 必須啟用推送通知。

  2. iOS 將要求轉送至 APNs。

  3. APNs 伺服器將 tokenId 傳回至 iOS。

  4. iOS 將 tokenId 傳回至用戶端應用程式。

  5. 用戶端應用程式 (使用應用程式特定的機制) 會將 tokenId 提供給遠端通知提供者,而遠端通知提供者會儲存 tokenId 以用於推送通知。

通知工作流程

通知工作流程如下:

  1. 遠端通知提供者會產生通知,並將通知負荷與 tokenId 一起傳遞至 APNs。

  2. APNs 會將通知轉送至裝置上的 iOS。

  3. iOS 會將通知負荷推送至應用程式。

推送通知 API

AIR 3.4 引進了一組支援 iOS 推送通知的 API。這些 API 位於 flash.notifications 套件中,並且包含下列類別:

此外,AIR 3.4 還包括由 RemoteNotifier 所傳送的 flash.events.RemoteNotificationEvent ,如下所示:

  • 當成功建立應用程式的訂閱及收到來自 APNs 的新 tokenId 時傳送。

  • 收到新遠端通知時傳送。

此外,如果在訂閱程序期間發生錯誤, RemoteNotifier 就會傳送 flash.events.StatusEvent

管理應用程式中的推送通知

若要註冊應用程式以取得推送通知,您必須執行下列步驟:

  • 建立可在應用程式中訂閱推送通知的程式碼。

  • 啟用應用程式 XML 檔案中的推送通知。

  • 建立啟用 iOS Push Services 的佈建描述檔和憑證。

下列註解的範例程式碼會訂閱推送通知並處理推送通知事件:

package 
                        { 
                        import flash.display.Sprite; 
                        import flash.display.StageAlign; 
                        import flash.display.StageScaleMode; 
                        import flash.events.*; 
                        import flash.events.Event; 
                        import flash.events.IOErrorEvent; 
                        import flash.events.MouseEvent; 
                        import flash.net.*; 
                        import flash.text.TextField; 
                        import flash.text.TextFormat; 
                        import flash.ui.Multitouch; 
                        import flash.ui.MultitouchInputMode; 
                        // Required packages for push notifications 
                        import flash.notifications.NotificationStyle; 
                        import flash.notifications.RemoteNotifier; 
                        import flash.notifications.RemoteNotifierSubscribeOptions; 
                        import flash.events.RemoteNotificationEvent; 
                        import flash.events.StatusEvent; 
                        [SWF(width="1280", height="752", frameRate="60")] 

                        public class TestPushNotifications extends Sprite 
                        { 
                        private var notiStyles:Vector.<String> = new Vector.<String>;; 
                        private var tt:TextField = new TextField(); 
                        private var tf:TextFormat = new TextFormat(); 
                        // Contains the notification styles that your app wants to receive 
                        private var preferredStyles:Vector.<String> = new Vector.<String>(); 
                        private var subscribeOptions:RemoteNotifierSubscribeOptions = new RemoteNotifierSubscribeOptions(); 
                        private var remoteNot:RemoteNotifier = new RemoteNotifier(); 

                        private var subsButton:CustomButton = new CustomButton("Subscribe"); 
                        private var unSubsButton:CustomButton = new CustomButton("UnSubscribe"); 
                        private var clearButton:CustomButton = new CustomButton("clearText"); 

                        private var urlreq:URLRequest; 
                        private var urlLoad:URLLoader = new URLLoader(); 
                        private var urlString:String; 

                        public function TestPushNotifications() 
                        { 
                        super(); 

                        Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT; 
                        stage.align = StageAlign.TOP_LEFT; 
                        stage.scaleMode = StageScaleMode.NO_SCALE; 

                        tf.size = 20; 
                        tf.bold = true; 


                        tt.x=0; 
                        tt.y =150; 
                        tt.height = stage.stageHeight; 
                        tt.width = stage.stageWidth; 
                        tt.border = true; 
                        tt.defaultTextFormat = tf; 

                        addChild(tt); 

                        subsButton.x = 150; 
                        subsButton.y=10; 
                        subsButton.addEventListener(MouseEvent.CLICK,subsButtonHandler); 
                        stage.addChild(subsButton); 

                        unSubsButton.x = 300; 
                        unSubsButton.y=10; 
                        unSubsButton.addEventListener(MouseEvent.CLICK,unSubsButtonHandler); 
                        stage.addChild(unSubsButton); 

                        clearButton.x = 450; 
                        clearButton.y=10; 
                        clearButton.addEventListener(MouseEvent.CLICK,clearButtonHandler); 
                        stage.addChild(clearButton); 

                        // 
                        tt.text += "\n SupportedNotification Styles: " + RemoteNotifier.supportedNotificationStyles.toString() + "\n"; 

                        tt.text += "\n Before Preferred notificationStyles: " + subscribeOptions.notificationStyles.toString() + "\n"; 

                        // Subscribe to all three styles of push notifications: 
                        // ALERT, BADGE, and SOUND. 
                        preferredStyles.push(NotificationStyle.ALERT ,NotificationStyle.BADGE,NotificationStyle.SOUND ); 

                        subscribeOptions.notificationStyles= preferredStyles; 

                        tt.text += "\n After Preferred notificationStyles:" + subscribeOptions.notificationStyles.toString() + "\n"; 


                        remoteNot.addEventListener(RemoteNotificationEvent.TOKEN,tokenHandler); 
                        remoteNot.addEventListener(RemoteNotificationEvent.NOTIFICATION,notificationHandler); 
                        remoteNot.addEventListener(StatusEvent.STATUS,statusHandler); 

                        this.stage.addEventListener(Event.ACTIVATE,activateHandler); 


                        } 
                        // Apple recommends that each time an app activates, it subscribe for 
                        // push notifications. 
                        public function activateHandler(e:Event):void{ 
                        // Before subscribing to push notifications, ensure the device supports it. 
                        // supportedNotificationStyles returns the types of notifications 
                        // that the OS platform supports 
                        if(RemoteNotifier.supportedNotificationStyles.toString() != "") 
                        {     
                        remoteNot.subscribe(subscribeOptions); 
                        } 
                        else{ 
                        tt.appendText("\n Remote Notifications not supported on this Platform !"); 
                        } 
                        } 
                        public function subsButtonHandler(e:MouseEvent):void{ 
                        remoteNot.subscribe(subscribeOptions); 
                        } 
                        // Optionally unsubscribe from push notfications at runtime. 
                        public function unSubsButtonHandler(e:MouseEvent):void{ 
                        remoteNot.unsubscribe(); 
                        tt.text +="\n UNSUBSCRIBED"; 
                        } 

                        public function clearButtonHandler(e:MouseEvent):void{ 
                        tt.text = " "; 
                        } 
                        // Receive notification payload data and use it in your app 
                        public function notificationHandler(e:RemoteNotificationEvent):void{ 
                        tt.appendText("\nRemoteNotificationEvent type: " + e.type + 
                        "\nbubbles: "+ e.bubbles + "\ncancelable " +e.cancelable); 

                        for (var x:String in e.data) { 
                        tt.text += "\n"+ x + ":  " + e.data[x]; 
                        } 
                        } 
                        // If the subscribe() request succeeds, a RemoteNotificationEvent of 
                        // type TOKEN is received, from which you retrieve e.tokenId, 
                        // which you use to register with the server provider (urbanairship, in 
                        // this example. 
                        public function tokenHandler(e:RemoteNotificationEvent):void 
                        { 
                        tt.appendText("\nRemoteNotificationEvent type: "+e.type +"\nBubbles: "+ e.bubbles + "\ncancelable " +e.cancelable +"\ntokenID:\n"+ e.tokenId +"\n"); 

                        urlString = new String("https://go.urbanairship.com/api/device_tokens/" + 
                        e.tokenId); 
                        urlreq = new URLRequest(urlString); 

                        urlreq.authenticate = true; 
                        urlreq.method = URLRequestMethod.PUT; 

                        URLRequestDefaults.setLoginCredentialsForHost 
                        ("go.urbanairship.com", 
                        "1ssB2iV_RL6_UBLiYMQVfg","t-kZlzXGQ6-yU8T3iHiSyQ"); 

                        urlLoad.load(urlreq); 
                        urlLoad.addEventListener(IOErrorEvent.IO_ERROR,iohandler); 
                        urlLoad.addEventListener(Event.COMPLETE,compHandler); 
                        urlLoad.addEventListener(HTTPStatusEvent.HTTP_STATUS,httpHandler); 

                        } 

                        private function iohandler(e:IOErrorEvent):void 
                        { 
                        tt.appendText("\n In IOError handler" + e.errorID +" " +e.type); 

                        } 
                        private function compHandler(e:Event):void{ 
                        tt.appendText("\n In Complete handler,"+"status: " +e.type + "\n"); 
                        } 

                        private function httpHandler(e:HTTPStatusEvent):void{ 
                        tt.appendText("\n in httpstatus handler,"+ "Status: " + e.status); 
                        } 

                        // If the subscription request fails, StatusEvent is dispatched with 
                        // error level and code. 
                        public function statusHandler(e:StatusEvent):void{ 
                        tt.appendText("\n statusHandler"); 
                        tt.appendText("event Level" + e.level +"\nevent code " + 
                        e.code + "\ne.currentTarget: " + e.currentTarget.toString()); 
                        } 
                        } 
                        }

啟用應用程式 XML 檔案中的推送通知

若要在應用程式中使用推送通知,請以 Entitlements 標籤 (在 iphone 標籤底下) 提供下列內容:

<iphone> 
                            ... 
                               <Entitlements> 
                                  <![CDATA[ 
                                     <key>aps-environment</key> 
                                     <string>development</string> 
                                  ]]> 
                               </Entitlements> 
                            </iphone>

當您準備好要將應用程式推送至 App Store 時,請使用 <string> 元素以部署至生產環境:

      <string>production</string>

如果您的應用程式支援當地語系化字串,請在 intialWindow 標籤之下,以 supportedLanguages 標籤指定語言,如下列範例所示:

<supportedLanguages>en de cs es fr it ja ko nl pl pt</supportedLanguages>

建立啟用 iOS Push Services 的佈建描述檔和憑證

若要啟用應用程式與 APNs 的通訊,您必須以啟用 iOS Push Services 的佈建描述檔和憑證來封裝應用程式,如下所示:

  1. 登入您的 Apple 開發人員帳戶。

  2. 移至 Provisioning Portal。

  3. 按一下 App IDs (應用程式 ID) 索引標籤。

  4. 按一下 New App ID (新增應用程式 ID) 按鈕。

  5. 指定說明和組合包識別名稱 (組合包識別名稱中不可以使用 *)。

  6. 按一下 Submit (送出)。Provisioning Portal 會產生應用程式 ID 並重新顯示應用程式 ID 頁面。

  7. 按一下應用程式 ID 右邊的 Configure (憑證)。Configure App ID (設定應用程式 ID) 頁面隨即顯示。

  8. 選取 Enable for Apple Push Notification service (啟用 Apple Push Notification 服務) 核取方塊。請注意,您可以使用兩種推送 SSL 憑證:一種可用於開發/測試,另一種則適用於生產。

  9. 按一下 Development Push SSL Certificate (開發推送 SSL 憑證) 右邊的 Configure (設定) 按鈕。Generate Certificate Signing Request (CSR) (產生憑證簽署要求) 頁面隨即顯示。

  10. 使用 Keychain Access 公用程式產生 CSR,如本頁所指示。

  11. 產生 SSL 憑證。

  12. 下載並安裝 SSL 憑證。

  13. (選擇性) 針對生產推送 SSL 憑證重複執行步驟 9 至 12。

  14. 按一下 Done (完成)。Configure App ID (設定應用程式 ID) 頁面隨即顯示。

  15. 按一下 Done (完成)。App IDs (應用程式 ID) 頁面隨即顯示。請注意您的應用程式 ID 在推送通知內是否出現綠色圓圈。

  16. 請務必儲存您的 SSL 憑證,因為稍後應用程式與提供者通訊時會用到。

  17. 按一下 Provisioning (佈建) 索引標籤以顯示 Provisioning Profiles (佈建描述檔) 頁面。

  18. 為您的新應用程式 ID 建立並下載佈建描述檔。

  19. 按一下 Certificates (憑證) 索引標籤並下載新佈建描述檔的新憑證。

使用推送通知的聲音

若要為您的應用程式啟用聲音通知,請合併聲音檔案與想要的任何其他資源,但是以 SWF 和 app-xml 檔案的形式合併在相同的目錄中。例如:

Build/adt -package -target ipa-app-store -provisioning-profile _-_.mobileprovision -storetype pkcs12 -keystore _-_.p12 test.ipa test-app.xml test.swf sound.caf sound1.caf

Apple 支援下列聲音資料格式 (aiff、wav 或 caf 檔案):

  • 線性 PCM

  • MA4 (IMA/ADPCM)

  • uLaw

  • aLaw

使用當地語系化的警告通知

若要在應用程式中使用當地語系化的警告通知,請以 lproj 資料夾的形式合併當地語系化字串。例如,您支援西班牙文的警告,如下所示:

  1. 在專案內建立與 app-xml 檔案相同層級的 es.lproj 資料夾。

  2. 在 es.lproj 資料夾內,建立名為 Localizable.Strings 的文字檔案。

  3. 以文字編輯器開啟 Localizable.Strings,然後加入訊息索引鍵和對應的當地語系化字串。例如:

    "PokeMessageFormat" = "La notificación de alertas en español."
  4. 儲存檔案。

  5. 當應用程式收到具有此索引鍵值的警告通知,並且裝置語言為西班牙文時,就會顯示翻譯的警告文字。

設定遠端通知提供者

您需要遠端通知提供者,才能將推送通知傳送至應用程式。這個伺服器應用程式的作用就像提供者一樣,會接受您的推送輸入、將通知和通知資料傳遞至 APNs,然後反過來將推送通知傳送至用戶端應用程式。

如需有關從遠端通知提供者推送通知的詳細資訊,請參閱 Apple Developer Library 中的 使用 Apple Push Notification Service 與提供者通訊

遠端通知提供者選項

遠端通知提供者的選項如下:

  • 根據 APNS-php 開放來源的伺服器建立專屬的提供者。您可以使用 http://code.google.com/p/apns-php/ 設定 PHP 伺服器。這個 Google Code 專案可讓您設計符合特定需求的介面。

  • 使用服務提供者。例如, http://urbanairship.com/ 提供現成的 APNs 提供者。註冊這個服務之後,就可以開始使用類似下列的程式碼提供您的裝置字符:

    private var urlreq:URLRequest; 
                                        private var urlLoad:URLLoader = new URLLoader(); 
                                        private var urlString:String; 
    
                                        //When subscription is successful then only call the following code 
                                        urlString = new String("https://go.urbanairship.com/api/device_tokens/" + e.tokenId); 
                                        urlreq = new URLRequest(urlString); 
    
                                        urlreq.authenticate = true; 
                                        urlreq.method = URLRequestMethod.PUT; 
                                        URLRequestDefaults.setLoginCredentialsForHost("go.urbanairship.com", 
                                           "Application Key","Application Secret"); 
                                        urlLoad.load(urlreq); 
                                        urlLoad.addEventListener(IOErrorEvent.IO_ERROR,iohandler); 
                                        urlLoad.addEventListener(Event.COMPLETE,compHandler); 
                                        urlLoad.addEventListener(HTTPStatusEvent.HTTP_STATUS,httpHandler); 
    
                                        private function iohandler(e:IOErrorEvent):void{ 
                                           trace("\n In IOError handler" + e.errorID +" " +e.type); 
                                        } 
    
                                        private function compHandler(e:Event):void{ 
                                           trace("\n In Complete handler,"+"status: " +e.type + "\n"); 
                                        } 
    
                                        private function httpHandler(e:HTTPStatusEvent):void{ 
                                           tt.appendText("\n in httpstatus handler,"+ "Status: " + e.status); 
                                        }

    然後,您可以使用 Urban Airship 工具來傳送測試通知。

遠端通知提供者的憑證

您必須將 SSL 憑證和私密金鑰 (先前所產生) 複製到遠端通知提供者伺服器上的適當位置。一般是將這兩個檔案合併到一個 .pem 檔案。若要執行這項作業,請執行下列步驟:

  1. 開啟終端機視窗。

  2. 輸入下列命令,從 SSL 憑證建立 .pem 檔案:

    openssl x509 -in aps_developer_identity.cer -inform der -out TestPushDev.pem
  3. 輸入下列命令,建立私密金鑰 ( .p12 ) 的 .pem 檔案:

    openssl pkcs12 -nocerts -out TestPushPrivateKey.pem -in certificates.p12
  4. 輸入下列命令,將兩個 .pem 檔案合併到一個檔案:

    cat TestPushDev.pem TestPushPrivateKey.pem > FinalTestPush.pem
  5. 在建立伺服器端推送應用程式時,將合併的 .pem 檔案提供給伺服器提供者。

如需詳細資訊,請參閱 Apple Local and Push Notification Programming Guide 中的 在伺服器上安裝 SSL 憑證和金鑰

處理應用程式中的推送通知

在應用程式中處理推送通知會牽涉到下列層面:

  • 全域使用者是否會設定並接受推送通知

  • 使用者是否接受個別推送通知

  • 推送通知和通知負荷資料的處理方式

設定及接受推送通知

使用者第一次啟動具有推送通知功能的應用程式時,iOS 會顯示含有 Don’t Allow (不允許) 和 OK (確定) 按鈕的 appname Would Like to Send You Push Notifications (要傳送推送通知給您) 對話方塊。如果使用者選取 OK (確定),應用程式就會收到已訂閱的所有通知樣式。如果使用者選取 Don’t Allow (不允許),則不會收到任何通知。

備註: 此外,使用者也可以前往「設定 > 通知」,控制每個具有推送功能的應用程式可接收的特定通知類型。

Apple 建議,每當應用程式啟用,都應訂閱推送通知。當您的應用程式呼叫 RemoteNotifier.subscribe() 時,會收到 token 類型的 RemoteNotificationEvent ,其中包含可唯一識別某個裝置之某個應用程式的 32 位元唯一數字 tokenId。

當裝置收到推送通知時,會顯示「關閉」和「啟動」按鈕的彈出式選單。如果使用者觸碰「關閉」,則不會有任何反應;如果使用者觸碰「啟動」,則 iOS 會叫用應用程式,然後應用程式會收到 notification 類型的 flash.events.RemoteNotificationEvent ,如下所示。

推送通知和負荷資料的處理方式

當遠端通知提供者傳送通知到裝置 (使用 tokenID) 時,您的應用程式會收到 notification 類型的 flash.events.RemoteNotificationEvent ,不論應用程式是否正在執行。此時,您的應用程式會執行應用程式特定通知處理。如果應用程式會處理通知資料,您就可以透過 JSON 格式的 RemoteNotificationEvent.data 屬性來存取。