¿Qué biblioteca WebSocket usar en la aplicación Android?

Quiero agregar un servicio a mi aplicación de Android que se ejecuta en segundo plano con una conexión WebSocket (posiblemente durante varias horas o incluso días) y regularmente envía algunos datos a un servidor.

Ahora parece que hay un montón de bibliotecas WebSocket para Java, y no estoy seguro de cuál debería usar:

  • Descripción de TooTallNate / Java-WebSocket de GitHub: Una implementación barebones de cliente y servidor WebSocket escrita en 100% Java. http://java-websocket.org/ – Este está vinculado en mi primer resultado de googlear “websocket Android” . Sin embargo, tiene bastantes problemas abiertos, especialmente sobre conexiones SSL, y no parece mantenerse activamente en este momento.

  • koush / AndroidAsync Descripción de GitHub: socket asíncrono, http (cliente + servidor), websocket y la biblioteca socket.io para android. Basado en nio, no hilos. – Una vez más muchos problemas abiertos, pero parece ser activiley mantenido / trabajado en.

  • Descripción del proyecto Tyrus desde el sitio web: JSR 356: API de Java para WebSocket – Implementación de referencia: esto está hecho por Oracle. No estoy seguro de si funciona en Android.

  • Jetty WebSocket Client API Información del sitio web: Jetty también proporciona una Jetty WebSocket Client Library para escribir, lo que facilita la conversación con servidores WebSocket. – De nuevo: no estoy seguro de si funciona en Android.

  • codebutler / android-websockets Descripción de GitHub: cliente mínimo de websockets desnudo (hybi13 / RFC) para Android: este se utiliza en schwiz / android-websocket-example , que es la respuesta aceptada para la pregunta de StackOverflow ” Cómo hacer que ¿El dispositivo Android tiene una conexión TCP a Internet sin locking de activación? “.

  • Atmosphere / wasync Descripción de GitHub: WebSockets con la biblioteca de cliente de transporte alternativo para Node.js, Android y Java http://async-io.org

  • TakahikoKawasaki / nv-websocket-client Descripción de GitHub: Implementación de cliente WebSocket de alta calidad en Java.

  • square / okhttp Descripción de GitHub: un cliente HTTP + SPDY para aplicaciones Android y Java. http://square.github.io/okhttp/ – Tiene un módulo Websocket . Como lo menciona scorpiodawg , OkHttp tiene soporte para websocket incorporado desde la versión 3.5.

  • firebase / TubeSock Descripción de GitHub: una biblioteca de cliente WebSocket implementada en Java

  • Autobahn | Android ( GitHub ) Descripción del sitio web: Autobahn | Android es una biblioteca de red abierta para Java / Android creada por el proyecto Autobahn que implementa el protocolo WebSocket y el protocolo de mensajería de aplicaciones web (WAMP) para crear WebSocket / WAMP móvil nativo clientela. – cloudsurfin señaló que esto no tiene soporte para wss.

Además, hay una biblioteca cliente socket.io nativa para Android:

  • nkzawa / socket.io-client.java Descripción de GitHub: Completo Socket.IO Client Library para Java, que es compatible con Socket.IO v1.0 y posterior.

Utilizar el cliente de socket.io Android sería útil para mí, porque planeo usar nodejs / socket.io para la interfaz web de todos modos. Pero el cliente nativo es bastante joven y tiene varios problemas abiertos. Y además de eso, tengo entendido que una aplicación de Android no tiene ningún beneficio de usar la biblioteca del cliente socket.io (además de ser compatible con el servidor socket.io 1.0), porque el soporte de WebSocket puede estar asegurado en el lado del cliente .

Mis requisitos son los siguientes:

  • Compatibilidad con Android API 9 y superior
  • Posibilidad de conectarse a través de SSL
  • Mantenga la conexión por un tiempo prolongado sin tener que sostener un wakelock permanente
  • Compatibilidad con una implementación de servidor websocket de nodejs disponible o con socket.io

¿Alguna sugerencia de cuál es la biblioteca correcta para estos requisitos?

Algunas notas.

  • koush / AndroidAsync no realiza el saludo de cierre requerido por RFC 6455 . Vea esto para más detalles.

  • El Proyecto Tyrus funciona en Android, pero asegúrese de que su licencia ( CDDL 1.1 y GPL 2 con CPE ) y su tamaño ( Reducir el tamaño del contenedor del cliente WebSocket con ProGuard ) cumplan con sus requisitos. También tenga en cuenta que Tyrus puede lanzar una excepción cuando el tamaño del texto es grande (probablemente sea un error). Vea esto para más detalles.

  • Jetty : Un hilo de correo electrónico de hace dos años en la lista de correo de usuarios de embarcaciones dice: “Actualmente no tenemos un cliente Jetty 9 WebSocket compatible con Android. Hay planes para intentar respaldar el Jetty WebSocket Client de JDK 7 a JDK 5/6 para Android uso, pero es una prioridad menor que terminar nuestra implementación de JSR-356 Java WebSocket API (javax.websocket). “ El documento actual de Jetty sobre su API de WebSocket Client no menciona nada sobre Android.

  • codebutler / android-websocket no realiza el saludo de cierre requerido por RFC 6455 y puede arrojar una excepción al cerrar. Mira esto

  • Atmosphere / wasync utiliza AsyncHttpClient / async-http-client como su implementación WebSocket. Por lo tanto, más bien, se debe mencionar AsyncHttpClient / async-http-client en su lugar.

  • firebase / TubeSock no verifica Sec-WebSocket-Accept . Esta es una violación contra RFC 6455 . Además, TubeSock tiene un error al construir un mensaje de texto. Si utiliza caracteres UTF-8 multibyte para mensajes de texto, tarde o temprano encontrará el error. Vea el Issue 3 en delight-im / Android-DDP para obtener una larga lista sobre los problemas de TubeSock.

Puntos de consideración

Puntos de consideración al seleccionar una implementación de cliente WebSocket escrita en Java:

  1. Cumplimiento . No pocas implementaciones implementan el saludo de cierre requerido por RFC 6455 . (¿Qué sucede si el saludo de cierre no está implementado? Consulte esto ).
  2. Versión Java requerida Java SE 5, 6, 7, 8 o Java EE? Funciona incluso en Android?
  3. Tamaño . Algunas implementaciones tienen muchas dependencias.
  4. soporte wss .
  5. Soporte proxy HTTP .
  6. wss a través del soporte de proxy HTTP . Consulte la Figura 2 en Cómo los sockets web HTML5 interactúan con los servidores proxy acerca de lo que debe hacer una biblioteca de cliente WebSocket para admitir wss a través del proxy HTTP.
  7. Flexibilidad en la configuración de SSL . SSLSocketFactory y SSLContext deberían poder utilizarse sin restricciones innecesarias.
  8. Cabeceras HTTP personalizadas en el handshake de apertura , incluida la autenticación básica.
  9. Cabeceras HTTP personalizadas en la negociación de proxy HTTP , incluida la autenticación en el servidor proxy.
  10. Capaz de enviar todos los tipos de cuadros (continuación, binario, texto, cerrar, ping y pong) o no. La mayoría de las implementaciones no proporcionan a los desarrolladores los medios para enviar marcos fragmentados y marcos de pong no solicitados manualmente.
  11. Interfaz de escucha para recibir varios eventos de WebSocket. Una interfaz deficiente frustra a los desarrolladores. Una interfaz rica ayuda a los desarrolladores a escribir aplicaciones robustas.
  12. Capaz de consultar el estado de WebSocket o no. RFC 6455 define estados de CONEXIÓN, ABRIR, CERRAR y CERRADO, pero pocas implementaciones mantienen su transición de estado interno de la manera definida.
  13. Capaz de establecer un valor de tiempo de espera para la conexión de socket . (Equivalente al segundo argumento del método Socket. connect (SocketAddress endpoint, int timeout) )
  14. Capaz de acceder al zócalo crudo subyacente .
  15. Intuitiva API fácil de usar o no.
  16. Bien documentado o no.
  17. Compatibilidad con RFC 7692 (Extensiones de compresión para WebSocket) (también conocido como permessage-deflate).
  18. Soporte de redirección (3xx).
  19. Soporte de Autenticación Digest .

nv-websocket-client cubre todo lo anterior excepto los dos últimos. Además, una de sus características pequeñas pero convenientes es enviar cuadros de ping / pong periódicamente. Se puede lograr simplemente llamando a los métodos setPingInterval / setPongInterval (Ver JavaDoc ).

Descargo de responsabilidad: Takahiko Kawasaki es el autor de nv-websocket-client.

Algunas otras consideraciones:

Tyrus trabaja en Android. Sin embargo, las bibliotecas SSL que usa en Android 5.0 son defectuosas y fallan los apretones de manos de SSL . Se supone que esto se debe solucionar en las versiones más nuevas de Android, pero con la forma en que Android no se actualiza en muchos dispositivos, esto puede ser un problema para usted.

Dependiendo de cómo se implementa SSL para otras implementaciones de websocket, esto también puede ser un problema.

AndroidAsync no tiene este problema SSL. Tiene otros problemas como no poder establecer los tiempos de espera .

a) Agregue este archivo en el archivo gradle

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

b) Agregue estas líneas en la Actividad de la aplicación:

  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) Agregue esta función a su actividad, donde llamó 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(() -> { }); } };