Pular para o conteúdo principal

Exemplos de WebSocket Android

WebSocket é um protocolo que permite abrir uma sessão de comunicação interativa bidirecional entre o cliente e o servidor. Ele fornece canais de comunicação full-duplex em uma única conexão TCP.

Este protocolo define uma API que estabelece uma conexão "socket" entre um navegador da web e um servidor. Em vez de pesquisas longas para obter atualizações, por exemplo, de um aplicativo de placar ao vivo, você pode usar websockets para criar uma conexão persistente entre o cliente e o servidor. Assim, o aplicativo se atualiza automaticamente sempre que novas atualizações estiverem disponíveis.

Isso evita a sobrecarga de enviar uma solicitação HTTP adicional para verificar se há atualizações mais recentes.

Assim, o cliente e o servidor precisam apenas concluir um aperto de mão, e uma conexão persistente pode ser criada diretamente entre os dois, e a transferência de dados bidirecional é realizada.

![Websocket](https://camo.githubusercontent.com/a985b5f6ece41fbd5ebcf5e126ac275cc0aab8f1d92c09696421f4c40e685f8a/68747470733a2f2f696d672d626c6f672e6373646e 696d672e636e2f32303139303130373130353635383936322e706e673f782d6f73732d70726f636573733d696d6167652f77617465726d61726b2c74797 0655f5a6d46755a33706f5a57356e6147567064476b2c736861646f775f31302c746578745f6148523063484d364c7939696247396e4c6d4e7a5a473475 626d56304c325a7662576c755833706f64513d3d2c73697a655f31362c636f6c6f725f4646464646462c745f3730)

O Websocket usa a mesma porta TCP do HTTP, que pode contornar a maioria das restrições de firewall. Por padrão, o protocolo Websocket usa a porta 80; ao executar sobre TLS, a porta 443 é usada por padrão. Seu identificador de protocolo é ws. Se wss for usado para criptografia, o endereço da web do servidor é URL, como:

ws://www.example.com/
wss://www.example.com/

Vantagens do Websocket

  • Menos sobrecarga de controle: após a criação da conexão, quando os dados são trocados entre o servidor e o cliente, o cabeçalho do pacote de dados usado para controle de protocolo é relativamente pequeno
  • Desempenho em tempo real mais forte: Como o protocolo é full-duplex, o servidor pode enviar dados ativamente para o cliente a qualquer momento
  • Manter o estado da conexão: Ao contrário do HTTP, o Websocket precisa primeiro criar uma conexão, o que o torna um protocolo com estado, e então parte da informação do estado pode ser omitida durante a comunicação. A solicitação HTTP pode precisar transportar informações de status em cada solicitação (como autenticação de identidade, etc.)
  • Melhor suporte binário: Websocket define quadros binários, que podem lidar com conteúdo binário mais facilmente do que HTTP
  • Melhor efeito de compactação: em comparação com a compactação HTTP, o Websocket pode usar o contexto do conteúdo anterior com suporte de extensão adequado e pode melhorar significativamente a taxa de compactação ao transferir dados semelhantes.

Exemplo 1: Exemplo de WebSockets do Android

Neste tutorial você aprenderá como usar websockets usando OkHTTP. O url (ws://echo.websocket.org) é usado para configurar websockets.

Passo 1: Instale o Okhttp

Em seu build.gradle no nível do aplicativo, adicione a seguinte instrução de implementação:

implementation 'com.squareup.okhttp3:okhttp:3.6.0'

Etapa 2: adicionar permissão de Internet

No manifesto do Android, adicione a permissão de internet da seguinte forma:

    <uses-permission android:name="android.permission.INTERNET"/>

Etapa 3: layout do design

Crie um layout com uma exibição de texto e um botão. O textview mostrará o resultado do servidor. O botão, por outro lado, iniciará a conexão:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/buttonSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="SEND"
android:layout_marginTop="60dp"
android:textSize="20sp"/>
<TextView
android:id="@+id/textResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/buttonSend"
android:layout_centerHorizontal="true"
android:textSize="18sp"
android:layout_marginTop="40dp"/>
</RelativeLayout>

Etapa 4: Escreva o código

Comece criando um método auxiliar para imprimir o resultado do servidor em uma exibição de texto. Isso é feito no thread da IU:

    private void print(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textResult.setText(textResult.getText().toString() + "\n" + message);
}
});
}

Crie um EchoWebListener como uma classe interna. Esta classe estenderá o WebSocketListener:

    private final class EchoWebSocketListener extends WebSocketListener {
private static final int CLOSE_STATUS = 1000;
@Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("What's up ?");
webSocket.send(ByteString.decodeHex("abcd"));
webSocket.close(CLOSE_STATUS, "Socket Closed !!");
}
@Override
public void onMessage(WebSocket webSocket, String message) {
print("Receive Message: " + message);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
print("Receive Bytes : " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(CLOSE_STATUS, null);
print("Closing Socket : " + code + " / " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable throwable, Response response) {
print("Error : " + throwable.getMessage());
}
}

O método a seguir iniciará a conexão do websocket. A classe OkHTTP Request é instanciada e a url é passada para o método url(). Em seguida, instancie um EchoWebSocketListener e passe o objeto Request e a instância EchoWebListener para o método newWebSocket().

Aqui está o método completo:

    private void start() {
Request request = new Request.Builder().url("ws://echo.websocket.org").build();
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket webSocket = mClient.newWebSocket(request, listener);
mClient.dispatcher().executorService().shutdown();
}

Aqui está o código completo:

MainActivity.java


import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

public class MainActivity extends AppCompatActivity {

private Button buttonSend;
private TextView textResult;
private OkHttpClient mClient;

private final class EchoWebSocketListener extends WebSocketListener {
private static final int CLOSE_STATUS = 1000;
@Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("What's up ?");
webSocket.send(ByteString.decodeHex("abcd"));
webSocket.close(CLOSE_STATUS, "Socket Closed !!");
}
@Override
public void onMessage(WebSocket webSocket, String message) {
print("Receive Message: " + message);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
print("Receive Bytes : " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(CLOSE_STATUS, null);
print("Closing Socket : " + code + " / " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable throwable, Response response) {
print("Error : " + throwable.getMessage());
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonSend = (Button) findViewById(R.id.buttonSend);
textResult = (TextView) findViewById(R.id.textResult);
mClient = new OkHttpClient();
buttonSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
start();
}
});
}
private void start() {
Request request = new Request.Builder().url("ws://echo.websocket.org").build();
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket webSocket = mClient.newWebSocket(request, listener);
mClient.dispatcher().executorService().shutdown();
}
private void print(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textResult.setText(textResult.getText().toString() + "\n" + message);
}
});
}
}

Referência

Abaixo está o link para download.

Não.Link
1.Download código
2.Siga autor do código

Exemplo 2: Exemplo de Websocket Android Kotlin com Okhttp

Aqui está outro exemplo de websocket android, mas desta vez escrito em Kotlin. Ele ainda usa OkHttp como a biblioteca de rede.

Passo 1: Criar Projeto

Comece criando um projeto Android Studio vazio.

Passo 2: Dependências

Vamos instalar duas bibliotecas OkHttp:

    implementation 'com.squareup.okhttp3:okhttp:3.12.6'
implementation 'com.squareup.okhttp3:mockwebserver:3.12.1'

Adicione aqueles em seu app/build.gradle e sincronize.

Etapa 3: layout do design

No layout do seu MainActivity's adicione vários botões e um texto de edição como mostrado abaixo:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<Button
android:id="@+id/connectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android : text = " Connect "
app:layout_constraintRight_toLeftOf="@+id/clientSendBtn"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/clientSendBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android : text = " Send from the client "
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/closeConnectionBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android : text = " Client is closed "
app:layout_constraintLeft_toRightOf="@+id/clientSendBtn"
app:layout_constraintTop_toTopOf="parent" />

<EditText
android:id="@+id/contentEt"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:background="@color/colorGray"
android:enabled="false"
android:gravity="top"
android:padding="5dp"
android:textColor="@color/colorWhite"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/clientSendBtn"
app:layout_constraintVertical_weight="1" />

</androidx.constraintlayout.widget.ConstraintLayout>

Etapa 4: criar um ouvinte de mensagem

Esta será uma interface com vários callbacks gerados dependendo do status da conexão, por exemplo quando conectado com sucesso, fechado, com falha etc:

MessageListener.kt

interface MessageListener {
fun onConnectSuccess () // successfully connected
fun onConnectFailed () // connection failed
fun onClose () // close
fun onMessage(text: String?)
}

Passo 5: Crie um Websocket Manager

Crie um WebSocketManager.kt, em seguida, comece adicionando as seguintes importações:

import  android.util.Log
import okhttp3.*
import okio.ByteString
import java.util.concurrent.TimeUnit

Crie uma classe de objeto WebSocketManager com os seguintes campos privados;

object  WebSocketManager {
private val TAG = WebSocketManager::class.java.simpleName
private const val MAX_NUM = 5 // Maximum number of reconnections
private const val MILLIS = 5000 // Reconnection interval, milliseconds
private lateinit var client: OkHttpClient
private lateinit var request: Request
private lateinit var messageListener: MessageListener
private lateinit var mWebSocket: WebSocket
private var isConnect = false
private var connectNum = 0

Em seguida, na função init, passe a url, bem como o MessageListener. Você inicializa o cliente OkHTTP aqui:

    fun init(url: String, _messageListener: MessageListener) {
client = OkHttpClient.Builder()
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
request = Request.Builder().url(url).build()
messageListener = _messageListener
}

Agora crie uma função para conectar:

    fun connect() {
if (isConnect()) {
Log.i(TAG, "web socket connected")
return
}
client.newWebSocket(request, createListener())
}

Crie também uma função para reconectar:

    fun reconnect() {
if (connectNum <= MAX_NUM) {
try {
Thread.sleep(MILLIS.toLong())
connect()
connectNum++
} catch (e: InterruptedException) {
e.printStackTrace ()
}
} else {
Log.i(
TAG,
"reconnect over $MAX_NUM,please check url or network"
)
}
}

Também teremos funções para enviar uma mensagem:

    fun sendMessage(text: String): Boolean {
return if (!isConnect()) false else mWebSocket.send(text)
}
fun sendMessage(byteString: ByteString): Boolean {
return if (!isConnect()) false else mWebSocket.send(byteString)
}

E uma função para fechar a conexão:

    fun close() {
if (isConnect()) {
mWebSocket.cancel()
mWebSocket.close( 1001 , "The client actively closes the connection " )
}
}

Aqui está o código completo:

WebSocketManager.kt

import  android.util.Log
import okhttp3.*
import okio.ByteString
import java.util.concurrent.TimeUnit

object WebSocketManager {
private val TAG = WebSocketManager::class.java.simpleName
private const val MAX_NUM = 5 // Maximum number of reconnections
private const val MILLIS = 5000 // Reconnection interval, milliseconds
private lateinit var client: OkHttpClient
private lateinit var request: Request
private lateinit var messageListener: MessageListener
private lateinit var mWebSocket: WebSocket
private var isConnect = false
private var connectNum = 0
fun init(url: String, _messageListener: MessageListener) {
client = OkHttpClient.Builder()
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
request = Request.Builder().url(url).build()
messageListener = _messageListener
}

/**
* connect
*/
fun connect() {
if (isConnect()) {
Log.i(TAG, "web socket connected")
return
}
client.newWebSocket(request, createListener())
}

/**
* Reconnection
*/
fun reconnect() {
if (connectNum <= MAX_NUM) {
try {
Thread.sleep(MILLIS.toLong())
connect()
connectNum++
} catch (e: InterruptedException) {
e.printStackTrace ()
}
} else {
Log.i(
TAG,
"reconnect over $MAX_NUM,please check url or network"
)
}
}

/**
* Whether to connect
*/
fun isConnect(): Boolean {
return isConnect
}

/**
* send messages
*
* @param text string
* @return boolean
*/
fun sendMessage(text: String): Boolean {
return if (!isConnect()) false else mWebSocket.send(text)
}

/**
* send messages
*
* @param byteString character set
* @return boolean
*/
fun sendMessage(byteString: ByteString): Boolean {
return if (!isConnect()) false else mWebSocket.send(byteString)
}

/**
* Close connection
*/
fun close() {
if (isConnect()) {
mWebSocket.cancel()
mWebSocket.close( 1001 , "The client actively closes the connection " )
}
}

private fun createListener(): WebSocketListener {
return object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response
) {
super.onOpen(webSocket, response)
Log.d(TAG, "open:$response")
mWebSocket = webSocket
isConnect = response.code() == 101
if (!isConnect) {
reconnect()
} else {
Log.i(TAG, "connect success.")
messageListener.onConnectSuccess()
}
}

override fun onMessage(webSocket: WebSocket, text: String) {
super.onMessage(webSocket, text)
messageListener.onMessage(text)
}

override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
super.onMessage(webSocket, bytes)
messageListener.onMessage(bytes.base64())
}

override fun onClosing(
webSocket: WebSocket,
code: Int,
reason: String
) {
super.onClosing(webSocket, code, reason)
isConnect = false
messageListener.onClose()
}

override fun onClosed(
webSocket: WebSocket,
code: Int,
reason: String
) {
super.onClosed(webSocket, code, reason)
isConnect = false
messageListener.onClose()
}

override fun onFailure(
webSocket: WebSocket,
t: Throwable,
response: Response?
) {
super.onFailure(webSocket, t, response)
if (response != null) {
Log.i(
TAG,
"connect failed:" + response.message()
)
}
Log.i(
TAG,
"connect failed throwable:" + t.message
)
isConnect = false
messageListener.onConnectFailed()
reconnect()
}
}
}
}

Etapa 6: Escreva o código MainActivity

Aqui está o código completo para MainActivity:

MainActivity.kt

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity(), MessageListener {
private val serverUrl = "ws://192.168.18.145:8086/socketServer/abc"
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate (savedInstanceState)
setContentView(R.layout.activity_main)
WebSocketManager.init(serverUrl, this)
connectBtn.setOnClickListener {
thread {
kotlin.run {
WebSocketManager.connect()
}
}
}
clientSendBtn.setOnClickListener {
if ( WebSocketManager .sendMessage( " Client send " )) {
addText( " Send from the client \n " )
}
}
closeConnectionBtn.setOnClickListener {
WebSocketManager.close()
}
}

override fun onConnectSuccess() {
addText( " Connected successfully \n " )
}

override fun onConnectFailed() {
addText( " Connection failed \n " )
}

override fun onClose() {
addText( " Closed successfully \n " )
}

override fun onMessage(text: String?) {
addText( " Receive message: $text \n " )
}

private fun addText(text: String?) {
runOnUiThread {
contentEt.text.append(text)
}
}

override fun onDestroy() {
super .onDestroy ()
WebSocketManager.close()
}
}

Correr

Copie o código ou baixe no link abaixo, construa e execute.

Referência

Aqui estão os links de referência:

NúmeroLink
1.Download Exemplo
2.Siga autor do código