Connecting to Pushbullet's Secure Websocket on

2019-04-02 21:09发布

The awesome service that is Pushbullet have a websocket stream that you can subscribe to and then listen for pushes to your device, which is exactly what I want. I want my App to be able to connect to the messages stream and do stuff based on what they say.

I've tried using https://github.com/andrepew/Java-WebSocket/tree/1.3.0-Android-SSL-Fix (forked from https://github.com/TooTallNate/Java-WebSocket), but am getting no luck. After a bit of a timeout, the connection response comes back with

onClose -1, draft org.java_websocket.drafts.Draft_10@a38fd36 refuses handshake, false

and

05-22 03:24:30.709  15423-15904 java.lang.NullPointerException: ssl == null
05-22 03:24:30.710  15423-15904 com.android.org.conscrypt.NativeCrypto.SSL_read_BIO(Native Method)
05-22 03:24:30.710  15423-15904 com.android.org.conscrypt.OpenSSLEngineImpl.unwrap(OpenSSLEngineImpl.java:477)
05-22 03:24:30.710  15423-15904 javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:1006)

my code to get that is (without my access token...) even trying the "trust all hosts" suggested hack,

private void createConnection()
{
    URI uri = URI.create("wss://stream.pushbullet.com/websocket/" + pushAT);

    final WebSocketClient mWebSocketClient = new WebSocketClient(uri) {
        @Override
        public void onOpen(ServerHandshake serverHandshake) {
            Log.d(TAG, "onOpen " + serverHandshake);
        }

        @Override
        public void onMessage(String s) {
            Log.d(TAG, "onMessage " + s);
        }

        @Override
        public void onClose(int i, String s, boolean b) {
            Log.d(TAG, "onClose " + i + ", " + s + ", " + b);
        }

        @Override
        public void onError(Exception e) {
            Log.d(TAG, "onError " + e);
            e.printStackTrace();
        }
    };

    Log.d(TAG, "Connecting to " + uri);
    trustAllHosts(mWebSocketClient);

    mWebSocketClient.connect();
    Log.d(TAG, "Connecting to " + uri);
}

public void trustAllHosts(WebSocketClient wsc) {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[]{};
        }

        public void checkClientTrusted(X509Certificate[] chain,
                                       String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain,
                                       String authType) throws CertificateException {
        }
    }};


    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        wsc.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(sc));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3条回答
【Aperson】
2楼-- · 2019-04-02 21:42

You might have an easier time using the streaming (long lived HTTP connection) instead of WebSocket on Android. Here's some sample code I have working on Android for this:

final URL url = new URL("https://stream.pushbullet.com/streaming/" + <USER_API_KEY>);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(38000);
connection.setConnectTimeout(8000);
connection.setRequestMethod("GET");
connection.setDoInput(true);

L.i("Connecting to stream server");

connection.connect();

final int responseCode = connection.getResponseCode();
if (responseCode != 200) {
    throw new QuietException("Unable to connect to stream, server returned " + responseCode);
}

final InputStream inputStream = connection.getInputStream();

try {
    final BufferedReader stream = new BufferedReader(new InputStreamReader(inputStream));

    final String line = stream.readLine();
    final JSONObject message = new JSONObject(line);
    // And now you can do something based on this message
} finally {
    inputStream.close();
}

This would work great while your app is open. If you want to get messages all the time, that's a bit harder. You'd need to receive the messages via GCM, which would mean creating a device for us to send the messages to for your app. If that's what you'd need, I suggest emailing api@pushbullet.com for more help.

查看更多
老娘就宠你
3楼-- · 2019-04-02 21:48

As far as I can tell from the error, you are using the Draft_10 which is rather old.

You should use the current draft [Draft_17] like this :

final WebSocketClient mWebSocketClient = new WebSocketClient(uri, new Draft_17()) {

And add to imports :

import org.java_websocket.drafts.Draft_10;

If you are interested, you may find more about drafts here:

https://github.com/TooTallNate/Java-WebSocket/wiki/Drafts

查看更多
萌系小妹纸
4楼-- · 2019-04-02 21:51

From that error I can only guess that it might have some issue with SSL. There is an alternative (not documented) streaming endpoint you could try that would maybe help debug this issue. If you do a request to https://stream.pushbullet.com/streaming/ACCESS_TOKEN_HERE it returns a chunked HTTP response that keeps going until you disconnect. If you can figure out how to read this streaming response (many http clients can do this) then at least that part works and it's just your websocket library.

You can use the streaming thing from the command line with curl --no-buffer. You should see a nop message immediately upon connection.

查看更多
登录 后发表回答