Programowanie Java WebSocket z Androidem i Spring Boot

PubNub Developer Relations - Jan 17 - - Dev Community

Protokół WebSocket zapewnia zawsze aktywne połączenie między klientem a serwerem w celu dwukierunkowej komunikacji. Jest to świetne rozwiązanie dla aplikacji, które wymagają połączenia w czasie rzeczywistym, takich jak gry wieloosobowe, aplikacje Internetu rzeczy i aplikacje do czatowania. Przypadkiem użycia w tym samouczku jest aplikacja czatu, klasyczny przykład komunikacji w czasie rzeczywistym. W tym samouczku skonfigurujemy prostego klienta Android, który będzie łączył się z serwerem WebSocket przy użyciu Spring Boot.

Klient Java WebSocket

Dla klienta Androida stworzymy prostą aplikację demonstracyjną zawierającą cztery przyciski z obrazkami uroczych zwierzątek. Przed zagłębieniem się w implementację Java warto zauważyć, że Kotlin stał się popularnym wyborem dla rozwoju Androida. Aby rozpocząć, zainicjuj nowy projekt w Android Studio, z aktywnością podstawową o nazwie JavaWebSocketClient. Zamierzamy użyć lekkiej biblioteki klienta WebSocket dla aplikacji, którą można znaleźć w tym repozytorium GitHub. Aby użyć tej biblioteki, musimy dodać ją do pliku build.gradle w katalogu aplikacji. Dodaj następujące elementy do zależności i zsynchronizuj projekt:

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

Upewnij się, że w pliku manifestu znajduje się uprawnienie dostępu do Internetu:

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

Połącz klienta z serwerem

Przejdź do MainActivity.java, zaimportuj następujące pakiety i skonfiguruj 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

Następnie utwórz nową metodę 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

Może to wyglądać na dużo, ale tak naprawdę robimy cztery kluczowe rzeczy w tej metodzie:

  1. Rozpoczęcie nowego połączenia WebSocket do localhost "ws://10.0.2.2:8080/websocket".

  2. Wysyłanie wiadomości do serwera po otwarciu połączenia.

  3. Wyświetlanie wiadomości wysłanych z serwera w aplikacji.

  4. Ustawianie limitów czasu i automatycznego ponownego połączenia.

Teraz, gdy połączyliśmy klienta z serwerem, skonfigurujmy metodę wysyłania wiadomości do serwera.

Wysyłanie wiadomości do serwera

W MainActivity.java dodaj następujące elementy do 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

Po naciśnięciu przycisku identyfikator przycisku jest wysyłany do serwera. Ta metoda jest wywoływana z pliku animal_sounds.xml, który można pobrać z mojego Java WebSocket Programming Repo. Upewnij się, że zmodyfikowałeś plik strings. xml w katalogu values, aby uniknąć błędów w pliku XML.

Ostatnią rzeczą do zrobienia po stronie klienta jest dodanie obrazów zwierząt do katalogu drawable. Obrazy są tworzone przez Freepik z www.flaticon.com.

Uruchom aplikację na Androida w emulatorze:

W tej chwili nic się nie dzieje, ponieważ serwer nie jest skonfigurowany. Zróbmy to teraz!

Spring Boot WebSocket Server

Dla naszego serwera użyjemy Spring Boot, który ułatwia tworzenie aplikacji Spring klasy produkcyjnej przy minimalnych konfiguracjach. Aby szybko uruchomić nasz projekt, użyjemy Spring Initializr. Wygenerujemy projekt Gradle, ale jeśli wolisz, możesz również wygenerować projekt Maven. Skonfiguruj Initializr jak na poniższym zrzucie ekranu i upewnij się, że dodałeś WebSocket jako zależność:

Wygeneruj projekt, aby pobrać plik zip. Po rozpakowaniu pliku przejdź do katalogu src i klikaj podkatalogi, aż dojdziesz do pliku 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

Dodaj dwa pliki do katalogu WebSocketHandler .java i WebSocketConfiguration.java.

Obsługa komunikatów WebSocket

Musimy obsłużyć przychodzące wiadomości, które docierają do serwera. Aby to zrobić, w WebSocketHandler .java odziedzicz klasę, aby zaimplementować metodę handleTextMessage(). Dodaj następujący kod do pliku:

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

Wewnątrz metody po prostu pobieramy wartość ciągu ładunku wiadomości i wykonujemy wyrażenie przełączające, aby sprawdzić wartość wiadomości z wartością każdego przypadku. Unikalna wiadomość z dźwiękiem zwierzęcia jest wysyłana do klienta.

Konfiguracja obsługi żądań WebSocket

W WebSocketConfiguration.java zaimplementuj interfejs WebSocketConfigurer i dodaj następujący kod do pliku:

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

Ustawiamy metodę registerWebSocketHandlers, aby skonfigurować WebSocketHandler do ścieżki "/websocket". To wszystko po stronie serwera. Teraz, gdy mamy już wszystko skonfigurowane, uruchommy serwer WebSocket i uruchommy aplikację!

Wysyłanie danych między serwerem a klientem

W terminalu przejdź do katalogu głównego projektu Spring Boot i uruchom następujące polecenie, aby uruchomić serwer:

gradle bootRun
Enter fullscreen mode Exit fullscreen mode

Następnie uruchom klienta Android w Android Studio, a po załadowaniu aplikacji kliknij dowolny z czterech przycisków.

Pobaw się aplikacją na Androida i zobacz, jak wiadomości są wysyłane od klienta do serwera za pomocą WebSockets!

Aktualizacja klienta Android do Pub/Sub

Wysyłanie danych klient-serwer lub serwer-klient nie jest trudne i można to zrobić dość szybko. Ale co jeśli chcesz wysłać dane od klienta do klienta? Nie można bezpośrednio połączyć klientów bez zaimplementowania logiki routingu i brokera wiadomości (poprzez enableSimpleBroker i zarejestrowanie go w typie MessageBrokerRegistry ) na serwerze.

Istnieje kilka narzędzi, których możemy użyć, aby uczynić to zadanie mniej czasochłonnym. Jednym z takich narzędzi jest Socket.IO, które ustanawia dwukierunkowe połączenie między klientami w czasie rzeczywistym. Jest to świetne narzędzie open-source, ale nadal musimy skonfigurować serwer i połączyć klienta z serwerem. Innym takim narzędziem jest użycie podprotokołów, takich jak STOMP w Spring Boot, aby osadzić wiadomości STOMP. Ten podprotokół działa na szczycie WebSocket i umożliwia obsługę wiadomości WebSocket. Jednak trzeba również samodzielnie skonfigurować punkty końcowe za pomocą typu StompEndpointRegistry, a następnie dodać punkty końcowe za pomocą metody addEndPoint. Czy istnieje łatwiejszy sposób na bezpieczne i niezawodne przesyłanie danych między klientami bez ręcznego konfigurowania serwera? Dzięki PubNub jest to możliwe.

PubNub zapewnia infrastrukturę czasu rzeczywistego do zasilania dowolnego urządzenia obsługującego protokół TCP. Możemy przesyłać strumieniowo dane od klienta do klienta, od klienta do serwera lub od serwera do klienta za pomocą globalnej sieci strumieni danych PubNub w czasie poniżej 100 ms! Dzięki PubNub, zawsze aktywne połączenie jest nawiązywane między urządzeniami podłączonymi do kanału, podobnie jak w przypadku WebSockets. Najlepsze jest to, że nie musisz martwić się o konfigurację serwera zaplecza i utrzymanie serwera, ponieważ PubNub jest bezserwerowy i nieskończenie skalowalny.

Aby zobaczyć, jak PubNub upraszcza proces wysyłania danych od klienta do klienta, zmodyfikujemy aplikację na Androida, którą zbudowaliśmy wcześniej. Najpierw jednak zarejestruj darmowe konto PubNub, aby otrzymać bezpłatne klucze Pub/Sub API.

Modyfikacja klienta Android

Aby odróżnić zaktualizowaną aplikację od starej, utwórz nowy projekt na Androida o nazwie PubNubJavaClient. Aby korzystać z Android SDK PubNub, zaktualizuj json, dodając następujące elementy do pliku build.gradle w katalogu aplikacji i zsynchronizuj projekt:

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

Dołącz następujące uprawnienia do pliku manifestu:

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

Wszystko inne, z wyjątkiem MainActivity.java, jest takie samo. Z poprzedniej aplikacji dodaj następujące pliki do zaktualizowanej aplikacji: animal_sounds.xml, strings.xml i obrazy z katalogu drawable. Po zakończeniu tych czynności przejdź do MainActivity. java, aby dodać nowy kod. Zaimportuj następujące pakiety i skonfiguruj funkcję 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

Wykonaj wywołanie initPubNub (), aby zainicjować 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

W tej metodzie wykonujemy trzy kluczowe czynności:

  1. Inicjalizujemy API klienta PubNub. Upewnij się, że zastąpiłeś "ENTER_YOUR_PUB_KEY" i "ENTER_YOUR_SUB_KEY" swoimi kluczami Pub/Sub.

  2. Skonfiguruj słuchacza, aby otrzymywać powiadomienia o wiadomościach przychodzących na kanał. Podobnie jak wcześniej, wyświetl wiadomość w aplikacji, aby klient mógł ją zobaczyć.

  3. Subskrybuj kanał globalny, na którym będą publikowane wiadomości.

Gdy użytkownik naciśnie przycisk, wywoływana jest metoda sendMessage( ):

// 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

Ta metoda jest podobna do tego, co zrobiliśmy wcześniej, z wyjątkiem tego, że teraz publikujemy rzeczywistą wiadomość, dźwięk zwierzęcia, na kanale globalnym, a nie na serwerze. Używamy publishMessage () jako funkcji pomocniczej do opublikowania wiadomości.

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

To wszystko, czego potrzebujemy, aby uruchomić aplikację!

Wysyłanie danych między klientami

Uruchom aplikację na Androida w dwóch emulatorach, aby zobaczyć, jak wiadomości pojawiają się w czasie rzeczywistym.

Uwaga: Aby zapewnić płynną komunikację między klientami, upewnij się, że oba emulatory Androida mają te same klucze PubNub i są subskrybowane na tym samym kanale. Ma to kluczowe znaczenie dla ustanowienia udanego połączenia WebSocket do komunikacji w czasie rzeczywistym.

Teraz, gdy nauczyłeś się wysyłać dane za pomocą WebSockets w Javie, nie zapomnij zapoznać się z naszymi innymi zasobami.

Na koniec zapoznaj się z naszą dokumentacją, aby dowiedzieć się o dodatkowych funkcjach oferowanych przez PubNub, takich jak Message Actions, Objects i Signal, aby zapewnić swojej aplikacji solidną przewagę. Sprawdź nasze zaktualizowane zrzuty ekranu i linki do zasobów, aby uzyskać bardziej kompleksowe zrozumienie.

Dzięki PubNub możesz także tworzyć rozwiązania dostosowane do geolokalizacji, szyny komunikatów brzegowych, oprogramowania dla przedsiębiorstw, gier, cyfrowego zdrowia i handlu elektronicznego.

Aby rozpocząć, warto zapoznać się z naszym ogólnym przewodnikiem konfiguracji, który przeprowadzi Cię przez proces zakładania konta. Jeśli chcesz dowiedzieć się, jak wysyłać i odbierać wiadomości, mamy również przewodniki na ten temat. Więcej informacji można znaleźć w naszych przewodnikach wysyłania i odbierania wiadomości.

Bardziej zaawansowane funkcje, takie jak wysyłanie wiadomości, potwierdzenia wiadomości i liczba nieprzeczytanych wiadomości w scenariuszu czatu, można znaleźć w tych dokumentach: wysyłanie wiadomości, potwierdzenia wiadomości i liczba nieprzeczytanych wiadomości.

Jeśli pracujesz na platformie Android i chcesz zaimplementować powiadomienia push, mamy wszystko pod kontrolą. Odwiedź nasz przewodnik Android push i przewodnik send push, aby uzyskać szczegółowe instrukcje dotyczące konfigurowania powiadomień push za pomocą Firebase i PubNub.

Masz sugestie lub pytania dotyczące treści tego wpisu? Skontaktuj się z nami pod adresem devrel@pubnub.com.

Jak PubNub może ci pomóc?

Ten artykuł został pierwotnie opublikowany na PubNub .com

Nasza platforma pomaga programistom tworzyć, dostarczać i zarządzać interaktywnością w czasie rzeczywistym dla aplikacji internetowych, aplikacji mobilnych i urządzeń IoT.

Podstawą naszej platformy jest największa w branży i najbardziej skalowalna sieć komunikacyjna w czasie rzeczywistym. Dzięki ponad 15 punktom obecności na całym świecie obsługującym 800 milionów aktywnych użytkowników miesięcznie i niezawodności na poziomie 99,999%, nigdy nie będziesz musiał martwić się o przestoje, limity współbieżności lub jakiekolwiek opóźnienia spowodowane skokami ruchu.

Poznaj PubNub

Sprawdź Live Tour, aby zrozumieć podstawowe koncepcje każdej aplikacji opartej na PubNub w mniej niż 5 minut.

Rozpocznij konfigurację

Załóż konto PubNub, aby uzyskać natychmiastowy i bezpłatny dostęp do kluczy PubNub.

Rozpocznij

Dokumenty PubNub pozwolą Ci rozpocząć pracę, niezależnie od przypadku użycia lub zestawu SDK.

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