前言
Apple 升级了后台推送接口,使用 http2 协议,提高了 payload 的最大大小(4k),本文介绍新版 APNS 实现方法
基于 okhttp 框架
http2 框架
不要使用 okhttp3 的 Request 类直接发送 post 请求,因为 http3 底层虽然使用了 ConnectionPool,可以设置 keep alive 和 keep alive duration,但是超过 keep alive duration,链接还是会断开,而 Apple 官方建议保持长链接!
所以最好自建 socket 长链接,使用 okhttp3 底层的 FramedConnection 类来直接发送 http2
请求,并通过定时 PING 帧来保持链接
在实际开发中,Apple 的 development 环境也非常不稳定,经常 链接超时 和 ssl 握手超时,大多数情况下只能建立一个链接,第二个连接要么连不上,要么在 ssl 握手断开
实现
Http2ApnsConnection
Http2ApnsConnection 类负责 ssl socket 链接的建立,心跳包发送以及通过 http2 multiple stream 在一个 frame 中发送多条 push notification
创建 ssl socket
private Socket createSocket() throws IOException {
debug("connect socket");
Socket socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
debug("socket connected");
SSLSocket sslSocket = (SSLSocket) socketFactory.createSocket(
socket, host, port, true);
sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
sslSocket.setKeepAlive(true);
debug("start ssl handshake");
sslSocket.startHandshake();
debug("handshake success");
return sslSocket;
}
创建 frame connection
private void createFramedConnection() throws IOException {
debug("createFramedConnection");
Socket socket = createSocket();
framedConnection = new FramedConnection.Builder(true)
.socket(socket)
.protocol(Protocol.HTTP_2)
.listener(this)
.build();
framedConnection.sendConnectionPreface();
framedConnectionAlive = true;
pingFuture = pingService.scheduleAtFixedRate(new PingTask(), 0, PING_PERIOD, TimeUnit.SECONDS);
}
发送 http2 header
private void sendHeader(String token, int contentLength) throws IOException {
// 创建 http2 header,参考 apple apns 开发文档
List<Header> headers = Arrays.asList(METHOD_POST_HEADER,
SCHEME_HEADER,
USER_AGENT_HEADER,
CONTENT_TYPE_HEADER,
new Header(":path", "/3/device/" + token),
new Header("authority", host),
new Header("content-length", String.valueOf(contentLength)));
// 创建 stream
framedStream = framedConnection.newStream(headers, true, true);
framedStream.readTimeout().timeout(timeOut, TimeUnit.MILLISECONDS);
framedStream.writeTimeout().timeout(timeOut, TimeUnit.MILLISECONDS);
}
发送 http2 data
private void sendData(byte[] bytes) throws IOException {
Buffer buffer = new Buffer();
buffer.write(bytes);
framedStream.getSink().write(buffer, bytes.length);
framedStream.getSink().flush();
}
Http2ApnsConnectionPool
Http2ApnsService
基于 netty 框架
整体代码结构和 基于 okhttp 框架的差不多,可以参考 https://github.com/black-bamb…