Której biblioteki WebSocket użyć w aplikacji na Androida? [Zamknięte]

136

Chcę dodać usługę do mojej aplikacji na Androida, która działa w tle, utrzymując połączenie WebSocket (prawdopodobnie przez kilka godzin lub nawet dni) i regularnie wysyła niektóre dane na serwer.

Teraz wydaje się, że jest kilka bibliotek WebSocket dla Javy i nie jestem pewien, której powinienem użyć:

Ponadto istnieje natywna biblioteka klienta socket.io dla systemu Android:

  • nkzawa / socket.io-client.java Opis z GitHub: W pełni funkcjonalna biblioteka klienta Socket.IO dla języka Java, która jest kompatybilna z Socket.IO v1.0 i nowszymi.

Korzystanie z klienta socket.io na Androida byłoby dla mnie przydatne, ponieważ i tak planuję używać nodejs / socket.io do frontendu internetowego. Ale rodzimy klient jest dość młody i ma kilka otwartych problemów. Poza tym, rozumiem, że aplikacja na Androida nie ma żadnych korzyści z używania biblioteki klienta socket.io (poza kompatybilnością z serwerem socket.io 1.0), ponieważ obsługa WebSocket może być zapewniona po stronie klienta .

Moje wymagania są następujące:

  • Zgodność z Android API 9 i nowszym
  • Możliwość połączenia przez SSL
  • Utrzymuj połączenie przez długi czas bez konieczności utrzymywania stałego wakelocka
  • Kompatybilność z dostępną implementacją serwera nodejs websocket lub z socket.io

Jakieś sugestie, która biblioteka jest odpowiednia dla tych wymagań?

prześwietlenie
źródło
Być może atmosfera . Zobacz to pytanie .
Basil Bourque
2
Nie jestem ekspertem od WebSocket ani Atmosphere. Wiem tylko, że Atmosphere jest mocno zużyty, używany w wielu projektach dla funkcji Push, w tym obsługi WebSocket. Moje jedyne doświadczenie jest pośrednie, w tworzeniu aplikacji internetowych Vaadin . Vaadin wykorzystuje Atmosphere do swojej automatycznej funkcji Push. Ale uwaga, WebSocket jest wciąż stosunkowo nowy, z wieloma zmianami w jego definicji, specyfikacjach i różnych implementacjach w swojej krótkiej historii. Więc spodziewaj się „problemów” bez względu na to, jak idziesz.
Basil Bourque
2
FYI, Autobahn jest tam i mają krzykliwą stronę internetową. Ale nie zauważ, że „bezpieczne WebSockets nie zostały zaimplementowane”, dopóki nie poświęcisz czasu na instalację i próbę uruchomienia. Kolejny.
cloudsurfin
1
Nie mam wystarczającej reputacji, aby komentować, więc piszę to jako odpowiedź, ponieważ spełniłem te same wymagania, o których wspomniałeś w swoim pytaniu, i okhttp pomogło mi spełnić wszystkie wymagania. Obsługuje gniazda sieciowe od czasu wprowadzenia wersji 3.5, więc dodatkową zaletą jest używanie okHttp (wywołania usług internetowych + obsługa gniazd sieciowych). Oto link, od którego można zacząć. < medium.com/@ssaurel/… >
Kaleem Patel
9
Takie pytania nie powinny być zamykane.
Martin Berger,

Odpowiedzi:

126

Kilka uwag.

  • koush / AndroidAsync nie wykonuje uzgadniania zamykającego, które jest wymagane przez RFC 6455 . Zobacz to, aby uzyskać szczegółowe informacje.

  • Projekt Tyrus działa na Androidzie, ale upewnij się, że jego licencja ( CDDL 1.1 i GPL 2 z CPE ) i jego rozmiar ( Zmniejszenie rozmiaru jar klienta WebSocket z ProGuard ) spełniają Twoje wymagania. Zwróć również uwagę, że Tyrus może zgłosić wyjątek, gdy rozmiar tekstu jest duży (prawdopodobnie jest to błąd). Zobacz to, aby uzyskać szczegółowe informacje.

  • Molo : 2 lata temu wątek e - mailowy na liście mailingowej użytkowników molo zawiera komunikat „Obecnie nie mamy klienta Jetty 9 WebSocket zgodnego z systemem Android. Planowane są próby przeniesienia klienta Jetty WebSocket z wersji JDK 7 na JDK 5/6 dla systemu Android wykorzystania, ale jest to niższy priorytet niż zakończenie naszej implementacji JSR-356 Java WebSocket API (javax.websocket). " Obecny dokument Jetty na temat jego interfejsu API klienta WebSocket nie wspomina nic o Androidzie.

  • codebutler / android-websocket nie wykonuje uzgadniania zamykającego, które jest wymagane przez RFC 6455 i może zgłosić wyjątek podczas zamykania. Zobacz to .

  • Atmosphere / wasync używa AsyncHttpClient / async-http-client jako implementacji WebSocket. Zamiast tego należy raczej wspomnieć o AsyncHttpClient / async-http-client.

  • Firebase / TubeSock nie weryfikuje Sec-WebSocket-Accept. Jest to naruszenie RFC 6455 . Ponadto TubeSock ma błąd w tworzeniu wiadomości tekstowej. Prędzej czy później napotkasz ten błąd, jeśli używasz wielobajtowych znaków UTF-8 w wiadomościach tekstowych. Zobacz Wydanie 3 w Delight-im / Android-DDP, aby uzyskać długą listę problemów z TubeSock.

Punkty do rozważenia

Punkty do rozważenia przy wyborze implementacji klienta WebSocket napisanej w języku Java:

  1. Zgodność . Niewielka liczba implementacji nie implementuje uzgadniania zamykającego wymaganego przez RFC 6455 . (Co się stanie, jeśli uzgadnianie zamykające nie zostanie zaimplementowane? Zobacz to ).
  2. Wymagana wersja Java . Java SE 5, 6, 7, 8 czy Java EE? Działa nawet na Androidzie?
  3. Rozmiar . Niektóre implementacje mają wiele zależności.
  4. wsparcie wss .
  5. Obsługa proxy HTTP .
  6. wss przez HTTP proxy . Zobacz Rysunek 2 w Jak gniazda sieciowe HTML5 współdziałają z serwerami proxy, aby dowiedzieć się, co musi zrobić biblioteka klienta WebSocket, aby obsługiwać wss przez serwer proxy HTTP.
  7. Elastyczność w konfiguracji SSL . SSLSocketFactoryi SSLContextpowinno być możliwe do wykorzystania bez zbędnych ograniczeń.
  8. Niestandardowe nagłówki HTTP w początkowym uzgadnianiu , w tym uwierzytelnianie podstawowe.
  9. Niestandardowe nagłówki HTTP w negocjacjach proxy HTTP , w tym uwierzytelnianie na serwerze proxy.
  10. Możliwość wysyłania wszystkich typów ramek (kontynuacja, binarna, tekstowa, zamknięta, ping i pong) lub nie. Większość implementacji nie zapewnia programistom możliwości ręcznego wysyłania pofragmentowanych ramek i niechcianych ramek ponga .
  11. Interfejs nasłuchujący do odbierania różnych zdarzeń WebSocket. Słaby interfejs powoduje frustrację programistów. Bogaty interfejs pomaga programistom pisać niezawodne aplikacje.
  12. W stanie zapytać o stan WebSocket, czy nie. RFC 6455 definiuje stany CONNECTING, OPEN, CLOSING i CLOSED, ale niewiele implementacji utrzymuje wewnętrzne przejście stanu w zdefiniowany sposób.
  13. Możliwość ustawienia wartości limitu czasu dla połączenia z gniazdem . (Odpowiednik drugiego argumentu metody)Socket.connect(SocketAddress endpoint, int timeout)
  14. Możliwość dostępu do podstawowego gniazda surowego .
  15. Intuicyjny i łatwy w użyciu interfejs API, czy nie.
  16. Dobrze udokumentowane czy nie.
  17. Obsługa RFC 7692 (Compression Extensions for WebSocket) (inaczej permessage-deflate).
  18. Obsługa przekierowań (3xx).
  19. Obsługa uwierzytelniania Digest .

nv-websocket-client obejmuje wszystkie powyższe z wyjątkiem dwóch ostatnich. Ponadto jedną z jego małych, ale wygodnych funkcji jest okresowe wysyłanie ramek ping / pong. Można to osiągnąć po prostu wywołującsetPingInterval/ MethodssetPongInterval (patrz JavaDoc ).

Zastrzeżenie: Takahiko Kawasaki jest autorem nv-websocket-client.

Takahiko Kawasaki
źródło
1
Czy biblioteka nv-websocket-client jest wciąż w fazie rozwoju? Napotkałem problem z automatycznym rozłączaniem z TooTallNate / Java-WebSockets z błędem 1006 i BEZ powodu .. czy ten nv-websocket również go rozwiązuje?
Ankit Bansal
1
Jeśli chodzi o 1006, specyfikacja (RFC 6455) stwierdza, że ​​kod NIE MOŻE być ustawiony jako kod stanu w ramce kontrolnej Zamknij przez punkt końcowy . Oznacza to, że kod został wygenerowany po stronie klienta. Więcej informacji na temat rozłączania można uzyskać za pomocą onDisconnectedmetody i onErrormetody WebSocketListener . onErrormetoda daje WebSocketExceptioninstancję. Wywołaj jego getError()metodę, aby zobaczyć, w czym jest problem.
Takahiko Kawasaki
7
W przypadku wss próbowałem okhttp i autobahn (również podejrzewam autopromocję w tej odpowiedzi). Autobahn było łatwe, ale nie ma SSL. OkHttp ma niewiele do zera (skonsolidowanej) dokumentacji (luty 2016 r.). Zmarnowałem dużo czasu, czytając ich kod i ich wyjątki, ponieważ nie byłem w stanie zastosować obejść (takich jak ustawienie limitu czasu na 0 lub zamknięcie wiadomości przychodzącej), aby uruchomić przykład gołej kości. Pozbywając się tych dwóch (i mojej frustracji), znalazłem nv (odświeżająco) dobrze udokumentowane; działało bez zamieszania.
cloudsurfin
1
Jakieś przemyślenia na temat obsługi nowych gniazd sieciowych Square / okhttp? medium.com/square-corner-blog/…
scorpiodawg
2
Nie znam szczegółów na temat OkHttp. Przykro mi, że jestem tak zajęty jako założyciel Authlete, Inc. („ Authlete, startujący z bezpieczeństwem API, pozyskuje 1,2 miliona dolarów na finansowanie początkowe ”). Nie mam czasu na zajrzenie do OkHttp i zaktualizowanie listy punktów do rozważenia. Odnośnie zmian od mojej odpowiedzi, zobacz CHANGES.md . Proszę zauważyć, że nv-websocket-client to tylko moje hobby, podczas gdy OkHttp wydaje się dużym projektem mającym 138 współpracowników.
Takahiko Kawasaki,
4

Kilka innych uwag:

Tyrus działa na Androidzie. Jednak biblioteki SSL, których używa w systemie Android 5.0, są wadliwe i nie mogą uzgadniać SSL . Ma to zostać naprawione w nowszych wersjach Androida, ale ze względu na to, że Android nie jest aktualizowany na wielu urządzeniach, może to stanowić problem.

W zależności od tego, jak SSL jest zaimplementowany w innych implementacjach protokołu internetowego, może to również stanowić problem.

AndroidAsync nie ma tego problemu z SSL. Ma inne problemy, takie jak brak możliwości ustawienia limitów czasu .

mattm
źródło
2

a) Dodaj ten plik w pliku gradle

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

b) Dodaj te wiersze w Aktywności aplikacji:

    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) Dodaj tę funkcję do swojej aktywności, w której wywołałeś 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
źródło
To nie obsługuje protokołu ws: //.
Girish Bhutiya