Quando precisamos fazer uma conexão com uma API existem algumas formas de fazer essa comunicação, como a SSE (que já falamos por aqui) https://medium.com/brasilflutter/server-sent-events-sse-com-dart-shelf-e-flutter-663589e300cc, em alguns casos precisamos de que essa comunicação seja interrupta e de forma bidirecional, ou seja, tanta quando houver alterações no cliente ou no server a aplicação seja notificada.

Vamos imaginar um exemplo que estamos desenvolvendo um aplicativo de mensagens instantânea (igual o whatsapp), então temos o cenário que a pessoa A estar conversando com a pessoa B, quando a pessoa A enviar mensagem deve notificar a pessoa B e vice-versa. Uma maneira de fazer isso é realizar uma solicitação HTTP periodicamente ao servidor para verificar se há novas mensagens para o usuário, esse método é conhecido como long pooling.
O problema do long pooling é que esta abordagem acaba criando requisições HRRP inúteis sobrecarregando o servidor.
A solução para este problema é utilizarmos WebSocket, criando uma conexão interrupta ao servidor que escutará todas as mensagens e quando não for mais necessário não se esqueça de fechar a conexão do WebSocket.

Para realizar esse tipo de conexão no flutter utilizaremos o pacote web_socket_channel que é um package criado e mantido pelo dart.dev, você pode conferir em https://pub.dev/packages/web_socket_channel.
A primeira tarefa que precisamos fazer é adicionar no nosso pubspec o pacote web_socket_channel apontando para sua última versão disponível.
| dependencies: |
| flutter: |
| sdk: flutter |
| web_socket_channel: ^3.0.1 |
para utilizarmos basta passar uma URI com o endereço do WebSocket
| final channel = WebSocketChannel.connect(Uri.parse(‘ws://localhost:8080/ws’)); |
Agora necessitamos adicionar um listener que ficara escutando todas as interações ao servidor e me retornara uma mensagem, que pode ser um simples String que iremos armazenar em uma lista
| final msg = ValueNotifier<List<String>>([]); |
| final channel = WebSocketChannel.connect(Uri.parse(‘wss://ws.postman-echo.com/raw’)); |
| init() async { |
| await channel.ready; |
| channel.stream.listen( |
| (message) { |
| msg.value = List.from(msg.value)..add(message); |
| }, |
| cancelOnError: true, |
| ); |
| } |
Ou podemos considerar que o WebSocket irá nos retornar um json onde posso desserializar em um objeto complexo
| final msg = ValueNotifier<List<String>>([]); |
| final msg = ValueNotifier<List<MessageEntity>>([]); |
| init() async { |
| await channel.ready; |
| channel.stream.listen( |
| (message) { |
| msg.value = List.from(msg.value)..add(MessageEntity.fromJson(message)); |
| }, |
| cancelOnError: true, |
| ); |
| } |
Também podemos tratar quando ocorrer um erro no WebSocket ou quando a comunicação for encerrada
| channel.stream.listen( |
| (message) { |
| msg.value = List.from(msg.value)..add(MessageEntity.fromJson(message)); |
| }, |
| onError: (error, stackTrace) { |
| print(error); |
| }, |
| onDone: () { |
| print(‘Comunicação encerrada.’); |
| }, |
| cancelOnError: true, |
| ); |
Agora para enviar a mensagem para o WebSocket apenas teremos que realizar um .add() na instância do WebSocket
| sendMessage(String message, String username) { |
| channel.sink |
| .add(MessageEntity(message: message, username: username).toJson()); |
Para testarmos o WebSocket podemos utilizar o WSCAT https://www.npmjs.com/package/wscat
E como resultado final teremos:

Viu só como não é uma tarefa difícil trabalhar com WebSocket? E também é possível criar o servidor em Dart, no próximo artigo eu demonstro como criar.
O código completo do exemplo deste artigo pode ser encontrado no meu github: https://github.com/toshiossada/dart_websocket_example
Até a proxima




