fbpixel
Etiquetas: ,
0
(0)

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',
  }

});

Fontes

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

As you found this post useful...

Follow us on social media!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?