Apple 升级了后台推送接口,使用 http2 协议,提高了 payload 的最大大小(4k)
http2 框架 : okHttp
不要使用 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 |