Programmation Java WebSocket avec Android et Spring Boot
Published: 2024-01-17 02:56:07

Le [protocole WebSocket](https://www.pubnub.com/blog/websockets-vs-rest-api-understanding-the-difference/) fournit une connexion permanente entre un client et un serveur pour une communication bidirectionnelle. Il est idéal pour les applications qui nécessitent une connexion en temps réel, telles que les [jeux multijoueurs](https://www.pubnub.com/industry/gaming/), les [applications de l'internet des objets](https://www.pubnub.com/industry/iot-and-connected-devices/) et les [applications de chat](https://www.pubnub.com/use-case/in-app-chat/). Le cas d'utilisation de ce tutoriel est une application de chat, un exemple classique de communication en temps réel. Dans ce tutoriel, nous allons mettre en place un simple client Android qui se connectera à un serveur WebSocket en utilisant [Spring Boot](https://spring.io/projects/spring-boot).

![](/cdn/3prze68gbwl1/archivedasset-17su7vkk2ohxnb3/97e1b1e1ab1a6f2f7de233157b9e0c31/WebSockets-Diagram.png)

Client Java WebSocket
---------------------

Pour le client Android, nous allons créer une application de démonstration simple qui contient quatre boutons d'images d'animaux mignons. Avant de plonger dans l'implémentation Java, il convient de noter que Kotlin est devenu un choix populaire pour le développement Android. Pour commencer, initialisez un nouveau projet sur [Android Studio](https://developer.android.com/studio), avec une activité de base, appelée **JavaWebSocketClient**. Nous allons utiliser une bibliothèque client WebSocket légère pour l'application, qui peut être trouvée dans ce [repo](https://github.com/gusavila92/java-android-websocket-client) GitHub. Afin d'utiliser cette bibliothèque, nous devons l'ajouter au fichier **build.gradle** dans le répertoire de l'application. Ajoutez les éléments suivants aux dépendances et synchronisez le projet :

```js
dependencies { 
    // Add this
    implementation 'tech.gusavila92:java-android-websocket-client:<latest-version>'    
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    ...
}
```

Assurez-vous d'inclure l'autorisation d'accès à Internet dans le fichier manifest :

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

### Connecter le client au serveur

Allez dans **MainActivity.java**, importez les paquets suivants et configurez **onCreate()**:

```js
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.net.URI;
import java.net.URISyntaxException;
import tech.gusavila92.websocketclient.WebSocketClient;

public class MainActivity extends AppCompatActivity {
  private WebSocketClient webSocketClient;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.animal_sounds);
    createWebSocketClient();
  }
}
```

Ensuite, créez une nouvelle méthode **createWebSocketClient()**:

```js
private void createWebSocketClient() {
    URI uri;
    try {
      // Connect to local host
      uri = new URI("ws://10.0.2.2:8080/websocket");
    }
    catch (URISyntaxException e) {
      e.printStackTrace();
      return;
    }

    webSocketClient = new WebSocketClient(uri) {
      @Override
      public void onOpen() {
        Log.i("WebSocket", "Session is starting");
        webSocketClient.send("Hello World!");
      }

      @Override
      public void onTextReceived(String s) {
        Log.i("WebSocket", "Message received");
        final String message = s;
        runOnUiThread(new Runnable() {
          @Override
          public void run() {
            try{
              TextView textView = findViewById(R.id.animalSound);
              textView.setText(message);
            } catch (Exception e){
                e.printStackTrace();
            }
          }
        });
      }

      @Override
      public void onBinaryReceived(byte[] data) {
      }

      @Override
      public void onPingReceived(byte[] data) {
      }

      @Override
      public void onPongReceived(byte[] data) {
      }

      @Override
      public void onException(Exception e) {
        Log.e("WebSocket", e.getMessage());
      }

      @Override
      public void onCloseReceived() {
        Log.i("WebSocket", "Closed ");
      }
    };

    webSocketClient.setConnectTimeout(10000);
    webSocketClient.setReadTimeout(60000);
    webSocketClient.enableAutomaticReconnection(5000);
    webSocketClient.connect();
  }
```

Cela peut sembler beaucoup, mais en réalité, nous faisons quatre choses essentielles dans cette méthode :

1.  Démarrer une nouvelle connexion WebSocket à l'hôte local "ws://10.0.2.2:8080/websocket".
    
2.  Envoi d'un message au serveur une fois la connexion ouverte.
    
3.  Affichage des messages envoyés par le serveur sur l'application.
    
4.  Définir les délais d'attente et la reconnexion automatique.
    

Maintenant que nous avons connecté le client au serveur, configurons la méthode pour envoyer des messages au serveur.

### Envoyer des messages au serveur

Dans **MainActivity.java**, ajoutez ce qui suit à **sendMessage()**:

```js
public void sendMessage(View view) {
   Log.i("WebSocket", "Button was clicked");

   // Send button id string to WebSocket Server
   switch(view.getId()){
     case(R.id.dogButton):
       webSocketClient.send("1");
       break;

     case(R.id.catButton):
       webSocketClient.send("2");
       break;

     case(R.id.pigButton):
       webSocketClient.send("3");
       break;

     case(R.id.foxButton):
       webSocketClient.send("4");
       break;
   }
 }
```

Lorsqu'un bouton est pressé, l'_identifiant du bouton_ est envoyé au serveur. Cette méthode est appelée à partir du fichier **animal\_sounds.xml**, que vous pouvez obtenir à partir de mon [Repo Java WebSocket Programming](https://github.com/ocastroa/java-websocket-demo/blob/master/JavaWebSocketClient/app/src/main/res/layout/animal_sounds.xml). Assurez-vous de modifier le fichier [**strings.xml**](https://github.com/ocastroa/java-websocket-demo/blob/master/JavaWebSocketClient/app/src/main/res/values/strings.xml) dans le répertoire **values** afin de ne pas avoir d'erreurs dans le fichier XML.

La dernière chose à faire côté client est d'ajouter les images des animaux dans le répertoire [**drawable**](https://github.com/ocastroa/java-websocket-demo/tree/master/JavaWebSocketClient/app/src/main/res/drawable). _Les images sont créées par_ [_Freepik_](https://www.flaticon.com/authors/freepik) _à partir de_ _www.flaticon.com._

Lancez l'application Android dans votre émulateur :

![](/cdn/3prze68gbwl1/asset-17suaysk1qa1k1d/c3da7192b47d3ca4e89d9012ad20fa62/clicking_buttons_client.gif?w=700&h=550)

Rien ne se passe pour l'instant car le serveur n'est pas configuré. Faisons-le tout de suite !

Serveur Spring Boot WebSocket
-----------------------------

Pour notre serveur, nous utiliserons Spring Boot qui permet de créer facilement des applications [Spring](https://spring.io/projects/spring-framework) de niveau production avec un minimum de configuration. Pour démarrer rapidement notre projet, nous utiliserons [Spring Initializr](https://start.spring.io/). Nous allons générer un projet [Gradle](https://gradle.org/), mais vous pouvez également générer un projet [Maven](https://maven.apache.org/) si vous préférez. Configurez l'Initializr comme dans la capture d'écran ci-dessous et assurez-vous d'ajouter WebSocket comme dépendance :

![](/cdn/3prze68gbwl1/asset-17suaysk1qa1k1e/3a66f9b5a0a6dcdee6f40f92a45d59fc/spring_initializr-1.png)

Générez le projet pour télécharger un fichier zip. Une fois le fichier décompressé, allez dans le répertoire **src** et continuez à cliquer sur les sous-répertoires jusqu'à ce que vous arriviez au fichier **JavaWebSocketServerApplication.java**.

```js
package com.example.javawebsocketserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JavaWebSocketServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(JavawebsocketserverApplication.class, args);
  }
}
```

Ajoutez deux fichiers au répertoire **: WebSocketHandler.java** et **WebSocketConfiguration.java.**

### Gérer les messages WebSocket

Nous devons gérer les messages entrants qui arrivent sur le serveur. Pour ce faire, dans **WebSocketHandler.java** , héritez de la classe pour implémenter la méthode **handleTextMessage()**. Ajoutez le code suivant au fichier :

```js
package com.server.javawebsocketserver;

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.io.IOException;

public class WebSocketHandler extends AbstractWebSocketHandler {
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
        String msg = String.valueOf(message.getPayload());
        // Send back a unique message depending on the id received from the client
        switch(msg){
            case("1"):
                Log.i("WebSocket", "Dog button was pressed");
                session.sendMessage(new TextMessage("Woooof"));
                break;

            case("2"):
                Log.i("WebSocket", "Cat button was pressed");
                session.sendMessage(new TextMessage("Meooow"));
                break;

            case("3"):
                Log.i("WebSocket", "Pig button was pressed");
                session.sendMessage(new TextMessage("Bork Bork"));
                break;

            case("4"):
                Log.i("WebSocket", "Fox button was pressed");
                session.sendMessage(new TextMessage("Fraka-kaka-kaka"));
                break;

            default:
                Log.i("WebSocket", "Connected to Client");
        }
    }
}
```

Dans la méthode, nous obtenons simplement la valeur de la chaîne de caractères de la charge utile du message et nous effectuons une expression **switch** pour vérifier la valeur du message avec la valeur de chaque cas. Un message unique contenant le son de l'animal est envoyé au client.

### Configurer la gestion des requêtes WebSocket

Dans **WebSocketConfiguration.java**, implémentez l'interface [**WebSocketConfigurer**](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/socket/config/annotation/WebSocketConfigurer.html) et ajoutez le code suivant au fichier :

```js
package com.server.javawebsocketserver;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new WebSocketHandler(), "/websocket");
    }
}
```

Nous avons mis en place la méthode **registerWebSocketHandlers** pour configurer le [WebSocketHandler](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/socket/config/annotation/WebSocketConfigurer.html#addHandler-org.springframework.web.socket.WebSocketHandler-java.lang.String...-) sur le chemin "**/websocket**". C'est tout pour le côté serveur. Maintenant que tout est configuré, démarrons le serveur WebSocket et lançons l'application !

Envoyer des données entre le serveur et le client
-------------------------------------------------

Dans le terminal, allez dans le répertoire racine de votre projet Spring Boot et exécutez la commande suivante pour démarrer le serveur :

```js
gradle bootRun
```

Ensuite, lancez le client Android dans Android Studio et, une fois l'application chargée, cliquez sur l'un des quatre boutons.

![](/cdn/3prze68gbwl1/asset-17suaysk1qa1k1f/6153c8947488b515b3166179789f8562/client_server_screenshot.png)

Jouez avec l'application Android et voyez comment les messages sont envoyés du client au serveur avec les WebSockets !

Mise à jour du client Android pour Pub/Sub
------------------------------------------

Envoyer des données de client à serveur ou de serveur à client n'est pas difficile et peut se faire assez rapidement. Mais que faire si vous voulez envoyer des données de client à client ? Vous ne pouvez pas connecter directement les clients sans mettre en œuvre une logique de routage et de courtier de messages (via `enableSimpleBroker` et en l'enregistrant avec le type `MessageBrokerRegistry` ) sur le serveur.

Plusieurs outils peuvent être utilisés pour rendre cette tâche moins fastidieuse. L'un d'entre eux est [Socket.IO](http://socket.io/), qui établit une connexion bidirectionnelle en temps réel entre les clients. Il s'agit d'un excellent outil open-source, mais nous devons toujours mettre en place un serveur et connecter le client au serveur. Un autre outil consiste à utiliser des sous-protocoles tels que [STOMP](https://en.wikipedia.org/wiki/Streaming_Text_Oriented_Messaging_Protocol) dans Spring Boot pour intégrer des messages STOMP. Ce sous-protocole fonctionne au-dessus de WebSocket et permet de gérer les messages WebSocket. Cependant, vous devez également configurer les points d'extrémité vous-même en utilisant le type `StompEndpointRegistry`, puis ajouter les points d'extrémité à l'aide de la méthode `addEndPoint.` Existe-t-il un moyen plus simple d'envoyer des données de manière sûre et fiable entre des clients sans avoir à configurer manuellement un serveur ? Avec PubNub, c'est possible.

![](/cdn/3prze68gbwl1/asset-17suaysk1qa1k1g/7e74251d4425718e24dd4c587e849ca5/pubsub-1.gif?w=700&h=550)

PubNub fournit l'infrastructure en temps réel pour alimenter n'importe quel appareil qui parle [TCP](https://www.pubnub.com/guides/tcp-ip/). Nous pouvons envoyer des données de client à client, de client à serveur ou de serveur à client en utilisant le [réseau mondial de flux de données de PubNub](https://www.pubnub.com/products/pubnub-platform/) en moins de 100 ms ! Avec PubNub, une connexion permanente est établie entre les appareils connectés au canal, à l'instar des WebSockets. Le plus intéressant est que vous n'avez pas à vous soucier de la mise en place d'un serveur backend et de sa maintenance, car PubNub est [sans serveur](https://www.pubnub.com/blog/everything-you-wanted-to-know-about-serverless-but-were-afraid-to-ask/) et infiniment évolutif.

Pour voir comment PubNub simplifie le processus d'envoi de données de client à client, nous allons modifier l'application Android que nous avons construite précédemment. Mais d'abord, [créez](https://admin.pubnub.com/#/signup) un compte PubNub gratuit pour obtenir vos **clés API Pub/Sub gratuites**.

### Modifier le client Android

Pour différencier l'application mise à jour de l'ancienne, créez un nouveau projet Android appelé **PubNubJavaClient**. Afin d'utiliser [le SDK Android de PubNub](https://www.pubnub.com/docs/sdks/java/android/), mettez à jour le json en ajoutant ce qui suit au fichier build.gradle dans le répertoire de l'application et synchronisez le projet :

```js
dependencies {
    implementation group: 'com.pubnub', name: 'pubnub-gson', version: '6.4.5' // Add this
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    ...
}
```

Inclure les permissions suivantes au fichier manifest :

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

Tout le reste, sauf **MainActivity.java**, est identique. A partir de l'application précédente, ajoutez les fichiers suivants à l'application mise à jour : [**animal\_sounds.xml**](https://github.com/ocastroa/java-websocket-demo/blob/master/JavaWebSocketClient/app/src/main/res/layout/animal_sounds.xml), [**strings.xml**](https://github.com/ocastroa/java-websocket-demo/blob/master/JavaWebSocketClient/app/src/main/res/values/strings.xml) et les images du répertoire [**drawable**](https://github.com/ocastroa/java-websocket-demo/tree/master/JavaWebSocketClient/app/src/main/res/drawable). Une fois que vous avez terminé, allez dans **MainActivity.java** pour ajouter le nouveau code. Importez les paquets suivants et configurez **onCreate()**:

```js
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.pubnub.api.PNConfiguration;
import com.pubnub.api.PubNub;
import com.pubnub.api.callbacks.PNCallback;
import com.pubnub.api.callbacks.SubscribeCallback;
import com.pubnub.api.models.consumer.PNPublishResult;
import com.pubnub.api.models.consumer.PNStatus;
import com.pubnub.api.models.consumer.pubsub.PNMessageResult;
import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity {
  PubNub pubnub;
  TextView textView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.animal_sounds);

    initPubNub(); // Initialize PubNub
  }
```

Faites un appel à **initPubNub()** pour initialiser PubNub :

```js
public void initPubNub(){
  PNConfiguration pnConfiguration = new PNConfiguration();
  pnConfiguration.setPublishKey("ENTER_YOUR_PUB_KEY"); // REPLACE with your pub key
  pnConfiguration.setSubscribeKey("ENTER_YOUR_SUB_KEY"); // REPLACE with your sub key
  pnConfiguration.setSecure(true);
  pubnub = new PubNub(pnConfiguration);

  // Listen to messages that arrive on the channel
  pubnub.addListener(new SubscribeCallback() {
    @Override
    public void status(PubNub pub, PNStatus status) {
    }

    @Override
    public void message(PubNub pub, final PNMessageResult message) {
      // Replace double quotes with a blank space
      final String msg = message.getMessage().toString().replace("\"", ""); 
      textView = findViewById(R.id.animalSound);

      runOnUiThread(new Runnable() {
        @Override
        public void run() {
          try{
            // Display the message on the app
            textView.setText(msg);
          } catch (Exception e){
              System.out.println("Error");
              e.printStackTrace();
          }
        }
      });
    }

    @Override
    public void presence(PubNub pub, PNPresenceEventResult presence) {
    }
  });

  // Subscribe to the global channel
  pubnub.subscribe()
    .channels(Arrays.asList("global_channel"))
    .execute();
}
```

Nous faisons trois choses essentielles dans cette méthode :

1.  Initialiser l'API du client PubNub. Assurez-vous de remplacer "ENTER\_YOUR\_PUB\_KEY" et "ENTER\_YOUR\_SUB\_KEY" par vos clés Pub/Sub.
    
2.  Mettez en place un listener pour être informé des messages qui arrivent sur le canal. Comme nous l'avons fait précédemment, affichez le message sur l'application pour que le client puisse le voir.
    
3.  S'abonner au canal global où les messages seront publiés.
    

Lorsque l'utilisateur appuie sur un bouton, la méthode **sendMessage()** est appelée :

```js
// This method is called when a button is pressed
public void sendMessage(View view) {
  // Get button ID
  switch(view.getId()){
    case(R.id.dogButton):
      publishMessage("Woooof");
      break;

    case(R.id.catButton):
      publishMessage("Meooow");
      break;

    case(R.id.pigButton):
      publishMessage("Bork Bork");
      break;

    case(R.id.foxButton):
      publishMessage("Fraka-kaka-kaka");
      break;
  }
}
```

Cette méthode est similaire à ce que nous avons fait précédemment, sauf que nous publions maintenant le message réel, le son de l'animal, sur le canal global et non sur le serveur. Nous utilisons **publishMessage()** comme fonction d'aide pour publier le message.

```js
public void publishMessage(String animal_sound){
  // Publish message to the global chanel
  pubnub.publish()
    .message(animal_sound)
    .channel("global_channel")
    .async(new PNCallback<PNPublishResult>() {
      @Override
      public void onResponse(PNPublishResult result, PNStatus status) {
        // status.isError() to see if error happened and print status code if error
        if(status.isError()) {
          System.out.println("pub status code: " + status.getStatusCode());
        }
      }
    });
}
```

C'est tout ce dont nous avons besoin pour faire fonctionner l'application !

Envoi de données entre clients
------------------------------

Exécutez l'application Android dans deux émulateurs pour voir les messages apparaître en temps réel.

![](/cdn/3prze68gbwl1/asset-17suaysk1qa1k1h/b19bdcfbe68755a7d419c30f9281286c/client_to_client.gif?w=700&h=550)

Remarque : pour garantir une communication transparente entre les clients, assurez-vous que les deux émulateurs Android possèdent les mêmes clés PubNub et sont abonnés au même canal. Cela est essentiel pour établir une connexion WebSocket réussie pour la communication en temps réel.

Maintenant que vous avez appris à envoyer des données à l'aide de WebSockets en Java, n'oubliez pas d'explorer nos autres ressources.

Enfin, consultez notre documentation pour en savoir plus sur les fonctionnalités supplémentaires offertes par PubNub, telles que les [actions de message](https://www.pubnub.com/docs/chat/sdks/messages/sending-messages), les [objets](https://www.pubnub.com/docs/general/setup/users-and-devices) et les [messages de signal](https://www.pubnub.com/docs/general/basics/send-messages), afin de donner à votre application une longueur d'avance. Consultez nos captures d'écran mises à jour et nos liens de ressources pour une compréhension plus complète.

Avec PubNub, vous pouvez également créer des solutions adaptées à la [géolocalisation](https://www.pubnub.com/solutions/geolocation/), au [bus de messages de périphérie](https://www.pubnub.com/solutions/edge-message-bus/), aux [logiciels d'entreprise](https://www.pubnub.com/solutions/enterprise-software/), aux [jeux](https://www.pubnub.com/solutions/gaming/), à la [santé numérique](https://www.pubnub.com/solutions/digital-health/) et au [commerce électronique](https://www.pubnub.com/solutions/ecommerce/).

Pour commencer, vous pouvez consulter notre [guide de configuration générale](https://www.pubnub.com/docs/general/basics/set-up-your-account), qui vous guidera dans la création de votre compte. Si vous souhaitez apprendre à envoyer et à recevoir des messages, nous avons également des guides pour cela. Consultez nos [guides sur l'envoi](https://www.pubnub.com/docs/general/basics/send-messages) et la [réception de messages](https://www.pubnub.com/docs/general/basics/receive-messages) pour plus d'informations.

Pour des fonctionnalités plus avancées, telles que l'envoi de messages, les accusés de réception et le décompte des messages non lus dans un scénario de chat, vous pouvez vous référer à ces documents : [envoi de messages](https://www.pubnub.com/docs/chat/sdks/messages/sending-messages), [accusés de réception](https://www.pubnub.com/docs/chat/sdks/messages/message-receipts) et [décompte des messages non lus](https://www.pubnub.com/docs/chat/sdks/messages/unread-counts).

Si vous travaillez sur une plateforme Android et que vous souhaitez mettre en œuvre des notifications push, nous avons tout ce qu'il vous faut. Consultez notre [guide Android push](https://www.pubnub.com/docs/general/push/android) et notre [guide send push](https://www.pubnub.com/docs/general/push/send) pour obtenir des instructions détaillées sur la mise en place de notifications push avec firebase et PubNub.

Vous avez des suggestions ou des questions sur le contenu de cet article ? Contactez [devrel@pubnub.com](mailto:devrel@pubnub.com).

Comment PubNub peut-il vous aider ?
===================================

Cet article a été publié à l'origine sur [PubNub.com](https://www.pubnub.com/blog/java-websocket-programming-with-android-and-spring-boot/)

Notre plateforme aide les développeurs à construire, fournir et gérer l'interactivité en temps réel pour les applications web, les applications mobiles et les appareils IoT.

La base de notre plateforme est le réseau de messagerie en temps réel le plus grand et le plus évolutif de l'industrie. Avec plus de 15 points de présence dans le monde, 800 millions d'utilisateurs actifs mensuels et une fiabilité de 99,999 %, vous n'aurez jamais à vous soucier des pannes, des limites de concurrence ou des problèmes de latence causés par les pics de trafic.

Découvrez PubNub
----------------

Découvrez le [Live Tour](https://www.pubnub.com/tour/introduction/) pour comprendre les concepts essentiels de chaque application alimentée par PubNub en moins de 5 minutes.

S'installer
-----------

Créez un [compte PubNub](https://admin.pubnub.com/signup/) pour un accès immédiat et gratuit aux clés PubNub.

Commencer
---------

La [documentation PubNub](https://www.pubnub.com/docs) vous permettra de démarrer, quel que soit votre cas d'utilisation ou votre [SDK](https://www.pubnub.com/docs).