Programmation Java WebSocket avec Android et Spring Boot

PubNub Developer Relations - Jan 17 - - Dev Community

Le protocole WebSocket 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, les applications de l'internet des objets et les applications de 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.

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, 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 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 :

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

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

<uses-permission android:name="android.permission.INTERNET" />
Enter fullscreen mode Exit fullscreen mode

Connecter le client au serveur

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

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();
  }
}
Enter fullscreen mode Exit fullscreen mode

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

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();
  }
Enter fullscreen mode Exit fullscreen mode

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

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;
   }
 }
Enter fullscreen mode Exit fullscreen mode

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. Assurez-vous de modifier le fichier 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. Les images sont créées par Freepik à partir de www.flaticon.com.

Lancez l'application Android dans votre émulateur :

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 de niveau production avec un minimum de configuration. Pour démarrer rapidement notre projet, nous utiliserons Spring Initializr. Nous allons générer un projet Gradle, mais vous pouvez également générer un projet Maven 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 :

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.

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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 :

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");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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 et ajoutez le code suivant au fichier :

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

Nous avons mis en place la méthode registerWebSocketHandlers pour configurer le WebSocketHandler 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 :

gradle bootRun
Enter fullscreen mode Exit fullscreen mode

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

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, 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 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.

PubNub fournit l'infrastructure en temps réel pour alimenter n'importe quel appareil qui parle TCP. 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 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 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 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, mettez à jour le json en ajoutant ce qui suit au fichier build.gradle dans le répertoire de l'application et synchronisez le projet :

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

Inclure les permissions suivantes au fichier manifest :

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Enter fullscreen mode Exit fullscreen mode

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, strings.xml et les images du répertoire drawable. Une fois que vous avez terminé, allez dans MainActivity.java pour ajouter le nouveau code. Importez les paquets suivants et configurez onCreate():

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
  }
Enter fullscreen mode Exit fullscreen mode

Faites un appel à initPubNub() pour initialiser PubNub :

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();
}
Enter fullscreen mode Exit fullscreen mode

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 :

// 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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

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());
        }
      }
    });
}
Enter fullscreen mode Exit fullscreen mode

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.

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, les objets et les messages de signal, 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, au bus de messages de périphérie, aux logiciels d'entreprise, aux jeux, à la santé numérique et au commerce électronique.

Pour commencer, vous pouvez consulter notre guide de configuration générale, 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 et la réception de 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, accusés de réception et décompte des messages non lus.

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 et notre guide send push 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.

Comment PubNub peut-il vous aider ?

Cet article a été publié à l'origine sur PubNub.com

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 pour comprendre les concepts essentiels de chaque application alimentée par PubNub en moins de 5 minutes.

S'installer

Créez un compte PubNub pour un accès immédiat et gratuit aux clés PubNub.

Commencer

La documentation PubNub vous permettra de démarrer, quel que soit votre cas d'utilisation ou votre SDK.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .