Quelle bibliothèque WebSocket utiliser dans l'application Android? [fermé]

131

Je souhaite ajouter un service à mon application Android qui s'exécute en arrière-plan avec une connexion WebSocket (éventuellement sur plusieurs heures, voire plusieurs jours) et envoie régulièrement des données à un serveur.

Maintenant, il semble y avoir un tas de bibliothèques WebSocket pour Java, et je ne sais pas laquelle je devrais utiliser:

De plus, il existe une bibliothèque client native socket.io pour Android:

  • nkzawa / socket.io-client.java Description de GitHub: Bibliothèque cliente Socket.IO complète pour Java, compatible avec Socket.IO v1.0 et versions ultérieures.

Utiliser le client Android socket.io serait pratique pour moi, car je prévois d'utiliser de toute façon nodejs / socket.io pour le frontend Web. Mais le client natif est assez jeune et a plusieurs problèmes en suspens. Et en plus de cela, je crois comprendre qu'une application Android n'a aucun avantage à utiliser la bibliothèque client socket.io (en plus d'être compatible avec le serveur socket.io 1.0), car la prise en charge de WebSocket peut être assurée côté client .

Mes exigences sont les suivantes:

  • Compatibilité avec l'API Android 9 et supérieur
  • Possibilité de se connecter via SSL
  • Gardez la connexion pendant une longue période sans avoir à tenir un wakelock permanent
  • Compatibilité avec une implémentation de serveur websocket nodejs disponible ou avec socket.io

Des suggestions quelle est la bonne bibliothèque pour ces exigences?

radiographie
la source
Peut-être Atmosphère . Voir cette question .
Basil Bourque
2
Je ne suis pas un expert sur WebSocket ni sur Atmosphere. Je sais seulement que Atmosphere est bien usé, utilisé dans de nombreux projets pour les fonctionnalités Push , y compris le support WebSocket. Ma seule expérience est indirecte, dans la création d'applications Web Vaadin . Vaadin utilise Atmosphere pour sa capacité Push automatique. Mais attention, WebSocket est encore relativement nouveau avec de nombreux changements dans sa définition, ses spécifications et diverses implémentations au cours de sa brève histoire. Alors attendez-vous à des «problèmes», peu importe comment vous allez.
Basil Bourque
2
FYI, Autobahn est là-bas et ils ont un site Web flashy. Mais ne remarquez pas que "WebSockets sécurisé n'est pas implémenté" jusqu'à ce que vous passiez le temps à l'installer et à essayer de l'exécuter. Prochain.
cloudsurfin
1
Je n'ai pas assez de réputation pour commenter donc je l'écris comme réponse car j'ai passé par les mêmes exigences que vous avez mentionnées dans votre question et okhttp m'a aidé à satisfaire toutes les exigences. Il prend en charge les sockets Web depuis l'introduction de la version 3.5, c'est donc un avantage supplémentaire d'utiliser okHttp (appels de service Web + prise en charge des sockets Web). Voici le lien pour commencer. < medium.com/@ssaurel/... >
Kaleem Patel
7
Des questions comme celle-ci ne devraient pas être fermées.
Martin Berger

Réponses:

123

Quelques notes.

  • koush / AndroidAsync n'effectue pas la négociation de clôture requise par la RFC 6455 . Voir ceci pour plus de détails.

  • Project Tyrus fonctionne sur Android, mais assurez-vous que sa licence ( CDDL 1.1 et GPL 2 avec CPE ) et sa taille ( Réduire la taille du jar client WebSocket avec ProGuard ) répondent à vos exigences. Notez également que Tyrus peut lancer une exception lorsqu'une taille de texte est grande (c'est probablement un bogue). Voir ceci pour plus de détails.

  • Jetty : Il y a 2 ans, un fil de discussion dans la liste de diffusion des utilisateurs de jetty indique: "Nous n'avons actuellement aucun client WebSocket Jetty 9 compatible Android. Il est prévu de tenter de rétroporter le client Jetty WebSocket de JDK 7 vers JDK 5/6 pour Android utiliser, mais c'est une priorité inférieure à la fin de notre implémentation de l'API Java WebSocket JSR-356 (javax.websocket). " Le document actuel de Jetty sur son API WebSocket Client ne mentionne rien sur Android.

  • codebutler / android-websocket n'effectue pas la négociation de fermeture qui est requise par la RFC 6455 et peut lever une exception à la fermeture. Regarde ça .

  • Atmosphere / wasync utilise AsyncHttpClient / async-http-client comme implémentation WebSocket. Donc, plutôt, AsyncHttpClient / async-http-client devrait être mentionné à la place.

  • firebase / TubeSock ne vérifie pas Sec-WebSocket-Accept. Il s'agit d'une violation de la RFC 6455 . En outre, TubeSock a un bogue dans la construction d'un message texte. Vous rencontrerez le bogue tôt ou tard si vous utilisez des caractères UTF-8 multi-octets pour les messages texte. Voir le numéro 3 dans Delight-im / Android-DDP pour une longue liste des problèmes de TubeSock.

Points à considérer

Points à prendre en compte lors de la sélection d'une implémentation client WebSocket écrite en Java:

  1. Conformité . Pas un petit nombre d'implémentations n'implémentent pas la négociation de fermeture requise par RFC 6455 . (Que se passe-t-il si la poignée de main de clôture n'est pas implémentée? Voir ceci .)
  2. Version Java requise . Java SE 5, 6, 7, 8 ou Java EE? Fonctionne même sur Android?
  3. Taille . Certaines implémentations ont de nombreuses dépendances.
  4. support wss .
  5. Prise en charge du proxy HTTP .
  6. wss sur la prise en charge du proxy HTTP . Reportez-vous à la figure 2 dans Interaction des sockets Web HTML5 avec les serveurs proxy pour savoir ce qu'une bibliothèque cliente WebSocket doit faire pour prendre en charge wss sur le proxy HTTP.
  7. Flexibilité sur la configuration SSL . SSLSocketFactoryet SSLContextdevrait pouvoir être utilisé sans restrictions inutiles.
  8. En-têtes HTTP personnalisés dans la poignée de main d'ouverture , y compris l'authentification de base.
  9. En-têtes HTTP personnalisés dans la négociation de proxy HTTP , y compris l'authentification au niveau du serveur proxy.
  10. Capable d'envoyer tous les types de trames (suite, binaire, texte, close, ping et pong) ou non. La plupart des implémentations ne fournissent pas aux développeurs les moyens d'envoyer manuellement des trames fragmentées et des trames pong non sollicitées .
  11. Interface d'écoute pour recevoir divers événements WebSocket. Une mauvaise interface rend les développeurs frustrés. Une interface riche aide les développeurs à écrire des applications robustes.
  12. Capable de se renseigner sur l'état de WebSocket ou non. La RFC 6455 définit les états CONNECTING, OPEN, CLOSING et CLOSED, mais peu d'implémentations maintiennent leur transition d'état interne de la manière définie.
  13. Capable de définir une valeur de délai d'expiration pour la connexion socket . (Équivaut au deuxième argument de la méthode)Socket.connect(SocketAddress endpoint, int timeout)
  14. Capable d'accéder au socket brut sous-jacent .
  15. API intuitive facile à utiliser ou non.
  16. Bien documenté ou pas.
  17. Prise en charge de la RFC 7692 (Compression Extensions for WebSocket) (aka permessage-deflate).
  18. Prise en charge de la redirection (3xx).
  19. Prise en charge de l' authentification Digest .

nv-websocket-client couvre tout ce qui précède, sauf les deux derniers. En outre, l'une de ses fonctionnalités petites mais pratiques est d'envoyer périodiquement des trames de ping / pong. Cela peut être réalisé simplement en appelantsetPingInterval/setPongIntervalmethods (voir JavaDoc ).

Avertissement: Takahiko Kawasaki est l'auteur de nv-websocket-client.

Takahiko Kawasaki
la source
1
la bibliothèque nv-websocket-client est-elle toujours en développement? J'ai rencontré un problème de déconnexion automatique avec TooTallNate / Java-WebSockets avec l'erreur 1006 et AUCUNE raison. Est-ce que ce nv-websocket le résout également?
Ankit Bansal
1
Comme pour 1006, la spécification (RFC 6455) indique que le code NE DOIT PAS être établi comme code d'état dans une trame de contrôle Close par un point d'extrémité . Cela signifie que le code a été généré côté client. Vous pouvez obtenir plus d'informations sur la déconnexion via la onDisconnectedméthode et la onErrorméthode de WebSocketListener . onErrorméthode vous donne une WebSocketExceptioninstance. Appelez sa getError()méthode pour voir quel est le problème.
Takahiko Kawasaki
7
Pour wss, j'ai essayé okhttp et autobahn (également suspect de l'auto-promotion dans cette réponse). Autobahn était facile, mais n'a pas de SSL. OkHttp a peu ou pas de documentation (consolidée) (février 2016). J'ai perdu beaucoup de temps à lire leur code et leurs exceptions parce que je n'étais pas au courant des solutions de contournement (comme définir le délai d'expiration à 0 ou fermer le message entrant) pour faire fonctionner un exemple simple. Laissant ces deux (et ma frustration), j'ai trouvé nv (rafraîchissant) bien documenté; cela a fonctionné sans problème.
cloudsurfin
1
Avez-vous des idées sur le nouveau support de Square / okhttp? medium.com/square-corner-blog/…
scorpiodawg
2
Je ne connais pas les détails d'OkHttp. Je suis désolé d'être si occupé en tant que fondateur d' Authlete, Inc. ("La start-up de sécurité API Authlete lève 1,2 million de dollars en financement de démarrage "). Je ne peux pas perdre de temps pour examiner OkHttp et mettre à jour la liste des points à considérer. Concernant les changements depuis ma réponse, voir CHANGES.md . Veuillez noter que nv-websocket-client est juste mon hobby alors qu'OkHttp semble être un gros projet ayant 138 contributeurs.
Takahiko Kawasaki
4

Quelques autres considérations:

Tyrus fonctionne sur Android. Cependant, les bibliothèques SSL qu'il utilise dans Android 5.0 sont boguées et échouent aux handshakes SSL . Ceci est censé être corrigé dans les nouvelles versions d'Android, mais avec la façon dont Android n'est pas mis à jour sur de nombreux appareils, cela peut être un problème pour vous.

Selon la façon dont SSL est implémenté pour d'autres implémentations websocket, cela peut également être un problème.

AndroidAsync n'a pas ce problème SSL. Il a d'autres problèmes comme l' impossibilité de définir des délais d'expiration .

mattm
la source
3

a) Ajoutez ce fichier dans le fichier gradle

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

b) Ajoutez ces lignes dans l'activité de l'application:

    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) Ajoutez cette fonction à votre activité, où vous avez appelé 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(() -> {


            });
        }
    };
Anil Singhania
la source
Cela ne prend pas en charge le protocole ws: //.
Girish Bhutiya