Qual biblioteca do WebSocket usar no aplicativo Android? [fechadas]

131

Desejo adicionar um Serviço ao meu aplicativo Android, que é executado em segundo plano, mantendo uma conexão WebSocket (possivelmente por várias horas ou até dias) e envia regularmente alguns dados para um servidor.

Agora, parece haver várias bibliotecas WebSocket para Java, e não tenho certeza de qual delas devo usar:

Além disso, há uma biblioteca cliente socket.io nativa para Android:

  • nkzawa / socket.io-client.java Descrição do GitHub: Biblioteca cliente Socket.IO completa para Java, compatível com o Socket.IO v1.0 e posterior.

Usar o cliente Android socket.io seria útil para mim, porque planejo usar o nodejs / socket.io para o front-end da Web de qualquer maneira. Mas o cliente nativo é bastante jovem e possui vários problemas em aberto. Além disso, entendo que um aplicativo Android não tem nenhum benefício em usar a biblioteca cliente socket.io (além de ser compatível com o servidor socket.io 1.0), porque o suporte ao WebSocket pode ser garantido no lado do cliente .

Meus requisitos são os seguintes:

  • Compatibilidade com a API Android 9 e superior
  • Possibilidade de conectar via SSL
  • Mantenha a conexão por um longo tempo sem ter que segurar um wakelock permanente
  • Compatibilidade com uma implementação disponível do servidor nodejs websocket ou com socket.io

Alguma sugestão de qual é a biblioteca certa para esses requisitos?

raio X
fonte
Talvez atmosfera . Veja esta pergunta .
Basil Bourque
2
Não sou especialista em WebSocket nem Atmosphere. Sei apenas que o Atmosphere está bem gasto, usado em muitos projetos de recursos Push , incluindo suporte ao WebSocket. Minha única experiência é indireta na criação de aplicativos Web Vaadin . Vaadin usa o Atmosphere por sua capacidade de envio automático. Mas cuidado, o WebSocket ainda é relativamente novo, com muitas alterações em sua definição, especificações e várias implementações durante seu breve histórico. Portanto, espere "problemas", não importa como você vá.
Basil Bourque
2
FYI, Autobahn está lá fora e eles têm um site chamativo. Mas não observe que "WebSockets seguros não foram implementados" até você gastar o tempo para instalar e tentar executá-lo. Próximo.
cloudsurfin
1
Como não tenho reputação suficiente para comentar, escrevo-a como resposta, pois cumpri os mesmos requisitos mencionados na sua pergunta e o okhttp me ajudou a satisfazer todos os requisitos. Ele suporta soquetes da web desde a introdução da versão 3.5. Portanto, é uma vantagem adicional usar o okHttp (chamadas de serviço da web + suporte de soquetes da web). Aqui está o link para começar. < medium.com/@ssaurel/… >
Kaleem Patel
7
Perguntas como esta não devem ser encerradas.
Martin Berger

Respostas:

123

Algumas notas.

  • O koush / AndroidAsync não executa o handshake de fechamento exigido pela RFC 6455 . Veja isto para detalhes.

  • O Project Tyrus funciona no Android, mas certifique-se de que sua licença ( CDDL 1.1 e GPL 2 com CPE ) e seu tamanho ( Reduzindo o tamanho do jar do cliente WebSocket com o ProGuard ) atendam aos seus requisitos. Observe também que o Tyrus pode gerar uma exceção quando o tamanho do texto é grande (provavelmente é um bug). Veja isto para detalhes.

  • Jetty : um tópico de e - mail de dois anos atrás na lista de discussão jetty-users diz "No momento, não temos um cliente Jetty 9 WebSocket compatível com Android. Há planos de tentar fazer o backport do Jetty WebSocket Client do JDK 7 para o JDK 5/6 para Android uso, mas é uma prioridade mais baixa do que concluir nossa implementação da API Java WebSocket JSR-356 (javax.websocket). " O documento atual do Jetty sobre a API do WebSocket Client não menciona nada sobre o Android.

  • O codebutler / android-websocket não executa o handshake de fechamento exigido pela RFC 6455 e pode lançar uma exceção de perto. Veja isso .

  • O Atmosphere / wasync usa AsyncHttpClient / async-http-client como sua implementação do WebSocket. Portanto, deve-se mencionar AsyncHttpClient / async-http-client.

  • firebase / TubeSock não verifica Sec-WebSocket-Accept. Isso é uma violação contra a RFC 6455 . Além disso, o TubeSock tem um erro ao criar uma mensagem de texto. Você encontrará o bug mais cedo ou mais tarde se você usar caracteres UTF-8 de bytes múltiplos para mensagens de texto. Consulte a Edição 3 em delight-im / Android-DDP para obter uma lista longa sobre os problemas do TubeSock.

Pontos de consideração

Pontos de consideração na seleção de uma implementação do cliente WebSocket escrita em Java:

  1. Conformidade . Um número pequeno de implementações não implementa o handshake de fechamento exigido pela RFC 6455 . (O que acontece se o handshake de fechamento não for implementado? Veja isso .)
  2. Versão Java necessária . Java SE 5, 6, 7, 8 ou Java EE? Funciona mesmo no Android?
  3. Size . Algumas implementações têm muitas dependências.
  4. suporte a wss .
  5. Suporte a proxy HTTP .
  6. suporte a wss sobre proxy HTTP . Consulte a Figura 2 em Como os soquetes da Web HTML5 interagem com os servidores proxy sobre o que uma biblioteca cliente WebSocket precisa fazer para oferecer suporte ao wss sobre o proxy HTTP.
  7. Flexibilidade na configuração SSL . SSLSocketFactorye SSLContextdeve poder ser utilizado sem restrições desnecessárias.
  8. Cabeçalhos HTTP personalizados no handshake de abertura , incluindo autenticação básica.
  9. Cabeçalhos HTTP personalizados na negociação de proxy HTTP , incluindo autenticação no servidor proxy.
  10. Capaz de enviar todos os tipos de quadros (continuação, binário, texto, fechamento, ping e pong) ou não. A maioria das implementações não fornece aos desenvolvedores meios para enviar quadros fragmentados e quadros de pong não solicitados manualmente.
  11. Interface do ouvinte para receber vários eventos do WebSocket. Uma interface ruim deixa os desenvolvedores frustrados. Uma interface rica ajuda os desenvolvedores a escrever aplicativos robustos.
  12. Capaz de consultar ou não o estado WebSocket . O RFC 6455 define os estados CONNECTING, OPEN, CLOSING e CLOSED, mas poucas implementações mantêm sua transição de estado interna da maneira definida.
  13. Capaz de definir um valor de tempo limite para a conexão do soquete . (Equivalente ao segundo argumento do método)Socket.connect(SocketAddress endpoint, int timeout)
  14. Capaz de acessar o soquete bruto subjacente .
  15. API intuitiva e fácil de usar ou não.
  16. Bem documentado ou não.
  17. Suporte ao RFC 7692 (extensões de compressão para WebSocket) (também conhecido como permessage-deflate).
  18. Suporte de redirecionamento (3xx).
  19. Suporte à autenticação Digest .

O nv-websocket-client cobre todos os itens acima, exceto os dois últimos. Além disso, um de seus recursos pequenos, porém convenientes, é enviar quadros de ping / pong periodicamente. Isso pode ser alcançado apenas chamandosetPingInterval/setPongIntervalmétodos (consulte JavaDoc ).

Isenção de responsabilidade: Takahiko Kawasaki é o autor do nv-websocket-client.

Takahiko Kawasaki
fonte
1
a biblioteca nv-websocket-client ainda está em desenvolvimento? Eu enfrentei um problema de desconexão automática com TooTallNate / Java-WebSockets com erro 1006 e sem motivo .. este nv-websocket também resolve isso?
Ankit Bansal
1
Quanto ao 1006, a especificação (RFC 6455) afirma que o código NÃO DEVE ser definido como um código de status em um quadro de controle Fechar por um ponto de extremidade . Isso significa que o código foi gerado no lado do cliente. Você pode obter mais informações sobre desconexão através do onDisconnectedmétodo e onErrormétodo do WebSocketListener . onErrorO método fornece uma WebSocketExceptioninstância. Chame seu getError()método para ver qual é o problema.
Takahiko Kawasaki
7
Para o wss, tentei okhttp e autobahn (também suspeito de autopromoção nesta resposta). Autobahn foi fácil, mas não tem SSL. O OkHttp possui pouca ou nenhuma documentação (consolidada) (fevereiro de 2016). Eu perdi muito tempo lendo o código e as exceções porque não tinha acesso a soluções alternativas (como definir o tempo limite como 0 ou fechar a mensagem recebida) para obter um exemplo básico. Despejando aqueles dois (e minha frustração), achei nv (refrescante) bem documentado; funcionou sem problemas.
cloudsurfin
1
Alguma opinião sobre os novos websockets da Square / okhttp? medium.com/square-corner-blog/…
scorpiodawg
2
Não sei detalhes sobre o OkHttp. Sinto muito por estar tão ocupado como o fundador da Authlete, Inc. ("A startup de segurança da API Authlete levanta US $ 1,2 milhão em financiamento inicial "). Não tenho tempo para olhar o OkHttp e atualizar a lista de pontos de consideração. Sobre as alterações desde a minha resposta, consulte CHANGES.md . Observe que o nv-websocket-client é apenas o meu hobby, enquanto o OkHttp parece um grande projeto com 138 colaboradores.
Takahiko Kawasaki
4

Algumas outras considerações:

Tyrus funciona no Android. No entanto, as bibliotecas SSL usadas no Android 5.0 são de bugs e apresentam falhas nos handshakes SSL . Isso deve ser corrigido nas versões mais recentes do Android, mas com a maneira como o Android não é atualizado em muitos dispositivos, isso pode ser um problema para você.

Dependendo de como o SSL é implementado para outras implementações de websocket, isso também pode ser um problema.

AndroidAsync não tem esse problema de SSL. Ele tem outros problemas, como não conseguir definir tempos limite .

mattm
fonte
3

a) Adicione este arquivo no arquivo gradle

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

b) Adicione estas linhas na Atividade do Aplicativo:

    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) Adicione esta função à sua atividade, onde você chamou 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
fonte
Isso não suporta o protocolo ws: //.
Girish Bhutiya