How To Send & Receive Data Over Wifi Without Internet In React-Native - android

I am developing a game on React-Native that works completely offline without needing internet connection,
The game will be multiplayer 1vs1 game, and players will join via Wifi Hotspot (also known as wifi Direct)
The game will also allow users to chat with eachother
and this all should be done without internet by just using the wifi..
I have tried "React-Native-Wifi-Hotspot" but there is no documentation about how to send and receive data
I want to send and receive objects/arrays over wifi hotspot between 2 connected devices. P2P
I have also readed about react-native-wifi-p2p library but it's documentation says that we need a local server or something i am really not sure about how to do that.

So, I would keep this answer as comprehensive as possible. I will share a small react-native application I build to help understand what exactly we need to do.
This answer is a working extension to #ßãlãjî 's answer.
Libraries we need:
react-native-tcp
react-native-network-info
// In App.js
import {createAppContainer} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import ClientScreen from './src/screens/ClientScreen';
import ServerScreen from './src/screens/ServerScreen';
const navigator = createStackNavigator({
Server: ServerScreen,
Client: ClientScreen
});
export default createAppContainer(navigator);
// In ClientScreen.js
import React, {useState, useEffect} from 'react';
import {View, Text, Button, FlatList, TextInput} from 'react-native';
import { NetworkInfo } from 'react-native-network-info';
var net = require('react-native-tcp');
const createClient = (ip, chats, setChats) => {
const client = net.createConnection(6666,ip, () => {
console.log('opened client on ' + JSON.stringify(client.address()));
// client.write('Hello, server! Love, Client.');
});
client.on('data', (data) => {
setChats([...chats, {id:chats.length+1, msg:data}]);
// console.log('Client Received: ' + data);
// client.destroy(); // kill client after server's response
// this.server.close();
});
client.on('error', (error) => {
console.log('client error ' + error);
});
client.on('close', () => {
console.log('client close');
});
return client;
};
const ClientScreen = ({navigation}) => {
const [client, setClient] = useState(null);
const [chats, setChats] = useState([]);
useEffect(async () => {
let ip = await NetworkInfo.getIPV4Address(); //await NetworkInfo.getGatewayIPAddress();
setClient(createClient(ip));
return () => {};
}, []);
return <View>
<Text>Client Screen</Text>
<Button title="Stop Client" onPress={() => {
if(client){
client.destroy();
setClient(null);
}
}}/>
{client ? <Text>Client is on</Text>: null}
<FlatList
data={chats}
renderItem={({item}) =>{
return <Text style={{margin:10, fontSize:20}}>{item.msg}</Text>;
}}
keyExtractor={item => item.id}
/>
<TextInput placeholder="Type a message" placeholderTextColor="black" style={{margin:10, borderWidth:2, color:'black'}} onSubmitEditing={({nativeEvent: {text}}) => {
if(client){
client.write(JSON.stringify({msg:text, id:1}));
}
}}/>
</View>;
};
export default ClientScreen;
// In ServerScreen.js
import React, {useState} from 'react';
import {View, Text, Button, StyleSheet, FlatList} from 'react-native';
import { NetworkInfo } from 'react-native-network-info';
var net = require('react-native-tcp');
const createServer = (chats, setChats) => {
const server = net.createServer((socket) => {
console.log('server connected on ' + socket.address().address);
socket.on('data', (data) => {
let response = JSON.parse(data);
setChats([...chats, {id:chats.length+1, msg:response.msg}]);
// console.log('Server Received: ' + data);
// socket.write('Echo server\r\n');
});
socket.on('error', (error) => {
console.log('error ' + error);
});
socket.on('close', (error) => {
console.log('server client closed ' + (error ? error : ''));
});
}).listen(6666, () => {
console.log('opened server on ' + JSON.stringify(server.address()));
});
server.on('error', (error) => {
console.log('error ' + error);
});
server.on('close', () => {
console.log('server close');
});
return server;
};
const ServerScreen = ({navigation}) => {
const [server, setServer] = useState(null);
const [chats, setChats] = useState([]);
const [ip, setIp] = useState('');
return <View>
{ip.length > 0? <Text>Server Screen: {ip}</Text>: <Text>Server Screen</Text>}
<Button title="Start Server" onPress={async () => {
if(!server)
setServer(createServer(chats, setChats));
try{
let temp_ip = await NetworkInfo.getIPV4Address();
setIp(temp_ip);
}catch(e){
console.log(e.message);
}
}}/>
<Button title="Stop Server" onPress={() => {
if(server){
server.close();
setServer(null);
}
}}/>
<Button title="Go to Client Screen" onPress={() => navigation.navigate('Client')}/>
{server ? <Text>Server is on</Text>: null}
<FlatList
data={chats}
renderItem={({item}) =>{
return <Text style={{margin:10, fontSize:20}}>{item.msg}</Text>;
}}
keyExtractor={item => item.id}
/>
</View>;
};
const styles = StyleSheet.create({});
export default ServerScreen;
Firstly, how to run this application.
Build and Install this into a physical device or Emulator.
First, go to ServerScreen.
In the ServerScreen press on Start Server button. You will be able to see an IP address pop in the screen.
Now navigate to ClientScreen. The Client socket gets automatically invoked once you navigate to this Screen. Here you can see a button and a text input field. Type in some message in the field and submit from the keyboard. Press the Stop Client button to avoid any errors.
Go back to the ServerScreen you will be able to see the message that you typed in the ClientScreen.
Now, this is a minimal example of how to communicate between 2 devices through local network. But as you might be wondering, this app only lets us communicate between 2 screens right?
To be honest, thats true, we are only able to communicate between 2 screens so far using this application, but, the underlying mechanism we used to make it work is exactly same as what we would do in case of communication between 2 devices.
So, how to do it for different devices.
Lets say we have 2 device, namely A and B. We want to establish a connection between both of these device. Firstly, we will turn on the wifi hotspot of A, and will connect B to that wifi.
Now, on device A, we will go to the ServerScreen and start the server. On device B, go to ClientScreen and you will see "client is on" info appear, but if you type in some message in the textfield and submit, you wont be seeing any message appear on Device A, this is because to make it work, we need to change a little bit on the ClientScreen.js component file.
Change from =>
useEffect(async () => {
let ip = await NetworkInfo.getIPV4Address(); //await NetworkInfo.getGatewayIPAddress();
setClient(createClient(ip));
return () => {};
}, []);
to =>
useEffect(async () => {
let ip = await NetworkInfo.getGatewayIPAddress();
setClient(createClient(ip));
return () => {};
}, []);
What this does is, the IP that we want, to connect our device B to device A, is the IP of the Gateway of device B (Remember, we connected B to the hotspot of A).
That's it.
Now simply build again and follow the steps previously mentioned. Once you type in a message and submit it over the ClientScreen on B, you will be able to see it on ServerScreen of A.
Hope this helps anyone who is struggling with establishing a local socket connection between devices.
Note that, you can sure have multiple clients with a single server with some little behaviourial change on ServerScreen and this same codebase.
PS. I will make sure that I keep a check on this answer frequently so that any issue you face, you can comment and I can get back to you ASAP.
Edit: If you want to sent messages to the client system from the main system (hotspot), then you can follow this answer https://stackoverflow.com/a/73166697/9748372.

Yes You can share data between two devices but you mentioned
React-Native-Wifi-Hotspot
this library is helps to establish connection between two devices but not share anything (this lib just made for establish connection thats it)
then how i share the data?
1.you can share data with help of TCP and UDP
The major applications using TCP/UDP for file sharing and data communicaiton like shareit
Now You imagine exactly share it app
it has sender and reciever same way
sender is a client in tcp/udp
reciever is a server in tcp/udp
Now we see detail approach(server and client)
device one is server(just Imagine)
eg:
ip address 192.1.1.1
port: 6666
device two is a client
eg
ip address 192.2.2.2
port: 6666
sending data to server by ip address with port
Note:device 2 should know server ip and port thats it
Now we configure device one as server
npm i react-native-tcp
to know ip
npm i react-native-network-info
import { NetworkInfo } from "react-native-network-info";
// Get Local IP
NetworkInfo.getIPAddress().then(ipAddress => {
console.log(ipAddress);
});
// Get IPv4 IP (priority: WiFi first, cellular second)
NetworkInfo.getIPV4Address().then(ipv4Address => {
console.log(ipv4Address);
});
server setup only i added port(eg 6666)
let server = net.createServer((socket) => {
this.updateChatter('server connected on ' + JSON.stringify(socket.address()));
socket.on('data', (data) => {
this.updateChatter('Server Received: ' + data);
socket.write('Echo server\r\n');
});
socket.on('error', (error) => {
this.updateChatter('error ' + error);
});
socket.on('close', (error) => {
this.updateChatter('server client closed ' + (error ? error : ''));
});
}).listen("6666", () => {
this.updateChatter('opened server on ' + JSON.stringify(server.address()));
});
server.on('error', (error) => {
this.updateChatter('error ' + error);
});
server.on('close', () => {
this.updateChatter('server close');
});
client setup(i added manualy server ip address(192.1.1.1) and port(6666) ):
let client = net.createConnection(6666,192.1.1.1, () => {
this.updateChatter('opened client on ' + JSON.stringify(client.address()));
client.write('Hello, server! Love, Client.');
});
client.on('data', (data) => {
this.updateChatter('Client Received: ' + data);
this.client.destroy(); // kill client after server's response
this.server.close();
});
client.on('error', (error) => {
this.updateChatter('client error ' + error);
});
client.on('close', () => {
this.updateChatter('client close');
});
this.server = server;
this.client = client;
}
componentWillUnmount() {
this.server = null;
this.client = null;
}
thats it
then i come to your point
React-Native-Wifi-Hotspot
this library just helps to share ip address between devices then you establish tcp connection to communicate or share files between devices
Note:
file sharing possible with tcp ,udp , ftp , websocket,peer network and also over http
you can choose any one of above protocol to make file sharing application,extra tips ,you must learn about chunks and stream.(this helps you large file sharing)
i hope it may help you

You can use this library called React Native TCP which is able to send and receive data over wifi.
It is the node's net API in React Native.
It is almost identical to the node's net API and you can use net's documentation. And just a suggestion on how to do it would be that, You can set up a connection page consistent of two buttons for example. And then define a hotspot creating functionality for one and define a hotspot connecting functionality for another one.

Related

Read ALL SMS in inbox or Send it to Server in React NATIVE

I am building an app that requires the functionality of reading SMS from the inbox. It's a kind of app that Microsoft built known as SMS organizer. I'm trying to build it for the local crowd and I'm using react-native to do the same. I read many libraries but none seem to be helpful or informative for my cause.
https://www.npmjs.com/package/react-native-read-sms
https://www.npmjs.com/package/react-native-get-sms-android
Anyone has any idea for how I can accomplish the same.
PS- I'm aiming to do it for both androids as well as ios.
True- We cannot read sms in IOS devices.
For Android, I found a library that helps to achieve this.
import SmsAndroid from 'react-native-get-sms-android';
var filter = {
box: 'inbox',
};
const Readsms_list = async () => {
SmsAndroid.list(
JSON.stringify(filter),
(fail) => {
console.log('Failed with this error: ' + fail);
},
(count, smsList) => {
console.log('Count: ', count);
console.log('List: ', smsList);
var arr = JSON.parse(smsList);
arr.forEach(function (object) {
// 'Object: ' +
console.log(object);
// console.log('-->' + object.date);
// console.log('-->' + object.body);
});
},
);
};
This helps in reading all the SMS from the device.

React-Native NFC Reader returns: The NFC tag's type is not supported

I am trying to create an android app that will be used to make a payment with an Ingenico terminal. I added the react-native-nfc-manager (https://github.com/whitedogg13/react-native-nfc-manager) to my project an followed the v2-ios+android-write-ndef example. I also enabled NFC on my phone. I bought from Amazon an NFC USB reader. I installed it and also got a windows app called GoToTags that connected successfully to the USB module.
I fired up my app and tested the NFC button.
The scanner beeps (So the NFC technologie was loaded) but GoToTags sends back a message (The NFC tag's type is not supported) that looks like this:
{"Uid":null,"ReadOnly":false,"DataLength":null,"CanMakeReadOnly":false,
"Formatted":false,"Records":null,"TagTech":null,"MaxDataLength":null,
"Exception":"The NFC tag's type is not supported."}
I am unsure what I am doing wrong. I followed the instructions to the letter and also watched and followed a YouTube tutorial.
https://www.youtube.com/watch?v=Kx22B6OH3Oc
The only difference between my code and the guy in the YouTube video is that I am using an android phone instead of an iPhone.
This is my code:
import React from 'react';
import {
View,
Text,
TouchableOpacity,
} from 'react-native';
import NfcManager, {Ndef, NfcTech} from 'react-native-nfc-manager';
function buildUrlPayload(valueToWrite) {
return Ndef.encodeMessage([
Ndef.uriRecord(valueToWrite),
]);
}
class AppV2Ndef extends React.Component {
componentDidMount() {
NfcManager.start();
}
componentWillUnmount() {
this._cleanUp();
}
render() {
return (
<View style={{padding: 20}}>
<Text>NFC Demo</Text>
<TouchableOpacity
style={{padding: 10, width: 200, margin: 20, borderWidth: 1, borderColor: 'black'}}
onPress={this._testNdef}
>
<Text>Test Ndef</Text>
</TouchableOpacity>
<TouchableOpacity
style={{padding: 10, width: 200, margin: 20, borderWidth: 1, borderColor: 'black'}}
onPress={this._cleanUp}
>
<Text>Cancel Test</Text>
</TouchableOpacity>
</View>
)
}
_cleanUp = () => {
NfcManager.cancelTechnologyRequest().catch(() => 0);
}
_testNdef = async () => {
try {
let resp = await NfcManager.requestTechnology(NfcTech.Ndef, {
alertMessage: 'Ready to write some NFC tags!'
});
console.warn(resp);
let ndef = await NfcManager.getNdefMessage();
console.warn(ndef);
let bytes = buildUrlPayload('https://www.google.com');
await NfcManager.writeNdefMessage(bytes);
console.warn('successfully write ndef');
await NfcManager.setAlertMessageIOS('I got your tag!');
this._cleanUp();
} catch (ex) {
console.warn('ex', ex);
this._cleanUp();
}
}
}
export default AppV2Ndef;
What I need to do is send out a 4 digit code to the Ingenico terminal from the phone using the NFC tech. But before I go a head an make that possible, I just want to get the NFC to work first. Sending out https://google.com to the card reader would be a good first step. But so fare, no luck.
What am I missing? It seems pretty much straight forward no?

Android - PWA does not open in standalone mode with service worker

While developing a Progressive-Web-App the following Problem occurred:
Standalone mode works perfectly without including the service worker - but does NOT work with.
Without Service-Worker a2hs (added to Homescreen) PWA gets correctly started in "standalone"-Mode.
After adding the Service-Worker (a2hs + installed / Web-APK) PWA opens new Tab in new Chrome-Window.
Chrome-PWA-Audit:
login_mobile_tablet.jsf / include service worker:
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../serviceWorker.js', {scope: "/application/"})
/* also tried ".", "/", "./" as scope value */
.then(function(registration) {
console.log('Service worker registration successful, scope is: ', registration.scope);
})
.catch(function(error) {
console.log('Service worker registration failed, error: ', error);
});
}
</script>
serviceWorker.js:
var cacheName = 'pwa-cache';
// A list of local resources we always want to be cached.
var filesToCache = [
'QS1.xhtml',
'pdf.xhtml',
'QS1.jsf',
'pdf.jsf',
'login_pages/login_mobile_tablet.jsf',
'login_pages/login_mobile_tablet.xhtml'
];
// The install handler takes care of precaching the resources we always need.
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll(filesToCache);
})
);
})
// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
// The fetch handler serves responses for same-origin resources from a cache.
self.addEventListener('fetch', event => {
// Workaround for error:
// TypeError: Failed to execute 'fetch' on 'ServiceWorkerGlobalScope': 'only-if-cached' can be set only with 'same-origin' mode
// see: https://stackoverflow.com/questions/48463483/what-causes-a-failed-to-execute-fetch-on-serviceworkerglobalscope-only-if
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin')
return;
event.respondWith(
caches.match(event.request, {ignoreSearch: true})
.then(response => {
return response || fetch(event.request);
})
);
});
manifest.json:
{
"name":"[Hidden]",
"short_name":"[Hidden]",
"start_url":"/application/login_pages/login_mobile_tablet.jsf",
"scope":".",
"display":"standalone",
"background_color":"#4688B8",
"theme_color":"#4688B8",
"orientation":"landscape",
"icons":[
{
"src":"javax.faces.resource/images/icons/qsc_128.png.jsf",
"sizes":"128x128",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_144.png.jsf",
"sizes":"144x144",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_152.png.jsf",
"sizes":"152x152",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_192.png.jsf",
"sizes":"192x192",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_256.png.jsf",
"sizes":"256x256",
"type":"image/png"
},
{
"src":"javax.faces.resource/images/icons/qsc_512.png.jsf",
"sizes":"512x512",
"type":"image/png"
}
]
}
The following questions / answers were considered - but no solution was found:
PWA wont open in standalone mode on android
WebAPK ignores display:standalone flag for PWA running on local network
PWA deployed in node.js running in Standalone mode on Android and iOS
Technical Background
The Moment you add your Service-Worker (along all other PWA-Requirements) your App gets created as an Real PWA - with Web-APK getting installed.
Therefore you also need to use Default-HTTPS-Port 443 - make sure you use a valid HTTPS-Certificate.
Before adding the Service-Worker, this mandatory requirement was missing so your PWA was NOT installed and therefore needed less other requirements to be displayed in "standalone-mode".
It's just a shame that this is nowhere documented... and we had to "find out" for ourselves.
Short-List of Mandatory Requirements for "Installable Web-APK":
(As we could not find a full List, i try to include all Points)
Registered Service-Worker (default-implementation like yours is enough)
manifest.json (yours is valid)
https with valid certificate
https default-port (443, eg. https://yourdomain.com/test/)
... for the rest just check chrome audit tool (HINT: you don't need to pass all requirements - your web-apk should work when switching to https-default-port)

Cordova and socket.io : client disconnection and reconnection

I am trying to share datas between a cordova app (android) and a node server, but the client doesn't stop disconnect and reconnect...
Also, I can't get any information from the server (probably because the client disconnects too fast).
Here's my simple server :
io.sockets.on('connection', function (socket) {
console.log('new connected : ' + socket.id);
socket.emit('connected', {"data": "YEAAAAH"});
socket.on('slt', ( data ) => {
console.log(data);
});
socket.on("disconnect", () => {
console.log("disconnection");
});
});
And the code i use for the client app :
<script type="text/javascript" src="http://cdn.socket.io/socket.io-1.0.3.js"></script>
let socket = io.connect('http://MY-DOMAIN-NAME.com');
socket.on('connected', function (data) {
alert('connected');
socket.emit('slt', { data: 'slt' });
});
And a picture of the logs after 5 sec... :
logs
Do you have an idea how to fix that ? :)
Ok problem fixed : I messed up for linking my scripts :/

Connecting Android Application With CakePhp website

Is it possible to communicate an android Application with cakePhp website and share data? If it is possible, I want to create an application that can login into the website; my doubt is:
How to pass user name and password from our application to cakephp websites login page? Can anybody show me an example program?
How cakephp controller handle this request and respond to this request? Please show me an example program?
(I am a beginner in android and cakephp.)
Quick answer -- YES!
We just finished pushing an Android app to the market place that does this exact thing. Here's how we did it:
1) Download and learn to use Cordova PhoneGap (2.2.0 is the latest version) within Eclipse. This makes the whole thing so much easier with just some HTML and a lot of Javascript.
2) In your JS, create methods that push the login information using AJAX parameters. Example:
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
$("#login").click(function() {
$email = $("#UserEmail").val();
$pass = $("#UserPassword").val();
$.ajax({
url : yourURL + 'api/users/login',
async : false,
data : {
'email' : $email,
'password' : $pass
},
dataType : 'json',
type : 'post',
success : function(result) {
/**
* do your login redirects or
* use localStorage to store your data
* on the phone. Keep in mind the limitations of
* per domain localStorage of 5MB
*/
// you are officially "logged in"
window.location.href = "yourUrl.html";
return;
},
error : function(xhr, status, err) {
// do your stuff when the login fails
}
});
}
}
3) In Cake / PHP, your Users controller here will take the username and password data in the AJAX call and use that for its authentication.
<?php
class UsersController extends AppController {
public $name = 'Users';
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('api_login');
}
public function api_login() {
$this->autoRender = false;
if ($this->request->data && isset($this->request->data['email']) && isset($this->request->data['password'])) {
$arrUser = $this->User->find('all',array(
'conditions'=>array(
'email'=> $this->request->data['email'],
'password' => $this->Auth->password($this->request->data['password']),
)
)
);
if (count($arrUser) > 0) {
$this->Session->write('Auth.User',$arrUser[0]['User']);
// Do your login functions
$arrReturn['status'] = 'SUCCESS';
$arrReturn['data'] = array( 'loginSuccess' => 1,'user_id' => $arrUser[0]['User']['id'] );
} else {
$arrReturn['status'] = 'NOTLOGGEDIN';
$arrReturn['data'] = array( 'loginSuccess' => 0 );
}
} else {
$arrReturn['status'] = 'NOTLOGGEDIN';
$arrReturn['data'] = array( 'loginSuccess' => 0 );
}
echo json_encode($arrReturn);
}
}
?>
That's pretty much it. You are now authenticated to CakePHP.
You do not need to use "api_", you can use any function name you want, but this helped us keep a handle on what we allowed mobile users to do versus web users.
Now, these are just the building blocks. You basically have to create a whole version of your site on the phone using HTML and Javascript, so depending on your application it may be easier just to create a responsive design to your site and allow mobile browsing.
HTH!
Use Admad JWT Auth Plugin
If you use cakephp3 change your login function with this one :
public function token() {
$user = $this->Auth->identify();
if (!$user) {
throw new UnauthorizedException('Invalid username (email) or password');
}
$this->set([
'success' => true,
'data' => [
'token' => JWT::encode([
'sub' => $user['id'],
'exp' => time() + 604800
],
Security::salt())
],
'_serialize' => ['success', 'data']
]);
}
You can read this tutorial about REST Api and JWT Auth Implementation
http://www.bravo-kernel.com/2015/04/how-to-add-jwt-authentication-to-a-cakephp-3-rest-api/
if rebuild most of the view pages in cakephp into ajax will seem defeat the purposes of using cakephp as it is.

Categories

Resources