使用推送通知

推送通知使远程通知提供方将通知发送至在移动设备中运行的应用程序。针对使用 Apple 推送通知服务 (APNs) 的 iOS 设备,AIR 3.4 支持推送通知。

注: 要针对 AIR for Android 应用程序启用推送通知,请使用本机扩展,例如由 Adobe evangelist Piotr Walczyszyn 开发的 as3c2dm

本章节其余部分描述了如何在 AIR for iOS 应用程序中启用推送通知。

注: 该讨论假定您拥有 Apple 开发人员 ID,熟悉 iOS 开发工作流程,并且已在一台 iOS 设备上至少部署了一个应用程序。

推送通知概述

Apple 推送通知服务 (APNs) 使远程通知提供方将通知发送至在 iOS 设备中运行的应用程序。APNs 支持以下通知类型:

  • Alerts

  • Badges

  • Sounds

关于 APNs 的完整信息,请参阅 developer.apple.com

在应用程序中使用推送通知涉及到多个方面:

  • 客户端应用程序 - 推送通知注册、与远程通知提供方沟通、接收推送通知。

  • iOS - 管理客户端应用程序和 APNs 之间的互动。

  • APNs - 在客户端注册期间提供一个 tokenID,并将远程通知提供方的通知传递至 iOS。

  • 远程通知提供方 - 储存 tokenId-client 应用程序信息并将通知推送至 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 还包含 flash.events.RemoteNotificationEvent(由RemoteNotifier调度),如下所示:

  • 成功创建应用程序预定和收到来自 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>

如果应用程序支持已本地化的字符串,则请在 supportedLanguages 标签中指定语言,该标签在 intialWindow 标签下,如以下示例所示:

<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. 单击“应用程序 ID”选项卡。

  4. 单击“新建应用程序 ID”按钮。

  5. 指定说明和捆绑标识符(不应在捆绑标识符中使用 * )。

  6. 单击“提交”。Provisioning Portal 会生成您的应用程序 ID 并重新显示“应用程序 ID”页面。

  7. 单击“配置”(位于应用程序 ID右侧)。显示“配置应用程序 ID”页面。

  8. 选择“启用 Apple 推送通知服务”复选框。注意有两种类型的推送 SSL 证书:一种用于开发/测试,一种用于生生产。

  9. 单击“开发推送 SSL 证书”右侧的“配置”按钮。显示“生成证书签名请求 (CSR)”页面。

  10. 按照页面所指示,使用 Keychain Access 公用程序生成 CSR。

  11. 生成 SSL 证书。

  12. 下载并安装 SSL 证书。

  13. (可选)对于生产推送 SSL 证书重复第 9 步至第 12 步。

  14. 单击“完成”。显示“配置应用程序 ID”页面。

  15. 单击“完成”。显示“应用程序 ID”页面。注意应用程序 ID 的推送通知旁的绿色圆圈。

  16. 确保保存 SSL 证书,因为该证书稍后将用于应用程序和提供方通信。

  17. 单击“供给”选项卡以显示“供给配置文件”页面。

  18. 为新的应用程序 ID 创建供给配置文件并下载。

  19. 单击“证书”选项卡并为新的供给配置文件下载一个新的证书。

对推送通知使用声音。

要为应用程序启用声音通知,请将声音文件捆绑为其他任何资源,但在相同目录中捆绑为 SEF 和 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,然后 APNs 将推送通知发送至客户端应用程序。

关于来自远程通知提供方的推送通知的详细信息,请参阅 Apple 开发人员库中的提供方与 Apple 推送通知服务的通信

远程通知提供方选项

远程通知提供方选项包含以下内容:

  • 基于 APNS-php 开源服务器创建自己的提供方。可以使用 http://code.google.com/p/apns-php/ 建立 PHP 服务器。通过该 Google 代码项目,您可以设计一个与指定要求匹配的界面。

  • 使用服务提供方。例如,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 本机和推送通知编程指南中的在服务器中安装 SSL 证书和密钥

在应用程序中处理推送通知

在应用程序中处理推送通知涉及以下内容:

  • 推送通知的全局用户配置和接受

  • 单个推送通知的用户接受

  • 处理推送通知和通知有效载荷数据

推送通知的配置和接受

用户第一次启动启用推送通知的应用程序时,iOS 显示 appname 是否要给您发送推送通知对话框,对话框中包括“不允许”和“好”按钮。如果用户选择“好”,则应用程序会接收预定的所有类型的通知。如果用户选择“不允许”,则不会接收通知。

注: 用户可以在“设置”>“通知”中控制可以为每个启用推送的应用程序接收的特定通知类型。

Apple 建议每次激活应用程序时都应预定推送通知。应用程序调用 RemoteNotifier.subscribe() 时,会接收到 RemoteNotificationEvent,类型为 token,其包含唯一可以识别设备中应用程序的 32 字节唯一数字 tokenId。

设备接收到推送通知时,显示一个弹出窗口,其中包括“关闭”和“启动”按钮。如果用户点击“关闭”,则没有事件发生;如果用户点击“启动”,则 iOS 会调用应用程序,且应用程序会接收到类型为 notificationflash.events.RemoteNotificationEvent,如下所述。

处理推送通知和有效载荷数据

远程通知提供方将通知发送至设备(使用 tokenID)时,无论应用程序是否在运行中,应用程序都会接收到类型为 notificationflash.events.RemoteNotificationEvent。此时,应用程序执行特定于应用程序的通知处理。如果应用程序处理通知数据,则可以通过 JSON 格式的 RemoteNotificationEvent.data 属性访问该数据。