首页 文章

在Android应用程序中使用哪个WebSocket库? [关闭]

提问于
浏览
108

我想在我的Android应用程序中添加一个Service,它在后台运行WebSocket连接(可能持续几个小时甚至几天),并定期向服务器发送一些数据 .

现在似乎有一堆用于Java的WebSocket库,我不确定应该使用哪一个:

  • TooTallNate/Java-WebSocket 来自GitHub的描述:使用100%Java编写的准系统WebSocket客户端和服务器实现 . http://java-websocket.org/ - 这个链接在my first result of googling "android websocket"中 . 但是,它有很多未解决的问题,特别是关于SSL连接,目前似乎没有积极维护 .

  • koush/AndroidAsync 来自GitHub的描述:用于android的异步套接字,http(客户端服务器),websocket和socket.io库 . 基于nio,而不是线程 . - 许多公开问题,但似乎是维持/工作的活动 .

  • Project Tyrus 网站描述:JSR 356:WebSocket的Java API - 参考实现 - 这是由Oracle完成的 . 不确定它是否适用于Android .

  • Jetty WebSocket Client API 来自网站的信息:Jetty还提供了一个Jetty WebSocket客户端库,可以更轻松地与WebSocket服务器进行通信 . - 再次:不确定它是否适用于Android .

  • codebutler/android-websockets 来自GitHub的描述:适用于Android的裸最小websockets(hybi13 / RFC)客户端 - 这个用于schwiz/android-websocket-example,这是StackOverflow问题“How to make the Android device hold a TCP connection to Internet without wake lock?”的可接受答案 .

  • Atmosphere/wasync 来自GitHub的描述:具有回退的WebSockets传输Node.js,Android和Java的客户端库http://async-io.org

  • TakahikoKawasaki/nv-websocket-client 来自GitHub的描述:Java中的高质量WebSocket客户端实现 .

  • square/okhttp 来自GitHub的描述:适用于Android和Java应用程序的HTTP SPDY客户端 . http://square.github.io/okhttp/ - 它有一个Websocket模块 . 作为mentioned by scorpiodawg,OkHttp自3.5版以来就内置了websocket支持 .

  • firebase/TubeSock 来自GitHub的描述:用Java实现的WebSocket客户端库

  • Autobahn|Android (GitHub) 网站描述:Autobahn | Android是一个用于Java / Android的开源网络库,由Autobahn项目创建,该项目实现WebSocket协议和Web应用程序消息传递协议(WAMP),用于创建本机移动WebSocket / WAMP客户端 . - cloudsurfin pointed out这不支持wss .

此外,还有一个适用于Android的原生socket.io客户端库:

  • nkzawa/socket.io-client.java 来自GitHub的描述:适用于Java的全功能Socket.IO客户端库,与Socket.IO v1.0及更高版本兼容 .

要使用socket.io Android客户端对我来说很方便,因为我打算使用nodejs / socket.io作为web前端 . 但本地客户很年轻,有几个未解决的问题 . 除此之外,我的理解是Android应用程序没有使用socket.io客户端库的任何好处(除了与socket.io 1.0服务器兼容),因为可以在客户端保证WebSocket支持 .

我的要求如下:

  • 与Android API 9及更高版本的兼容性

  • 可通过SSL连接

  • 保持连接很长时间而不必持有永久的唤醒锁

  • 与可用的nodejs websocket服务器实现或与socket.io的兼容性

对于这些要求,哪一个是正确的库?

3 回答

  • 109

    一些笔记 .

    • koush/AndroidAsync 不执行RFC 6455所需的closing handshake . 有关详细信息,请参阅this .

    • Project Tyrus 适用于Android,但要确保其许可证(CDDL 1.1 and GPL 2 with CPE)及其大小(Reducing WebSocket client jar size with ProGuard)符合您的要求 . 另请注意,当文本大小很大时,Tyrus可能会抛出异常(这可能是一个错误) . 有关详细信息,请参阅this .

    • Jetty :2年前email thread在jetty-users邮件列表中说"We currently have no Android compatible Jetty 9 WebSocket client. There are plans to attempt to backport the Jetty WebSocket Client from JDK 7 to JDK 5/6 for android use, but its a lower priority than finishing our implementation of JSR-356 Java WebSocket API (javax.websocket)." Jetty当前关于其WebSocket Client API的document没有提及有关Android的任何内容 .

    • codebutler/android-websocket 不执行RFC 6455所需的closing handshake,并且可能会在关闭时抛出异常 . 见this .

    • Atmosphere/wasync 使用 AsyncHttpClient/async-http-client 作为其WebSocket实现 . 因此,应该提到AsyncHttpClient / async-http-client .

    • firebase/TubeSock 无法验证 Sec-WebSocket-Accept . 这违反了RFC 6455 . 此外,TubeSock在构建短信时存在错误 . 如果您对文本消息使用多字节UTF-8字符,您迟早会遇到该错误 . 有关TubeSock问题的详细列表,请参阅delight-im/Android-DDP中的Issue 3 .

    考虑点

    选择用Java编写的WebSocket客户端实现时的注意事项:

    • Compliance . 不少实现不实现RFC 6455所需的closing handshake . (如果未执行结束握手会怎样?请参阅this . )

    • Required Java version . Java SE 5,6,7,8或Java EE?甚至可以在Android上运行?

    • Size . 一些实现具有许多依赖性 .

    • wss 支持 .

    • HTTP proxy 支持 .

    • wss over HTTP proxy 支持 . 请参阅How HTML5 Web Sockets Interact With Proxy Servers中的图2,了解WebSocket客户端库必须采取哪些措施来支持HTTP代理上的wss .

    • Flexibility on SSL configuration . SSLSocketFactorySSLContext 应该能够在没有不必要限制的情况下使用 .

    • Custom HTTP headers in the opening handshake ,包括基本身份验证 .

    • Custom HTTP headers in HTTP proxy negotiation ,包括代理服务器上的身份验证 .

    • Capable of sending all the frame types (继续,二进制,文本,关闭,ping和pong)与否 . 大多数实现都没有为开发人员提供手动发送fragmented frames和未经请求的pong frames的方法 .

    • Listener interface 接收各种WebSocket事件 . 糟糕的界面让开发人员感到沮丧 . 丰富的界面可帮助开发人员编写健壮的应

    • Able to inquire WebSocket state 与否 . RFC 6455定义了CONNECTING,OPEN,CLOSING和CLOSED状态,但很少有实现以定义的方式维护其内部状态转换 .

    • Able to set a timeout value for socket connection . (相当于 Socket.connect(SocketAddress endpoint, int timeout) 方法的第二个参数)

    • Able to access the underlying raw socket .

    • Intuitive easy-to-use API 与否 .
      是否

    • Well-documented .

    • RFC 7692 (Compression Extensions for WebSocket) 支持(aka permessage-deflate) .

    • Redirection (3xx)支持 .

    • Digest Authentication 支持 .

    nv-websocket-client 涵盖了除最后两个之外的所有内容 . 此外,它的一个小而方便的功能是定期发送ping / pong帧 . 只需调用 setPingInterval / setPongInterval 方法即可实现(参见JavaDoc) .

    免责声明:Takahiko Kawasaki是nv-websocket-client的作者 .

  • 3

    其他一些考虑:

    Tyrus适用于Android . 但是,它在Android 5.0中使用的SSL库是错误的fail SSL handshakes . 这应该在较新版本的Android中修复,但由于Android未在许多设备上更新的方式,这可能是一个问题 .

    根据SSL对其他websocket实现的实现方式,这可能也是一个问题 .

    AndroidAsync没有此SSL问题 . 它确实有其他问题,如not being able to set timeouts .

  • 2

    a)在gradle文件中添加此文件

    compile 'com.github.nkzawa:socket.io-client:0.3.0'

    b)在Application Activity中添加以下行:

    public class MyApplication extends Application {
         private Socket mSocket;
            {
                try {
                   mSocket = IO.socket(Config.getBaseURL());
    
                } catch (URISyntaxException e) {
                    throw new RuntimeException(e);
                }
            }
    
            public Socket getSocket() {
                return mSocket;
            }
    }
    

    c)将此函数添加到您调用WebSocket的活动中:

    private void websocketConnection() {
                //Get websocket from application
                MyApplication app = (MyApplication ) getApplication();
                mSocket = app.getSocket();
                mSocket.on(Socket.EVENT_CONNECT, onConnect);
                mSocket.on(Socket.EVENT_DISCONNECT, onDisconnect);
                mSocket.on(Socket.EVENT_CONNECT_ERROR, onConnectError);
                mSocket.on(Socket.EVENT_CONNECT_TIMEOUT, onConnectError);
                mSocket.on("messageFromServer", onNewLocation);
                mSocket.connect();
            } 
    
    
        private Emitter.Listener onConnect = new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                runOnUiThread(() -> {
                    if (!isConnected) {
    
                        RequestSocket mRequestSocket = new RequestSocket();
    
                        mRequestSocket.setToken("anil_singhania");
                       /* your parameter */
                        mSocket.emit("messageFromClient", new Gson().toJson(mRequestSocket));
                        Log.i("Socket Data", new Gson().toJson(mRequestSocket));
                        isConnected = true;
                    }
                });
            }
        };
    
        private Emitter.Listener onDisconnect = args -> runOnUiThread(() -> {
            isConnected = false;
           /* Toast.makeText(getApplicationContext(),
                    R.string.disconnect, Toast.LENGTH_LONG).show();*/
        });
    
        private Emitter.Listener onConnectError = args -> runOnUiThread(() -> {
             /*   Toast.makeText(getApplicationContext(),
                R.string.error_connect, Toast.LENGTH_LONG).show()*/
        });
    
        private Emitter.Listener onNewLocation = new Emitter.Listener() {
            @Override
            public void call(final Object... args) {
                runOnUiThread(() -> {
    
    
                });
            }
        };
    

相关问题