Aller au contenu principal

Exemples de WebSocket Android

WebSocket est un protocole qui permet d'ouvrir une session de communication interactive bidirectionnelle entre le client et le serveur. Il fournit des canaux de communication en duplex intégral sur une seule connexion TCP.

Ce protocole définit une API qui établit une connexion "socket" entre un navigateur Web et un serveur. Plutôt que de longues interrogations pour obtenir des mises à jour, par exemple à partir d'une application de scores en direct, vous pouvez utiliser des websockets pour créer une connexion persistante entre le client et le serveur. Ainsi, l'application se met à jour automatiquement chaque fois que de nouvelles mises à jour sont disponibles.

Cela évite la surcharge liée à l'envoi d'une requête HTTP supplémentaire pour vérifier s'il existe de nouvelles mises à jour.

Ainsi, le client et le serveur n'ont qu'à effectuer une poignée de main, et une connexion persistante peut être créée directement entre les deux, et un transfert de données bidirectionnel peut être effectué.

![Websocket](https://camo.githubusercontent.com/a985b5f6ece41fbd5ebcf5e126ac275cc0aab8f1d92c09696421f4c40e685f8a/68747470733a2f2f696d672d626c6f672e6373646e6 96d672e636e2f32303139303130373130353635383936322e706e673f782d6f73732d70726f636573733d696d6167652f77617465726d61726b2c747970 655f5a6d46755a33706f5a57356e6147567064476b2c736861646f775f31302c746578745f6148523063484d364c7939696247396e4c6d4e7a5a4734756 26d56304c325a7662576c755833706f64513d3d2c73697a655f31362c636f6c6f725f4646464646462c745f3730)

Websocket utilise le même port TCP que HTTP, qui peut contourner la plupart des restrictions de pare-feu. Par défaut, le protocole Websocket utilise le port 80 ; lors de l'exécution au-dessus de TLS, le port 443 est utilisé par défaut. Son identifiant de protocole est ws. Si wss est utilisé pour le chiffrement, l'adresse Web du serveur est une URL, par exemple :

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

Avantages de Websocket

  • Moins de surcharge de contrôle : après la création de la connexion, lorsque des données sont échangées entre le serveur et le client, l'en-tête de paquet de données utilisé pour le contrôle du protocole est relativement petit
  • Performances en temps réel renforcées : étant donné que le protocole est en duplex intégral, le serveur peut envoyer activement des données au client à tout moment
  • Conserver l'état de la connexion : contrairement à HTTP, Websocket doit d'abord créer une connexion, ce qui en fait un protocole avec état, puis une partie des informations d'état peut être omise lors de la communication. La requête HTTP peut devoir contenir des informations d'état dans chaque requête (telles que l'authentification d'identité, etc.)
  • Meilleure prise en charge binaire : Websocket définit des trames binaires, qui peuvent gérer le contenu binaire plus facilement que HTTP
  • Meilleur effet de compression : par rapport à la compression HTTP, Websocket peut utiliser le contexte du contenu précédent avec un support d'extension approprié, et peut améliorer considérablement le taux de compression lors du transfert de données similaires.

Exemple 1 : Exemple de WebSockets Android

Dans ce didacticiel, vous apprendrez à utiliser les websockets à l'aide d'OkHTTP. L'URL (ws://echo.websocket.org) est utilisée pour configurer les websockets.

Étape 1 : Installez Okhttp

Dans votre build.gradle au niveau de l'application, ajoutez la déclaration d'implémentation suivante :

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

### Étape 2 : Ajouter une autorisation Internet

Dans votre manifeste Android, ajoutez l'autorisation Internet comme suit :

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

Étape 3 : Conception de la mise en page

Créez une mise en page avec une vue de texte et un bouton. La vue textuelle affichera le résultat du serveur. Le bouton d'autre part initiera la connexion :

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>

Étape 4 : Écrire le code

Commencez par créer une méthode d'assistance pour imprimer le résultat du serveur sur une vue de texte. Cela se fait sur le thread de l'interface utilisateur :

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

Créez un EchoWebListener en tant que classe interne. Cette classe étendra le 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());
}
}

La méthode suivante lancera la connexion websocket. La classe OkHTTP Request est instanciée et l'url est passée à la méthode url(). Instanciez ensuite un EchoWebSocketListener et transmettez à la fois l'objet Request et l'instance EchoWebListener à la méthode newWebSocket().

Voici la méthode complète :

    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();
}

Voici le code complet :

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);
}
});
}
}

Référence

Ci-dessous le lien de téléchargement.

NonLien
1.[Télécharger] (https://github.com/sayanmanna/WebSocketOkhttp/archive/refs/heads/master.zip) code
2.Suivre auteur du code

Exemple 2 : Exemple de Websocket Android Kotlin avec Okhttp

Voici un autre exemple de websocket Android mais cette fois-ci écrit en Kotlin. Il utilise toujours OkHttp comme bibliothèque réseau.

### Étape 1 : Créer un projet

Commencez par créer un projet Android Studio vide.

Étape 2 : Dépendances

Nous allons installer deux bibliothèques OkHttp :

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

Ajoutez-les dans votre app/build.gradle et synchronisez.

Étape 3 : Conception de la mise en page

Dans la mise en page de votre "MainActivity", ajoutez plusieurs boutons et un texte d'édition comme indiqué ci-dessous :

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>

Étape 4 : Créer un écouteur de message

Il s'agira d'une interface avec plusieurs rappels déclenchés en fonction de l'état de la connexion, par exemple en cas de connexion réussie, de fermeture, d'échec, etc. :

MessageListener.kt

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

Étape 5 : Créer un gestionnaire de Websocket

Créer un WebSocketManager.kt puis commencez par ajouter les importations suivantes :

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

Créez une classe d'objets WebSocketManager avec les champs privés suivants ;

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

Puis la fonction init, passez l'url ainsi que le MessageListener. Vous initialisez le client OkHTTP ici :

    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
}

Créez maintenant une fonction pour vous connecter :

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

Créez également une fonction pour vous reconnecter :

    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"
)
}
}

Nous aurons également des fonctions pour envoyer un message :

    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)
}

Et une fonction pour fermer la connexion :

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

Voici le code complet :

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()
}
}
}
}

Étape 6 : Écrivez le code MainActivity

Voici le code complet de 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()
}
}

Courir

Copiez le code ou téléchargez-le dans le lien ci-dessous, créez et exécutez.

Référence

Voici les liens de référence :

NuméroLien
1.Télécharger Exemple
2.Suivre auteur du code