苹果APNS推送PUSH升级成基于HTTP2.0的方式在中大型互联网App的应用实践-java

前言

Apple APNS PUSH是最能保证iOS系统上PUSH到达率的一种途径(考虑到iOS app的后台存活时间不长);几乎可以这样说,只要用户启动过APP,并且没有在系统设置里关闭其通知栏,在联网的情况下,APNS PUSH可以近乎实时送达客户系统通知栏。非联网情况下,APNS亦可以保留最后一条离线通知(重新联网时离线会下发)。这些APNS的特点,可直接查看:

苹果APNS PUSH官方文档

苹果APNS PUSH的历史到现在

第一版 APNS PUSH应该是应用最早,也是最广泛的方式。APP服务端与APNS服务器之间建立SSLSocket连接,且是基于客户端证书认证的SSL方式。比较好的客户端实现举个例子  https://github.com/RamosLi/dbay-apns-for-java。第一版APNS PUSH虽然是长连接,但并未定义完善的心跳等协议规范。另外一个缺点是,客户认证证书有有效期一般是一年,在互联网企业开发运营人员更新频繁的节奏下,很容易将证书更换环节遗忘,就会导致暂时性iOS PUSH不可用。如果想要在这一版中获得PUSH推送结果,还需要单开feedback接口做PUSH状态回执。

第二版 APNS PUSH建立于HTTP2.0协议之上。提供了非证书方式的,且没有失效期(自己不主动撤销)的token认证方式。更好的一点是,可以在同一个信道接收PUSH回执状态,错误码定义亦非常全面,可见 APNS HTTP2推送错误码表 其中的Table 8-6。

基于HTTP2.0 APNS PUSH 推送sdk(jar)开源项目选择

1、https://github.com/CleverTap/apns-http2(不是最终选择)

A Java library for sending notifications via APNS using Apple's new HTTP/2 API. This library uses OkHttp. Previous versions included support for Jetty's client, however, we've removed that due to instability of the Jetty client.

Note: Ensure that you have Jetty's ALPN JAR (OkHttp requires it) in your boot classpath. See here for more information. This is required until Java 9 is released, as Java 8 does not have native support for HTTP/2.

总结的来说就是,当下这个客户端依赖OkHttp来建立与APNS服务器的连接,并且如果你的jvm低于1.9,还需要在jvm启动的boot classpath里配置ALPN这个jar的依赖来支持java8不支持的http2。

-Xbootclasspath/p:/home/xxxxxxx/www/yourapp/webapps/ROOT/WEB-INF/lib/alpn-boot-8.1.7.v20160121.jar

//上下两位的版本的对应关系比较紧密(上下两个版本的搭配是OK的,经过验证,版本关系

java version "1.8.0_91"Java(TM) SE Runtime Environment (build 1.8.0_91-b14)Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

使用方式(maven):

<dependency>

    <groupId>com.clevertap.apns</groupId>

    <artifactId>apns-http2</artifactId>

     <version>1.0.3</version>

     <type>pom</type>

</dependency>

    Create a client

Using provider certificates

FileInputStream cert = new FileInputStream("/path/to/certificate.p12");

final ApnsClient client = new ApnsClientBuilder()

        .withProductionGateway()

        .inSynchronousMode()

        .withCertificate(cert)

        .withPassword("")

        .withDefaultTopic("<your app's topic>")

        .build();

Using provider authentication tokens

final ApnsClient client = new ApnsClientBuilder()

        .inSynchronousMode()

        .withProductionGateway()

        .withApnsAuthKey("<your APNS auth key, excluding -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----->")   //注意这里的key不包含前后那个分隔串!

        .withTeamID("<your team ID here>")

        .withKeyID("<your key ID here, present in the auth key file name>")

        .withDefaultTopic("<your app's topic>")

        .build();

Build your notification

The notification builder supports several other features (such as badge, category, etc). The minimal is shown below:

Notification n = new Notification.Builder("<the device token>")

        .alertBody("Hello").build();

Send the notification

Asynchronous

client.push(n, new NotificationResponseListener() {

    @Override

    public void onSuccess(Notification notification) {

        System.out.println("success!");

    }

    @Override

    public void onFailure(Notification notification, NotificationResponse nr) {

        System.out.println("failure: " + nr);

    }

});

Synchronous

NotificationResponse result = client.push(n);

System.out.println(result);

总结:基本推送都OK,但是QPS能力不足,环境绑定苛刻,且单机只能提供5 QPS,原因下边会说明。

支持认证方式:token认证和证书认证

OkHttp本身更多应用于Android等用户有限能力端做http访问,并不要求高并发,证据如下。

 okhttp3.Dispatcher

public final class Dispatcher {

  private int maxRequests = 64;

  private int maxRequestsPerHost = 5;  //此处限制了单机并发数!!!!!

2、https://github.com/relayrides/pushy(我们的最后选择)

总结:实现基于Netty,支持推送QPS良好。

支持认证方式:token认证和证书认证

集成:

<dependency>

    <groupId>com.turo</groupId>

    <artifactId>pushy</artifactId>

    <version>0.13.10</version>

</dependency>


基于token的认证方式:

final  ApnsClient apnsClient=newApnsClientBuilder() .setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST) .setSigningKey(ApnsSigningKey.loadFromPkcs8File(newFile("/path/to/key.p8"),"TEAMID1234","KEYID67890")) .build();

// key.p8中存储的就是苹果开发者后台申请的token认证文件,可以取出来其中的值当成认证串来使用。

发送回执都很简单,可直接参考https://github.com/relayrides/pushy 这里的示例


有任何问题可以留言,不吝赐教谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。