Vamos criar um aplicativo React Native que atuará como um cliente Websockets e será capaz de se comunicar com um servidor remoto. O WebSockets é um protocolo de comunicação web popular, simples e robusto que permite a comunicação em tempo real entre cliente e servidor.
Hardware
- Dispositivo Android
- Computador para programação
- Um cabo USB para ligar o dispositivo Android ao PC
Configurar o projeto React Native
Para comunicar via Websocket, vamos utilizar a biblioteca Websocket, react-use-websocket
npm install --save react-use-websocket
Utilizar a biblioteca
A partir da biblioteca, importamos os objectos e funções que nos interessam
import useWebSocket, { ReadyState } from 'react-use-websocket';
- ReadyState estado da ligação com o servidor
- useWebScoket é utilizado para inicializar uma ligação websockets
Em seguida, criamos um componente funcional com os estados desejados
const [ipAddress, setIpAddress] = useState('');
const [ipServer, setIpServer] = useState('ws://192.168.1.52:8765');
const [messageText, setMessageText] = useState("");
const [messageHistory, setMessageHistory] = useState([]);
const { sendMessage, sendJsonMessage, lastMessage, lastJsonMessage, readyState } = useWebSocket(ipServer);
const connectionStatus = {
[ReadyState.CONNECTING]: 'Connecting',
[ReadyState.OPEN]: 'Open',
[ReadyState.CLOSING]: 'Closing',
[ReadyState.CLOSED]: 'Closed',
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
}[readyState];
const paramCmd = {
type: 'setParam',
param1: 30,
param2: 2.3,
}
Nos estados, recuperamos as funções e os estados de useWebSokcet
- sendMessage a função para enviar mensagens em formato String
- sendJsonMessage para enviar mensagens em formato JSON
- lastMessage contém a resposta do servidor em formato String
- lastJsonMessage contém a última mensagem do servidor em formato JSON
- readyState contém o estado da ligação
Também definimos uma constante no formato Json paramCmd.
Utilizamos um gancho useEffect para obter o endereço IP do dispositivo e gerir as mensagens recebidas do servidor.
useEffect(() => {
const fetchIpAddress = async () => {
const ip = await NetworkInfo.getIPV4Address();
setIpAddress(ip);
console.log("ip adresses ; ", ip)
};
fetchIpAddress();
if (lastMessage !== null) {
setMessageHistory((prev) => prev.concat(lastMessage));
}
if (lastJsonMessage !== null) {
console.log(JSON.stringify(lastJsonMessage));
}
return () => {
};
}, [lastMessage, setMessageHistory,lastJsonMessage]);
Por fim, criamos a renderização da aplicação com os seguintes elementos
- um texto para apresentar o endereço IP do dispositivo
- um botão para enviar uma mensagem JSON
- caixa de texto para o texto a escrever para escrever a mensagem em formato de texto
- Botão Enviar para enviar a mensagem
- caixa de texto para introduzir o endereço do servidor
- caixa de texto para apresentar as respostas do servidor
return (
<View style={styles.mainBody}>
<Text
style={styles.mainTitle}>
AC Websocket Terminal
</Text>
<ScrollView>
<View style={styles.deviceItem}>
<View style={{flex:2}}>
<Text style={styles.deviceName}>{ipAddress}</Text>
<Text style={styles.deviceInfo}>{connectionStatus}</Text>
</View>
<TouchableOpacity
onPress={() => sendJSON()}
disabled={readyState !== ReadyState.OPEN}
style={styles.deviceButton}>
<Text
style={styles.buttonText}>
Send JSON
</Text>
</TouchableOpacity>
</View>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={messageText}
onChangeText={(text) => setMessageText(text)
}
/>
<TouchableOpacity
onPress={() => sendMessage(messageText)}
disabled={readyState !== ReadyState.OPEN}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Server IP"
onChangeText={setIpServer}
value={ipServer}
/>
<View style={{flex:1,minHeight:200}}>
<Text>Received Message:</Text>
<ScrollView style={styles.textOutput}>
{lastMessage ? <Text>last message : {lastMessage.data}</Text> : null}
{messageHistory.map((message, idx) => (
<Text key={idx}>{message ? message.data : null}</Text>
))}
</ScrollView>
</View>
</ScrollView>
</View>
);
Criando um servidor WebSockets com Python
Para testar a nossa aplicação, criamos um servidor de websockets no PC
#!/usr/bin/env python
# python3 -m pip install websockets
import json
import asyncio
from websockets.server import serve
def getIpAddress():
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ipaddress = s.getsockname()[0]
s.close()
return ipaddress
ipaddress = getIpAddress()
port = 8765
async def echo(websocket):
async for message in websocket:
print("received from {}:{} : ".format(websocket.remote_address[0],websocket.remote_address[1]) + message)
if('{' not in message):
await websocket.send(message)
else:
request = json.loads(message)
answer = {}
if(request['type'] == 'setParam'):
answer['type'] = request['type']
if(request['param1']<100 and request['param2']>1.2):
answer['valid'] = True
for key, val in request.items():
print("\t"+key+": ", val)
else:
answer['valid'] = False
else:
answer['type'] = 'unknown'
answer['valid'] = False
await websocket.send(json.dumps(answer))
async def main():
print("Server is activated on ws://{}:{}".format(ipaddress,port))
#async with serve(echo, "localhost", 8765):
async with serve(echo, "0.0.0.0", port):
await asyncio.Future() # run forever
asyncio.run(main())
Resultados
Graças a esta aplicação, podemos enviar Strings e JSON para o servidor e apresentar as suas respostas

Código completo para comunicação WebSockets com React Native
/**
* https://reactnative.dev/docs/network
* https://www.npmjs.com/package/react-use-websocket
* https://github.com/robtaussig/react-use-websocket
* test on python
* https://websockets.readthedocs.io/en/stable/
*/
import React, {useState, useEffect, useCallback} from 'react';
import {
View,
ScrollView,
Text,
TextInput,
TouchableOpacity,
StyleSheet} from 'react-native';
import { NetworkInfo } from 'react-native-network-info'
import useWebSocket, { ReadyState } from 'react-use-websocket';
const WebsocketTerminal = () => {
const [ipAddress, setIpAddress] = useState('');
const [ipServer, setIpServer] = useState('ws://192.168.1.52:8765');
const [messageText, setMessageText] = useState("");
const [messageHistory, setMessageHistory] = useState([]);
const { sendMessage, sendJsonMessage, lastMessage, lastJsonMessage, readyState } = useWebSocket(ipServer);
useEffect(() => {
const fetchIpAddress = async () => {
const ip = await NetworkInfo.getIPV4Address();
setIpAddress(ip);
console.log("ip adresses ; ", ip)
};
fetchIpAddress();
if (lastMessage !== null) {
setMessageHistory((prev) => prev.concat(lastMessage));
}
if (lastJsonMessage !== null) {
console.log(JSON.stringify(lastJsonMessage));
}
return () => {
};
}, [lastMessage, setMessageHistory,lastJsonMessage]);
const connectionStatus = {
[ReadyState.CONNECTING]: 'Connecting',
[ReadyState.OPEN]: 'Open',
[ReadyState.CLOSING]: 'Closing',
[ReadyState.CLOSED]: 'Closed',
[ReadyState.UNINSTANTIATED]: 'Uninstantiated',
}[readyState];
const sendJSON = () => {
const paramCmd = {
type: 'setParam',
param1: 30,
param2: 2.3,
}
sendJsonMessage(paramCmd);
}
return (
<View style={styles.mainBody}>
<Text
style={styles.mainTitle}>
AC Websocket Terminal
</Text>
<ScrollView>
<View style={styles.deviceItem}>
<View style={{flex:2}}>
<Text style={styles.deviceName}>{ipAddress}</Text>
<Text style={styles.deviceInfo}>{connectionStatus}</Text>
</View>
<TouchableOpacity
onPress={() => sendJSON()}
disabled={readyState !== ReadyState.OPEN}
style={styles.deviceButton}>
<Text
style={styles.buttonText}>
Send JSON
</Text>
</TouchableOpacity>
</View>
<View
style={styles.inputBar}>
<TextInput
style={styles.textInput}
placeholder="Enter a message"
value={messageText}
onChangeText={(text) => setMessageText(text)
}
/>
<TouchableOpacity
onPress={() => sendMessage(messageText)}
disabled={readyState !== ReadyState.OPEN}
style={[styles.sendButton]}>
<Text
style={styles.buttonText}>
SEND
</Text>
</TouchableOpacity>
</View>
<TextInput
placeholder="Server IP"
onChangeText={setIpServer}
value={ipServer}
/>
<View style={{flex:1,minHeight:200}}>
<Text>Received Message:</Text>
<ScrollView style={styles.textOutput}>
{lastMessage ? <Text>last message : {lastMessage.data}</Text> : null}
{messageHistory.map((message, idx) => (
<Text key={idx}>{message ? message.data : null}</Text>
))}
</ScrollView>
</View>
</ScrollView>
</View>
);
}
export default WebsocketTerminal;
let BACKGROUND_COLOR = "#161616"; //191A19
let BUTTON_COLOR = "#346751"; //1E5128
let ERROR_COLOR = "#C84B31"; //4E9F3D
let TEXT_COLOR = "#ECDBBA"; //D8E9A8
var styles = StyleSheet.create({
mainBody: { flex: 1, justifyContent: 'center', backgroundColor: BACKGROUND_COLOR},
mainTitle:{
color: TEXT_COLOR,
fontSize: 30,
textAlign: 'center',
borderBottomWidth: 2,
borderBottomColor: ERROR_COLOR,
},
backgroundVideo: {
borderWidth: 2,
borderColor: 'red',
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
webVideo: {
borderWidth: 2,
borderColor: 'green',
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
buttonText: {
color: TEXT_COLOR,
fontWeight: 'bold',
fontSize: 12,
textAlign: 'center',
textAlignVertical: 'center',
},
sendButton: {
backgroundColor: BUTTON_COLOR,
padding: 15,
borderRadius: 15,
margin: 2,
paddingHorizontal: 20,
},
deviceItem: {
flexDirection: 'row',
flex: 3,
marginBottom: 2,
},
deviceName: {
fontSize: 14,
fontWeight: 'bold',
},
deviceInfo: {
fontSize: 8,
},
deviceButton: {
backgroundColor: '#2196F3',
padding: 10,
borderRadius: 10,
margin: 2,
paddingHorizontal: 20,
},
inputBar:{
flexDirection: 'row',
justifyContent: 'space-between',
margin: 5,
},
textInput:{
backgroundColor: '#888888',
margin: 2,
borderRadius: 15,
flex:3,
},
textOutput:{
backgroundColor: '#333333',
margin: 10,
borderRadius: 2,
borderWidth: 1,
borderColor: '#EEEEEE',
textAlignVertical: 'top',
}
});