iOS消息推送

转自丰俊文的博客

这里写图片描述

经常有同学问我们,iOS上推送究竟怎么做啊,为什么我的设备总收不到推送呢,这里跟大家集中讨论一下iOS上推送的实现细节。

APNS的推送机制

与Android上我们自己实现的推送服务不一样,Apple对设备的控制非常严格,消息推送的流程必须要经过APNs:
这里写图片描述
这里 Provider 是指某个应用的Developer,当然如果开发者使用AVOS Cloud的服务,把发送消息的请求委托给我们,那么这里的Provider就是AVOS Cloud的推送服务程序了。上图可以分为三步:
第一步:AVOS Cloud推送服务程序把要发送的消息、目的设备的唯一标识打包,发给APNs。
第二步:APNs在自身的已注册Push服务的应用列表中,查找有相应标识的设备,并把消息发送到设备。
第三步:iOS系统把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知

为了实现消息推送,有两点非常重要:

1,App的推送证书

要能够完整实现一条消息推送,需要我们在App ID中打开Push Notifications,需要我们准备好Provisioning Profile和SSL证书,并且一定要注意Development和Distribution环境是需要分开的。最后,把SSL证书导入到AVOS Cloud平台,就可以尝试远程消息推送了。具体的操作流程可以参考我们的使用指南:iOS推送证书设置指南。

2,设备标识DeviceToken

知道了谁要推送,或者说要推送给哪个App之后,APNs还需要知道推到哪台设备上,这就是设备标识的作用。获取设备标识的流程如下:
这里写图片描述
第一步:App打开推送开关,用户要确认TA希望获得该App的推送消息
第二步:App获得一个DeviceToken
第三步:App将DeviceToken保存起来,这里就是通过[AVInstallation saveInBackground]将DeviceToken保存到AVOS Cloud
第四步:当某些特定事件发生,开发者委托AVOS Cloud来发送推送消息,这时候AVOS Cloud的推送服务器就会给APNs发送一则推送消息,APNs最后消息送到用户设备

推送相关的几个概念

消息类型

一条消息推送过来,可以有如下几种表现形式:
1. 显示一个alert或者banner,展现具体内容
2. 在应用icon上提示一个新到消息数
3. 播放一段声音

开发者可以在每次推送的时候设置,在推送达到用户设备时开发者也可以选择不同的提示方式。

本地消息通知

iOS上有两种消息通知,一种是本地消息(Local Notification),一种是远程消息(Push Notification,也叫Remote Notification),设计这两种通知的目的都是为了提醒用户,现在有些什么新鲜的事情发生了,吸引用户重新打开应用。

本地消息什么时候有用呢?譬如你正在做一个To-do的工具类应用,对于用户加入的每一个事项,都会有一个完成的时间点,用户可以要求这个To-do应用在事项过期之前的某一个时间点提醒一下TA。为了达到这一目的,App就可以调度一个本地通知,在时间点到了之后发出一个Alert消息或者其他提示。
我们在处理推送消息的时候,也可以综合运用这两种方式。

代码里面如何实现推送
首先,我们要获取DeviceToken。

App需要每次启动的时候都去注册远程通知——通过调用UIApplication的registerForRemoteNotificationTypes:方法,传递给它你希望支持的消息类型参数即可,例如:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    // do some initiale working 
    ... 

    [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; 
    return YES; 
} 

如果注册成功,APNs会返回给你设备的token,iOS系统会把它传递给app delegate代理——application:didRegisterForRemoteNotificationsWithDeviceToken:方法,你应该在这个方法里面把token保存到AVOS Cloud后台,例如:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { 
    NSLog(@"Receive DeviceToken: %@", deviceToken); 
    AVInstallation *currentInstallation = [AVInstallation currentInstallation]; 
    [currentInstallation setDeviceTokenFromData:deviceToken]; 
    [currentInstallation saveInBackground]; 
} 

如果注册失败,application:didFailToRegisterForRemoteNotificationsWithError:方法会被调用,通过NSError参数你可以看到具体的出错信息,例如:

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { 
    NSLog(@"注册失败,无法获取设备ID, 具体错误: %@", error); 
} 

请注意:注册流程需要在app每次启动时调用,这并不不会带来额外的负担,因为iOS操作系统在第一次获得了有效的device token之后,会本地缓存起来,以后app再调用registerForRemoteNotificationTypes:的时候会立刻返回,并不会再进行网络请求。另外,app层面不应该对device token进行缓存,因为device token也有可能变化——如果用户重装了操作系统,那么APNs再次给出的device token就会和之前的不一样,又或者是,用户restore了原来的backup到新的设备上,那么原来的device token也会失效。

其次,我们要处理收到消息之后的回调

我们可以设想一下消息通知的几种使用场景:
1,在app没有被启动的时候,接收到了消息通知。这时候操作系统会按照默认的方式来展现一个alert消息,在app icon上标记一个数字,甚至播放一段声音。

2,用户看到消息之后,点击了一下action按钮或者点击了应用图标。如果action按钮被点击了,系统会通过调用application:didFinishLaunchingWithOptions:这个代理方法来启动应用,并且会把notification的payload数据传递进去。如果应用图标被点击了,系统也一样会调用application:didFinishLaunchingWithOptions:这个代理方法来启动应用,唯一不同的是这时候启动参数里面不会有任何notification的信息。
示例代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    // do initializing works 
    ... 

    if (launchOptions) { 
        // do something else 
        ... 

        [AVAnalytics trackAppOpenedWithLaunchOptions:launchOptions]; 
    } 

    [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; 

    return YES; 
} 

3,如果远程消息发送过来的时候,app正在运行,这时候会发生什么呢?
app代理的application:didReceiveRemoteNotification:方法会被调用,同时远程消息中的payload数据会作为参数传递进去。

示例代码如下:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { 
    if (application.applicationState == UIApplicationStateActive) { 
        // 转换成一个本地通知,显示到通知栏,你也可以直接显示出一个alertView,只是那样稍显aggressive:) 
        UILocalNotification *localNotification = [[UILocalNotification alloc] init]; 
        localNotification.userInfo = userInfo; 
        localNotification.soundName = UILocalNotificationDefaultSoundName; 
        localNotification.alertBody = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"]; 
        localNotification.fireDate = [NSDate date]; 
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; 
    } else { 
        [AVAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo]; 
    } 
} 

常见问题FAQ

1. 我能推送长消息吗?

不能,APNs限制了每个notification的payload最大长度是256字节,超长的消息是不能发送的。

2. 推送怎么加声音提醒?

消息推送是可以指定声音的。譬如你可以对正面的反馈使用欢快的声音,对负面的反馈使用低沉一点的声音,都可以达到别出心裁让人眼前一亮的目的。

你需要先放一些aiff、wav或者caf音频文件到app的资源文件中,然后在推送的时候指定不同的音频文件名就可以了。
这里写图片描述

3. 推送的Badge是怎么回事?

推送并不一定会导致应用图标上红色数字增加,是否显示这一数字,显示成多少,都取决于开发者自己。
在发送推送消息的时候,我们可以选择是否递增这一数字;如果不选择这一项,那么消息推送并不会导致应用图标上红色数字的出现。
这里写图片描述
好,现在问题来了,这个数字如果搞出来了,怎么让它消失掉呢?

其实我们只需要在任何时候设置 UIApplication.applicationIconBadgeNumber 属性为0,就可以让这个数字消失掉。

一般我们会选择在应用启动的时候(application:didFinishLaunchingWithOptions:方法中),或者干脆一点,在应用每次被切换到前台的时候(applicationWillEnterForeground:方法中),调用这一行代码,即可立刻清除掉Badge数字了。

4. AVOS Cloud平台发出去的通知格式究竟是什么样子的

对于每一条推送消息,都包含一个payload,通常是组成了一个JSON的Dictionary,这其中必不可少的是aps属性,它对应的value也是一个Dictionary,包含下面一些内容:
1)alert消息(文本或Dictionary)
2)应用图标上的红色数字
3)播放的声音文件名

在由推送激活的app打开事件中,application:didFinishLaunchingWithOptions:的options参数就是这个大的Dictionary对象。

{ 
    aps =     { 
        alert = "hello, everyone"; 
        badge = 2; 
        sound = default; 
    }; 
} 

这里要注意的时alert部分,它的值可以是一个String(文本消息),也可以是一个JSON的Dictionary。当它是文本消息的时候,系统就会把这些文字显示到一个alertview中;如果它也是由一个JSON Dictionary组成的话,其格式如下:
* body
* action-loc-key
* loc-key
* loc-args
* launch-image

body部分就是alertView中将要展现出来的文本消息,loc-属性主要是用来实现本地化消息,launch-image只是app主bundle里的一个图片文件的名称,一般来说我们不指定这一属性。

5. 如何显示本地化的消息

有两种办法可以实现推送消息的本地化:
1)在推送的payload中使用loc-key和loc-args来指定进行本地化,这样Provider方只需要按照统一的格式来发送即可,消息的解析和组装则由客户端来完成。
2)如果推送的payload里面不包含loc-key/loc-args信息,那么Provider方就需要自己做本地化处理,然后给不同的device发送不同的消息,为了做到这一点,还需要app在上传device token的时候也把用户的语言设置信息传回来。
目前,因为AVOS Cloud主要就是瞄准中国大陆市场和海外中文用户,所以我们在推送上还不提供多语言支持。

6. 应用该怎么响应推送消息

上面说的处理流程,只能简单展示一下远程消息,激活用户让他们重新回到app中来。但是有时候,我们希望带给用户更好的使用体验,譬如如果我们告诉用户:张三刚刚评论了你的照片。这时候用户如果点击action按钮进入app,我们是展示具体的评论页面为好,还是展示通常的启动页面然后让用户自己去找张三的评论好?我想负责任的开发者都会选择前者。

要做到灵活响应不同类型的通知消息,我们需要在通知的payload中增加更多信息,而不能仅仅只有alert出来的文字信息。对于AVOS Cloud消息推送平台来讲,就需要开发者使用更高级功能的JSON格式。譬如我们发送这样的json字符串{“action”:{“type”:4},”alert”:”hello, everyone”} 最终在app内会收到这样的UserInfo Dictionary:

{ 
    action =     { 
        type = 4; 
    }; 
    aps =     { 
        alert = "hello, everyone"; 
        badge = 4; 
    }; 
} 

“hello, everyone”会显示到alertView中,但是整个Dictionary会通过launchOptions传递给application: didFinishLaunchingWithOptions: 方法,这样我们在程序里面就可以对不同的消息实现不同的跳转了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: iOS消息 APNs 是指苹果公司提供的一种用于向移动设备发远程通知的服务。而使用 Java 实现 HTTP/2 协议发消息可以通过以下步骤完成。 首先,我们需要使用 Java 开发一个 HTTP/2 客户端,以实现与 APNs 服务器的通信。我们可以使用 okhttp、netty 或者 java-http-client 等库来实现这个客户端。 其次,我们需要获取 APNs 服务器的地址和凭证认证信息。地址常见的有两个,分别是开发环境和生产环境。在获取地址之后,我们还需要生成一个包含认证信息的 JWT(JSON Web Tokens),以进行身份验证。 然后,我们可以使用 Java 客户端向 APNs 服务器发 HTTP/2 请求。请求的内容应包括通知的 payload 和设备的设备标识符(Device Token)等信息。设备标识符是由 APNs 服务器为每个设备生成的唯一标识符,用于指定接收消息的设备。 最后,我们可以根据 APNs 服务器的响应来判断是否成功。APNs 服务器会返回一个包含结果的响应,其中包括是否成功以及失败的原因。 总之,使用 Java 实现 HTTP/2 协议发 iOS 消息 APNs,需要开发一个符合 HTTP/2 协议的客户端,生成凭证信息并发请求。通过与 APNs 服务器的通信,可以将消息到指定的 iOS 设备上。 ### 回答2: iOS消息(APNs)是苹果公司提供的一种服务,用于将通知发iOS设备上的应用程序。实现APNs的一种方法是使用HTTP/2协议发请求。 在Java中,可以使用一些第三方库来实现使用HTTP/2协议发APNs消息。其中,使用Netty库是一个常见的选择。 首先,你需要引入Netty库的相关依赖项,并创建一个Netty的客户端连接。 然后,你需要创建APNs的请求和消息内容。APNs消息使用JSON格式进行发,你需要构建一个JSON对象来包含的内容。这个内容可以包括通知标题、内容、图标等。 接下来,你需要将JSON对象编码为二进制数据,并发给APNs服务器。此时,你可以使用Netty库提供的HTTP/2的客户端请求来发。 发请求的过程包括建立连接、发帧、处理响应等步骤。你需要设置请求的方法、URL、Headers以及Payload(即消息内容的二进制数据)。 最后,你需要在接收到APNs服务器的响应后,进行对应的处理和错误处理。常见的响应包括成功响应和错误响应。 总结起来,实现使用HTTP/2协议发APNs消息的过程,包括建立连接、构建JSON消息、编码为二进制数据、发请求、处理响应等步骤。通过使用Netty库,可以简化这个实现过程,并提供了更好的性能和可扩展性。 ### 回答3: 在iOS中,APNS(Apple Push Notification Service)是一种用于向苹果设备(如iPhone、iPad、iPod Touch等)消息的服务。而在Java中,可以使用HTTP/2协议来实现发APNS通知。 HTTP/2是一种基于HTTP/1.1的进化版本,其在性能和效率上有所提升。使用Java实现HTTP/2协议发APNS通知的步骤如下: 1. 首先,需要准备APNS证书。在苹果开发者账号中创建一个证书,并将其导出为.p12文件。 2. 将.p12文件转换为Java可用的密钥和证书形式。可以使用Java的KeyTool工具来完成此步骤。 3. 使用Java的HTTP/2库,如Jetty或Netty,建立与APNS服务器的HTTP/2连接。这些库可提供与APNS服务器之间的双向通信。 4. 在建立连接后,可以使用HTTP/2的帧和流的概念向APNS服务器发通知。可以使用Jetty或Netty提供的API来创建和发HTTP/2帧。 5. 在发通知时,需要将的相关信息,如设备令牌、内容等,封装为HTTP/2的帧数据发到APNS服务器。 6. APNS服务器收到请求后,会根据设备令牌等信息将通知给相应的设备。 总之,使用Java实现HTTP/2协议发APNS通知需要准备证书、使用HTTP/2库建立连接,并利用API创建和发HTTP/2帧,最后将信息发给APNS服务器。这样就可以通过HTTP/2协议向iOS设备消息了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值