Apple 升級了後臺推送接口,使用 http2 協議,提升了 payload 的最大大小(4k),本文介紹新版 APNS 實現方法git
不要使用 okhttp3 的 Request 類直接發送 post 請求,由於 http3 底層雖然使用了 ConnectionPool,能夠設置 keep alive 和 keep alive duration,可是超過 keep alive duration,連接仍是會斷開,而 Apple 官方建議保持長連接!github
因此最好自建 socket 長連接,使用 okhttp3 底層的 FramedConnection 類來直接發送 http2
請求,並經過定時 PING 幀來保持連接app
在實際開發中,Apple 的 development 環境也很是不穩定,常常 連接超時 和 ssl 握手超時,大多數狀況下只能創建一個連接,第二個鏈接要麼連不上,要麼在 ssl 握手斷開框架
Http2ApnsConnection 類負責 ssl socket 連接的創建,心跳包發送以及經過 http2 multiple stream 在一個 frame 中發送多條 push notificationsocket
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; }
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); }
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); }
private void sendData(byte[] bytes) throws IOException { Buffer buffer = new Buffer(); buffer.write(bytes); framedStream.getSink().write(buffer, bytes.length); framedStream.getSink().flush(); }
總體代碼結構和 基於 okhttp 框架的差很少,能夠參考 https://github.com/black-bamb...post