Das WebSocket-Protokoll bietet eine ständig aktive Verbindung zwischen einem Client und einem Server für bidirektionale Kommunikation. Dies ist ideal für Anwendungen, die eine Echtzeit-Verbindung erfordern, wie z. B. Multiplayer-Spiele, Internet-of-Things-Anwendungen und Chat-Apps. Der Anwendungsfall für dieses Tutorial ist eine Chat-Anwendung, ein klassisches Beispiel für Echtzeitkommunikation. In diesem Tutorial werden wir einen einfachen Android-Client einrichten, der sich mit Hilfe von Spring Boot mit einem WebSocket-Server verbinden wird.
Java WebSocket-Client
Für den Android-Client werden wir eine einfache Demo-Applikation erstellen, die vier Bildschaltflächen mit niedlichen Tieren enthält. Bevor wir in die Java-Implementierung eintauchen, ist es erwähnenswert, dass Kotlin eine beliebte Wahl für die Android-Entwicklung geworden ist. Um zu beginnen, initialisieren Sie ein neues Projekt in Android Studio mit einer Basic Activity namens JavaWebSocketClient. Wir werden eine leichtgewichtige WebSocket-Client-Bibliothek für die App verwenden, die in diesem GitHub Repo zu finden ist. Um diese Bibliothek zu verwenden, müssen wir sie zur build.gradle-Datei im App-Verzeichnis hinzufügen. Fügen Sie Folgendes zu den Abhängigkeiten hinzu und synchronisieren Sie das Projekt:
dependencies {
// Add this
implementation 'tech.gusavila92:java-android-websocket-client:<latest-version>'
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
}
Stellen Sie sicher, dass die Internet-Zugriffsberechtigung in der Manifestdatei enthalten ist:
<uses-permission android:name="android.permission.INTERNET" />
Verbinden Sie den Client mit dem Server
Gehen Sie zu MainActivity.java, importieren Sie die folgenden Pakete und richten Sie onCreate() ein:
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();
}
}
Als nächstes erstellen Sie eine neue Methode 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();
}
Das sieht vielleicht nach viel aus, aber in Wirklichkeit erledigen wir in dieser Methode vier wichtige Dinge:
Starten einer neuen WebSocket-Verbindung zum lokalen Host "ws://10.0.2.2:8080/websocket".
Senden einer Nachricht an den Server, sobald eine Verbindung geöffnet ist.
Anzeige der vom Server gesendeten Nachrichten in der App.
Einstellen von Zeitüberschreitungen und automatischer Wiederherstellung der Verbindung.
Nachdem wir nun den Client mit dem Server verbunden haben, wollen wir die Methode zum Senden von Nachrichten an den Server einrichten.
Nachrichten an den Server senden
Fügen Sie in MainActivity.java folgendes zu sendMessage() hinzu:
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;
}
}
Wenn ein Button gedrückt wird, wird die Button-ID an den Server gesendet. Diese Methode wird aus der Datei animal_sounds.xml aufgerufen, die Sie aus meinem Java WebSocket Programming Repo beziehen können. Vergewissern Sie sich, dass Sie die Datei strings.xml unter dem Verzeichnis values ändern, damit Sie keine Fehler in der XML-Datei erhalten.
Das letzte, was auf der Client-Seite zu tun ist, ist das Hinzufügen der Bilder für die Tiere in das drawable-Verzeichnis. Die Bilder werden von Freepik von www.flaticon.com erstellt .
Starten Sie die Android-App in Ihrem Emulator:
Im Moment passiert nichts, weil der Server nicht eingerichtet ist. Lassen Sie uns das jetzt tun!
Spring Boot WebSocket-Server
Für unseren Server werden wir Spring Boot verwenden, das die Erstellung produktionsreifer Spring-Anwendungen mit minimalen Konfigurationen erleichtert. Um unser Projekt schnell zu booten, werden wir Spring Initializr verwenden. Wir werden ein Gradle-Projekt erzeugen, aber Sie können auch ein Maven-Projekt erzeugen, wenn Sie dies bevorzugen. Konfigurieren Sie Initializr wie im Screenshot unten und stellen Sie sicher, dass Sie WebSocket als eine Abhängigkeit hinzufügen:
Erzeugen Sie das Projekt, um eine Zip-Datei herunterzuladen. Sobald Sie die Datei entpackt haben, gehen Sie in das src-Verzeichnis und klicken Sie weiter auf die Unterverzeichnisse, bis Sie zur Datei JavaWebSocketServerApplication.java gelangen.
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);
}
}
Fügen Sie dem Verzeichnis zwei Dateien hinzu: WebSocketHandler.java und WebSocketConfiguration.java.
Behandeln Sie die WebSocket-Nachrichten
Wir müssen die eingehenden Nachrichten, die auf dem Server ankommen, verarbeiten. Dazu erben Sie in WebSocketHandler.java die Klasse zur Implementierung der Methode handleTextMessage(). Fügen Sie den folgenden Code in die Datei ein:
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");
}
}
}
Innerhalb der Methode holen wir uns einfach den String-Wert der Nutzlast der Nachricht und führen einen Switch-Ausdruck aus, um den Wert der Nachricht mit dem Wert des jeweiligen Falls zu überprüfen. Eine eindeutige Nachricht mit dem Tiergeräusch wird an den Client gesendet.
Konfigurieren Sie die WebSocket-Anfrageverarbeitung
Implementieren Sie in WebSocketConfiguration.java die Schnittstelle WebSocketConfigurer und fügen Sie den folgenden Code in die Datei ein:
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");
}
}
Wir richten die Methode registerWebSocketHandlers ein, um den WebSocketHandler auf den Pfad "/websocket" zu konfigurieren. Das ist alles für die Server-Seite. Nun, da wir alles eingerichtet haben, können wir den WebSocket-Server starten und die Anwendung ausführen!
Daten zwischen Server und Client senden
Wechseln Sie im Terminal in das Stammverzeichnis Ihres Spring Boot-Projekts und führen Sie den folgenden Befehl aus, um den Server zu starten:
gradle bootRun
Führen Sie als Nächstes den Android-Client in Android Studio aus, und sobald die App geladen ist, klicken Sie auf eine der vier Schaltflächen.
Spielen Sie mit der Android-App herum und sehen Sie, wie Nachrichten mit WebSockets vom Client zum Server gesendet werden!
Aktualisieren Sie den Android-Client auf Pub/Sub
Das Senden von Daten von Client zu Server oder von Server zu Client ist nicht schwierig und kann ziemlich schnell erledigt werden. Was aber, wenn Sie Daten von Client zu Client senden möchten? Sie können Clients nicht direkt miteinander verbinden, ohne eine Routing- und Message-Broker-Logik auf dem Server zu implementieren (über enableSimpleBroker
und die Registrierung beim MessageBrokerRegistry-Typ
).
Es gibt mehrere Tools, die diese Aufgabe weniger zeitaufwändig machen. Ein solches Tool ist Socket.IO, das eine bidirektionale Echtzeitverbindung zwischen Clients herstellt. Dies ist ein großartiges Open-Source-Tool, aber wir müssen trotzdem einen Server einrichten und den Client mit dem Server verbinden. Ein weiteres solches Tool ist die Verwendung von Unterprotokollen wie STOMP in Spring Boot, um STOMP-Nachrichten einzubetten. Dieses Unterprotokoll setzt auf WebSocket auf und ermöglicht die Verarbeitung von WebSocket-Nachrichten. Allerdings müssen Sie auch die Endpunkte selbst einrichten, indem Sie den Typ StompEndpointRegistry
verwenden und dann die Endpunkte mit der Methode addEndPoint
hinzufügen. Gibt es einen einfacheren Weg, um Daten sicher und zuverlässig zwischen Clients zu senden, ohne manuell einen Server einzurichten? Mit PubNub können wir das.
PubNub bietet die Echtzeit-Infrastruktur, um jedes TCP-fähige Gerät zu betreiben. Wir können Daten von Client zu Client, von Client zu Server oder von Server zu Client mit PubNub's Global Data Stream Network in weniger als 100 ms übertragen! Mit PubNub wird eine permanente Verbindung zwischen den Geräten hergestellt, die mit dem Kanal verbunden sind, ähnlich wie bei WebSockets. Das Beste daran ist, dass Sie sich nicht um die Einrichtung eines Backend-Servers und die Wartung des Servers kümmern müssen, da PubNub serverlos und unendlich skalierbar ist.
Um zu sehen, wie PubNub den Prozess des Sendens von Daten von Client zu Client vereinfacht, werden wir die Android-App, die wir zuvor gebaut haben, modifizieren. Aber zuerst müssen Sie sich für ein kostenloses PubNub-Konto anmelden, um Ihre kostenlosen Pub/Sub-API-Schlüssel zu erhalten.
Ändern Sie den Android-Client
Um die aktualisierte App von der alten App zu unterscheiden, erstellen Sie ein neues Android-Projekt namens PubNubJavaClient. Um das Android-SDK von PubNub zu verwenden, aktualisieren Sie die json-Datei, indem Sie Folgendes zur build.gradle-Datei im App-Verzeichnis hinzufügen und das Projekt synchronisieren:
dependencies {
implementation group: 'com.pubnub', name: 'pubnub-gson', version: '6.4.5' // Add this
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
}
Fügen Sie die folgenden Berechtigungen in die Manifestdatei ein:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Alles andere, außer MainActivity.java, bleibt gleich. Fügen Sie der aktualisierten App die folgenden Dateien aus der vorherigen App hinzu: animal_sounds.xml, strings.xml und die Bilder aus dem drawable-Verzeichnis. Sobald Sie damit fertig sind, fügen Sie in MainActivity.java den neuen Code ein. Importieren Sie die folgenden Pakete und richten Sie onCreate() ein:
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
}
Rufen Sie initPubNub() auf, um PubNub zu initialisieren:
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();
}
In dieser Methode erledigen wir drei wichtige Dinge:
Initialisierung der PubNub-Client-API. Stellen Sie sicher, dass Sie "ENTER_YOUR_PUB_KEY" und "ENTER_YOUR_SUB_KEY" durch Ihre Pub/Sub-Schlüssel ersetzen.
Richten Sie einen Listener ein, um über Nachrichten, die auf dem Kanal ankommen, informiert zu werden. Wie zuvor zeigen Sie die Nachricht in der App an, damit der Client sie sehen kann.
Abonnieren Sie den globalen Kanal, in dem die Nachrichten veröffentlicht werden sollen.
Wenn der Benutzer eine Schaltfläche drückt, wird die Methode sendMessage() aufgerufen:
// 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;
}
}
Diese Methode ähnelt dem, was wir zuvor gemacht haben, nur dass wir jetzt die eigentliche Nachricht, den Tierlaut, im globalen Kanal und nicht auf dem Server veröffentlichen. Wir verwenden publishMessage() als Hilfsfunktion, um die Nachricht zu veröffentlichen.
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());
}
}
});
}
Das ist alles, was wir brauchen, um die Anwendung zum Laufen zu bringen!
Daten zwischen Clients senden
Führen Sie die Android-App in zwei Emulatoren aus, um zu sehen, wie die Nachrichten in Echtzeit erscheinen.
Hinweis: Um eine nahtlose Kommunikation zwischen den Clients zu gewährleisten, stellen Sie sicher, dass beide Android-Emulatoren dieselben PubNub-Schlüssel haben und am selben Kanal angemeldet sind. Dies ist entscheidend für den Aufbau einer erfolgreichen WebSocket-Verbindung für die Echtzeitkommunikation.
Nun, da Sie gelernt haben, wie man Daten mit WebSockets in Java sendet, vergessen Sie nicht, unsere anderen Ressourcen zu erkunden.
Schauen Sie sich unsere Dokumente an, um mehr über die zusätzlichen Funktionen zu erfahren, die PubNub bietet, wie z.B. Message Actions, Objects und Signal Messages, um Ihrer Anwendung einen robusten Vorteil zu verschaffen. Sehen Sie sich unsere aktualisierten Screenshots und Ressourcenlinks an, um ein umfassenderes Verständnis zu erhalten.
Mit PubNub können Sie auch maßgeschneiderte Lösungen für Geolocation, Edge Message Bus, Unternehmenssoftware, Gaming, Digital Health und E-Commerce erstellen.
Für den Einstieg empfiehlt sich unser allgemeiner Einrichtungsleitfaden, der Sie durch die Einrichtung Ihres Kontos führt. Wenn Sie wissen möchten, wie Sie Nachrichten senden und empfangen können, haben wir auch dafür Anleitungen. Weitere Informationen finden Sie in unseren Anleitungen zum Senden und Empfangen von Nachrichten.
Für fortgeschrittene Funktionen, wie das Senden von Nachrichten, Nachrichtenbestätigungen und die Anzahl der ungelesenen Nachrichten in einem Chat-Szenario, können Sie sich auf diese Dokumente beziehen: Senden von Nachrichten, Nachrichtenbestätigungen und Anzahl der ungelesenen Nachrichten.
Wenn Sie auf einer Android-Plattform arbeiten und Push-Benachrichtigungen implementieren möchten, haben wir für Sie das Richtige. In unserem Android-Push-Guide und Send-Push-Guide finden Sie ausführliche Anweisungen zur Einrichtung von Push-Benachrichtigungen mit Firebase und PubNub.
Haben Sie Vorschläge oder Fragen zum Inhalt dieses Beitrags? Wenden Sie sich an devrel@pubnub.com.
Wie kann PubNub Ihnen helfen?
Dieser Artikel wurde ursprünglich auf PubNub.com veröffentlicht.
Unsere Plattform unterstützt Entwickler bei der Erstellung, Bereitstellung und Verwaltung von Echtzeit-Interaktivität für Webanwendungen, mobile Anwendungen und IoT-Geräte.
Die Grundlage unserer Plattform ist das größte und am besten skalierbare Echtzeit-Edge-Messaging-Netzwerk der Branche. Mit über 15 Points-of-Presence weltweit, die 800 Millionen monatlich aktive Nutzer unterstützen, und einer Zuverlässigkeit von 99,999 % müssen Sie sich keine Sorgen über Ausfälle, Gleichzeitigkeitsgrenzen oder Latenzprobleme aufgrund von Verkehrsspitzen machen.
PubNub erleben
Sehen Sie sich die Live Tour an, um in weniger als 5 Minuten die grundlegenden Konzepte hinter jeder PubNub-gestützten App zu verstehen
Einrichten
Melden Sie sich für einen PubNub-Account an und erhalten Sie sofort kostenlosen Zugang zu den PubNub-Schlüsseln
Beginnen Sie
Mit den PubNub-Dokumenten können Sie sofort loslegen, unabhängig von Ihrem Anwendungsfall oder SDK