我想在我的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 module。作为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客户端库:
使用socket.io Android客户端对我来说很方便,因为我打算使用nodejs / socket.io作为web前端。但本土客户很年轻,有几个未解决的问题。除此之外,我的理解是Android应用程序没有使用socket.io客户端库的任何好处(除了与socket.io 1.0服务器兼容),因为可以在客户端确保WebSocket支持
我的要求如下:
对于这些要求,哪一个是正确的库?
答案 0 :(得分:117)
一些注释。
koush / AndroidAsync 无法执行closing handshake所需的RFC 6455。有关详细信息,请参阅this。
Project Tyrus 适用于Android,但要确保其许可证(CDDL 1.1 and GPL 2 with CPE)及其大小(Reducing WebSocket client jar size with ProGuard)符合您的要求。另请注意,当文本大小很大时,Tyrus可能会抛出异常(这可能是一个错误)。有关详细信息,请参阅this。
Jetty :2年前{1}}在jetty-users邮件列表中说“我们目前没有Android兼容的Jetty 9 WebSocket客户端。计划尝试将Jetty WebSocket客户端从JDK 7反向移植到JDK 5/6以供Android使用,但它的优先级低于完成JSR-356 Java WebSocket API(javax.websocket)的实现。“ Jetty的当前版本关于其WebSocket Client API的email thread没有提及有关Android的任何内容。
codebutler / android-websocket 不会执行document所需的closing handshake,并且可能会在关闭时抛出异常。请参阅RFC 6455。
Atmosphere / wasync 使用 AsyncHttpClient / this 作为其WebSocket实现。所以,应该提到AsyncHttpClient / async-http-client。
firebase / TubeSock 无法验证Sec-WebSocket-Accept
。这违反了async-http-client。此外,TubeSock在构建短信时存在错误。如果您对文本消息使用多字节UTF-8字符,您迟早会遇到该错误。有关TubeSock问题的详细列表,请参阅RFC 6455中的Issue 3。
选择用Java编写的WebSocket客户端实现的注意事项:
SSLSocketFactory
和SSLContext
而不受不必要的限制。Socket.RFC 6455(SocketAddress endpoint, int timeout)
方法的第二个参数) RFC 7692 涵盖了上述所有内容,但最后两项除外。此外,它的一个小而方便的功能是定期发送ping / pong帧。只需调用setPingInterval
/ setPongInterval
方法即可实现(参见nv-websocket-client)。
免责声明:Takahiko Kawasaki是nv-websocket-client的作者。
答案 1 :(得分:4)
其他一些注意事项:
Tyrus适用于Android。但是,它在Android 5.0中使用的SSL库是错误的fail SSL handshakes。这应该在较新版本的Android中修复,但由于Android在许多设备上没有更新,这可能是一个问题。
根据SSL对其他websocket实现的实现方式,这可能也是一个问题。
AndroidAsync没有此SSL问题。它还有其他问题,例如not being able to set timeouts。
答案 2 :(得分:3)
a)在gradle文件中添加此文件
compile 'com.github.nkzawa:socket.io-client:0.3.0'
b)在“应用程序活动”中添加以下行:
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(() -> {
});
}
};