Unable to communicate between Android client and Node.js socket.io server - java

I've looked at many tutorials on this yet none of them seem to work so no idea whether it's the server, client or potentially something on my network that's stopping it I don't know, so I come here for help.
Just for reference this is the tutorial that this is mainly based on: https://socket.io/blog/native-socket-io-and-android/
So this is my server. All it's supposed to do at the moment is detect when a user connects and then detect users sending messages and send them back to all the clients.
index.js
const express = require("express");
const app = express();
const path = require("path");
const server = require("http").createServer(app);
const io = require("socket.io")(server);
server.listen(3000, () => {
console.log("Server listening at 3000");
});
app.use(express.static(path.join(__dirname, "public")));
io.on("connection", (socket) => {
console.log("User connected");
socket.on("new message", (data) => {
console.log("New message" + data)
socket.emit("new message", {
message: data
});
})
});
My Android client is made up of 3 classes. But to try and keep this shorter I'll only include 2 of them as if the problem can be found in these it's fixable in the 3rd.
This is what's launched at the start and simply pressing the button brings you to the main 'chat' part, but on clicking the button the server should log the connection but nothing appears in the console. So I can only assume the socket connection isn't working for some reason. Also you can ignore the nickname, I've not implemented that yet, been trying to get the main part working first.
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import io.socket.client.Socket;
public class MainActivity extends AppCompatActivity {
private EditText nickname;
private Button enterChat;
private Socket mSocket;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nickname = findViewById(R.id.nickname);
enterChat = findViewById(R.id.enterChat);
ChatApplication app = (ChatApplication) getApplication();
mSocket = app.getSocket();
mSocket.connect();
enterChat.setOnClickListener(v -> {
mSocket.emit("connection");
Intent i = new Intent(MainActivity.this, ChatActivity.class);
i.putExtra("name", nickname.getText().toString());
startActivity(i);
});
}
}
This is just to be able to get the Socket from any other activity.
ChatApplication.java
import android.app.Application;
import java.net.URISyntaxException;
import io.socket.client.IO;
import io.socket.client.Socket;
public class ChatApplication extends Application {
private Socket mSocket;
{
try {
//My IPv4 address here
mSocket = IO.socket("http://xxx.xxx.x.xxx:3000");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
public Socket getSocket() {
return mSocket;
}
}
Any help appreciated :)

Found the problem, I need to add this to the AndroidManifest.xml
<application
...
android:usesCleartextTraffic="true"
...
</application>

Related

Howto getExtras from a local broadcast Intent in react-native

in my React-Native opened project,
I want to receive the data (extra text) sent by another local service app named "scanservice" on its intent output (broadcast) on a Action named "scanservice.data" ,
and I do not know how to start & write that : someone can help me please?
I have tried without success HeadlessJs, Linking solutions.
I put some more info I got and I please ask for some corrections since I am null in Java writting :
I want to make a native Android module (in java) (as described on RN site : https://reactnative.dev/docs/native-modules-android)
to catch the text ('extra_text') sent by an intent of another app, named "manuf".
The class 'scan_intent.java' I wrote here has many mistakes (with "//error":
package com.intent_scan;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import org.w3c.dom.Text;
public class ScanIntent extends ReactContextBaseJavaModule {
//constructor
// normaly : "public class ScanIntent extends BroadcastReceiver" : how to add this ?
public ScanIntent(ReactApplicationContext reactContext) {
super(reactContext);
}
#Override
public String getName() {
return "ScanIntent";
}
//Custom function that we are going to export to JS
#ReactMethod
public void onReceive(Context context, Intent intent, String extra_text){
if ("manuf.scanservice.data".equals(intent.getAction()))
{
getReactApplicationContext().registerReceiver //error on registerR...
try {
Bundle extras = intent.getExtras();
if (extras != null) {
extra_text = extras.getString("text"); //error : this value will be returned ?
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}}
thank you !

cannot get android app to connect to my server on my local computer

Hi I'm new to android and Im
Trying to get my android app to connect to a my server that is running on my local computer. Im just trying to get the app to send a simple string message to the server first but keep getting an error. From the print out statements i can see that the app terminates as soon as it hits the line with the try in it so i believe there is an issue with creating the client connection. I have also enable Internet,ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE permissions
i tried changing the localhost to InetAddress.getLocalHost() but still wouldn't work
heres my code :
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.util.StringBuilderPrinter;
import android.view.View;
import android.widget.Button;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import static java.net.InetAddress.getLocalHost;
public class MainActivity extends AppCompatActivity{
private Button cam;
private Socket client;
DataOutputStream os;
private String IP = "localhost";
private static final String TAG = "testing";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (android.os.Build.VERSION.SDK_INT > 9)
{
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
setContentView(R.layout.activity_main);
cam = (Button) findViewById(R.id.Button_camera);
cam.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.v(TAG, "trying to connect to server");
try {
client = new Socket("My IP address entered", 8080);
Log.v(TAG, "client socket initalised");
String hey = "hey";
os = new DataOutputStream(client.getOutputStream());
Log.v(TAG, "outptu stream created");
os.flush();
Log.v(TAG, "flush");
os.writeBytes(hey);
Log.v(TAG, "written to server");
os.close();
} catch (UnknownHostException e) {
Log.v(TAG, "Unknown error");
Log.v(TAG, e.toString());
} catch (IOException e) {
Log.v(TAG, "IO exception u numpty");
Log.v(TAG, e.toString());
}
Intent intent = new Intent(MainActivity.this, Main2Activity.class);
startActivity(intent);
}
});
}
}
my code prints out the statement trying to connect to server but doesn't reach any of the other print out statements and my server is still not receiving anything
connect failed: ETIMEDOUT (Connection timed out)
ACTION_DOWN before UnsetPressedState. invoking mUnsetPressedState.run()
I/Choreographer: Skipped 3792 frames! The application may be doing too much work on its main thread.
I believe this is definitely just an issue with your IP, you are obviously giving ti the wrong ip address because everything else is fine. I would recommend either accessing the terminal and using the ifconfig command to find your ip or access your network settings, if your using a mac like I am select network , advance options , select tcp/ip tab and use ipv4 address as the ip address. If that doesn't work try using a different port or checking your firewall setting on your local computer. Hope that helps.
Localhost is the phone itself, not your computer. If on a simulator, localhost is the simulator, not your computer- the simulator doesn't know its a simulator, it has its own IP address. Fix the IP you're using.

How do put each AsyncTask class in a separate file?

I have a few asynstask that are definined inside of my main activity. I tried to make the code more modular by putting each one of these classes on a separate file. Unfortunately I keep getting some errors such as not being able to get the intents to work. How do I connect this code with my main activity. By the way if I place this code as is(without the imports) in the mainActivity it works just fine. Thanks
package com.example.food4thought;
import java.net.URL;
import twitter4j.TwitterException;
import twitter4j.auth.RequestToken;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;
// Starts an intent that loads up a web browser and asks the user to log in to twitter
// and get a pin#
public class TwitterLogin extends AsyncTask<URL, Integer, RequestToken> {
protected RequestToken doInBackground(URL... arg0) {
try {
requestToken = twitter.getOAuthRequestToken();
Log.i("Got Request Token", "food4thought");
} catch (TwitterException e) {
Log.i("Failed to get Request Token", "food4thought");
}
//Log.i(requestToken.getAuthorizationURL(), "food4thought");
//requestToken.getAuthorizationURL();
//log_in.setText();
try {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(requestToken.getAuthorizationURL()));
startActivity(browserIntent);
}
catch(NullPointerException e) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Unable to log in, No access to the Internet.", Toast.LENGTH_LONG).show();
}
});
}
return null;
}
}
To do that you need to understand what dependencies your AsyncTask has.
To fire Intents you need Context intance. I also see some twitter variable.
So you need declare appropriate fields and to pass those objects to your TwitterLogin constructor.
Something like that:
public class TwitterLogin extends AsyncTask<URL, Integer, RequestToken> {
private Context context;
//other fields here
public TwitterLogin(Context context, ...){ // other variables here
this.context = context;
//other fields assignment
}
}
Later you can fire Intent:
context.startActivity(browserIntent);
What's important to understand is that all those methods like startActivity are not some "global functions", rather they are methods of some class instance, and you can't just call those methods from AsycTask instance.

Connecting database using MySQL connector

I am a beginner to Android Eclipse. However, I have a project to do an Android application. I am unable to connect to the Android emulator using the MySQL connector to create a login page. Am I missing an important file?
Loginpage
package com.example.logininterface;
import com.example.logininterface.R.menu;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText txtUserName;
EditText txtPassword;
Button btnLogin;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtUserName = (EditText)this.findViewById(R.id.txtUname);
txtPassword = (EditText)this.findViewById(R.id.txtPwd);
btnLogin = (Button)this.findViewById(R.id.btnLogin);
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if ((txtUserName.getText().toString()).equals(txtPassword.getText().toString())) {
Toast.makeText(MainActivity.this, "Login Successful", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(MainActivity.this, "Invalid Login", Toast.LENGTH_LONG).show();
}
}
});
}
}
MySQLConn
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class Main {
public static void main(String[] args) throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mobiledb", "teddy", "password");
PreparedStatement statement = con.prepareStatement("select * from androidlogin");
ResultSet result = statement.executeQuery();
while(result.next())
{
System.out.println(result.getString(1) + "" + result.getString(2));
}
}
}
I don't think accessing any database directly from the Android layer is a good idea. It would be better if you could pass required parameters to a server page (PHP, JSP, etc.) and database connections could be done from server pages.
Coming to your question, localhost means Android in this case, so it will be looking for a MySQL database inside your emulator. Instead, you need to use your computer's IP address. Go to a terminal and type ipconfig or ifconfig if you are on *nix/Macintosh machine to get the IP address.
I suggest to use JSON with PHP to connect to the MySQL database. It is just an opinion.
It is better that you use JSON to communicate with the PHP script and within the PHP script to communicate with your localhost MySQL database. And you may try this to connect to your PHP script.
Example:
public class Login {
...
private static final String LOGIN_URL = "http://XXX.XXX.X.XX/Example/login.php";
...
// Invoke by Intent activity by Login class
class AttemptLogin extends AsyncTask<String, String, Integer> {
...
protected void onPreExecute() {
....
}
protected Integer doInBackground() {
....
// Getting product details by making HTTP request
JSONObject json = jsonParser.makeHttpRequest(LOGIN_URL, "POST",
params);
....
}
protected void onPostExecute() {
....
}
}
The XXX.XXX.X.XX is the local IP address of your computer, which means when your mobile is connected on the same network as your computer, the IP address is the computer local IP address. Do not put in localhost. It won't work.
Instead of using "Localhost" use 10.0.2.2. Hope it helps!

Android client server

I have done lots of research on this and tried every method out there to get it to work. I have a C# server that accepts communication on the socket 192.168.0.101:18250. I have the following code (below) and it is the main Activity of the app. The way i coded it is that everything is in the onCreate method so the socket should connect as soon as the app is started, but on my server i dont see it connecting. The server is flawless and i assume there is no problem with it. I also tried an app from the market to see if my phone could even manage to connect to the server and from that app it did communicate through the socket just fine. This is the code i threw together in minutes to test out the socket connection, but no matter what i try the socket just wont connect. And none of the exceptions are thrown either!
import java.io.*;
import java.net.*;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.*;
public class ClientServerTestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
InetAddress addr = InetAddress.getByName("192.168.0.101");
int port = 18250;
// This constructor will block until the connection succeeds
Socket socket = new Socket(addr, port);
socket.getOutputStream();
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
wr.write("Hello World");
wr.flush();
} catch (UnknownHostException e) {
TextView t=(TextView)findViewById(R.id.textView1);
t.setText(t.getText() + e.getMessage() + "\r\n");
} catch (IOException e) {
TextView t=(TextView)findViewById(R.id.textView1);
t.setText(t.getText() + e.getMessage() + "\r\n");
}
}
}
The problem was not in the code, the problem was in the manifest. I had to add this line to the manifest to grant the application permission to open Network Sockets.
<uses-permission android:name="android.permission.INTERNET" />
Hope it helps someone out! :)

Categories

Resources