fbpixel
Etiquetas: ,

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm install --save react-use-websocket
npm install --save 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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import useWebSocket, { ReadyState } from 'react-use-websocket';
import useWebSocket, { ReadyState } from 'react-use-websocket';
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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,
}
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, }
  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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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]);
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]);
  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
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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>
);
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> );
  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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/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())
#!/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())
#!/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

react-native-websockets-client-app Usando WebSockets com React Native

Código completo para comunicação WebSockets com React Native

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/**
* 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',
}
});
/** * 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', } });
/**
 * 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',
  }

});

Fontes