I am trying to connect with my Node.js Socket.IO server via an Android app. The console log shows that the phone connects with the server but when I try to emit a message from Android, the server does not give any output on the log console. I have read through the sample Socket.IO Android app but I am not able to figure out what's the problem...
Below lies my code...
Client Android
mSocket.connect();
private void attemptSend() {
JSONObject jsonObject1 = new JSONObject();
try {
jsonObject1 = new JSONObject();
jsonObject1.put("message","This is a test");
} catch (JSONException e) {
e.printStackTrace();
}
mSocket.emit("test",jsonObject1);
Log.d("TAG", "Sent");
}
Server Node.js
io.on('connection', function(socket) {
console.log('User Connected');
socket.on('test', function(data) {
console.log(data.message)
}
});
As stated in the comments under the question, the URL that I used while connecting to the server was erroneous. After fixing the URL, the app started working as expected.
Related
I currently try to write a android app to setup and controll a ESP8266 on which micropython runs.
On the micropython server I initialize a websocket like this:
def __init__(self, task_manager, setup_mode):
address = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
self._socket = socket.socket()
self._socket.bind(address)
self._socket.listen(1)
self._socket.setblocking(False)
self._socket.settimeout(5)
self._task_manager = task_manager
self._setup_mode = setup_mode
print('New Socket is listening on: ', address)
And then simple listen to incoming connections like this, and then react to the incoming messages. Also the listing is looped to allow the microcontroller logic to update every 5 seconds.
client, address = self._socket.accept()
print("New request from:", address)
Everything is working fine when I send test request using python from my PC. For example a simple request would be something like this:
data = json.dumps({'load': {'type': "is_lighthub", 'data': {}}})
response = requests.post(ip, json=data)
However when I try to make the same post request using OkHttp from an android app, then there is no incoming connection at the ESP.
Here is the android java code:
private void addIfLighthub(final InetAddress address) {
try {
RequestBody body = RequestBody.create(JSON, "{\"load\": {\"type\": \"is_lighthub_server\", \"data\": {}}");
Request request = new Request.Builder()
.url("http://" + address.getHostAddress())
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
final JSONObject myResponse = new JSONObject(response.body().string());
if((boolean)myResponse.get("is_lighthub")) {
onlineDeviceList.add(address);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
} catch (JSONException jsonException) {
System.out.println(jsonException.getMessage());
}
}
The odd thing however is that that sample code, if provided with for example the address of my router, does receive the routers default html site ...
So, am I missing something? I fairly new to networking but a simple post request from the phone should be the same as from a python sample code, right?
Or is there a error in my java function?
Thank you guys in advance for the help!
If fixed it myself!
The mistake was that the python test client sended the json seperate, while the okhttp client sended both in one piece.
That made the server timeout while waiting for a second message ...
I'm trying to send a downstream push notification from the android client for practice only.
However, with this code:
private void send() {
String urlString = "https://fcm.googleapis.com/fcm/send";
JSONObject jsonObjects = new JSONObject();
try {
jsonObjects.put("title", titleET.getText().toString());
jsonObjects.put("body", textET.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
RequestBody body = RequestBody.create(JSON, jsonObjects.toString());
Request req = new Request.Builder()
.url(urlString)
.post(body)
.addHeader("Authorization","key=censored")
.build();
try {
Response res = client.newCall(req).execute();
if (!res.isSuccessful()) {
throw new UnknownError("Error: " + res.code() + " " + res.body().string());
}
Log.d("MainActivity", res.body().toString());
} catch (IOException e) {
send();
}
}
As you can see, I'm not doing
jsonObjects.put("to","something");
That's because I don't want to send it to someone specifically, but to the whole application. If I don't put a "to" into the json, I get an error.
So, how can I send it to my whole application?
You must always specify either a device token, a device group id or a topic. There is no option to send untargeted messages with Firebase Cloud Messaging.
You send notifications to all users of one app in a project from the Firebase Notifications console. But there is no public API to call this functionality from your own code.
I am developing an Android application, and I need to send a message from the application to the Java Server.
Java Server works like this:
thread = new Thread(){
public void run(){
System.out.println("Server is running...");
try {
ServerSocket socket = new ServerSocket(7000);
while(true){
Socket s = socket.accept();
DataInputStream dis = new DataInputStream(s.getInputStream());
System.out.println("Received from client: " + dis.readUTF());
dis.close();
s.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
thread.start();
In my application I send the message in this way:
mt = new Thread() {
public void run() {
try {
Socket socket = new Socket("192.168.1.100", 7000);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(song_field.getText().toString());
dos.flush();
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
mt.start();
Toast.makeText(context, "Your Message is sent. Thank you!", Toast.LENGTH_SHORT).show();
I can send the message with emulator and my phone successfully, since they are connected to the same wifi connection, but if the device is not connected to the same network, message is not sent to the server. I want everybody to be able to send message to my computer server regardless of their internet connection.
How can I fix this problem?
In general you'll need to use something like Web Sockets to achieve what you're trying to do where, as would typically be the case, client/server are on different networks. There are a few different Web Socket implementations e.g. https://medium.com/square-corner-blog/web-sockets-now-shipping-in-okhttp-3-5-463a9eec82d1#.w9hrc1icw
EDIT
I initially misread question and thought you were trying to asynchronously send message from server to client (which would require something like Web Sockets). If you are just making requests from client to server then a typical solution would be to expose REST API from your server (and using something like Retrofit to make requests from client).
Is there any way to send Upstream notification message through FCM from one android device to another devices connected with Firebase database.
I know that XMPP server can then receive the upstream messages and send the notifications to the other devices.To receive messages sent with the upstream API i need to implement an XMPP server but there is any other way???
Is there any way to send Upstream notification message through FCM
from one android device to another devices connected with Firebase
database?
Currently it's NOT possible to send messages directly from one device to another.
(or at least it's not possible without introducing a HUGE security vulnerability: more details below)
Full details:
Sending messages to a user device is a pretty serious action!
based on the payload a message can result in spam, phishing, execution of internal methods.
You want this operation to be allowed only be trusted entities, this is why the FCM send API requires the SERVER-API-KEY in the authentication header.
Adding the SERVER-API-KEY in your app code (or communicating it to the app in some other way) IS NOT SAFE. This because apk can be extracted, decompiled, inspected, executed on emulators, executed under debugging and so on.
The best way to implement this today: is to have some sort of server between the two devices:
[DeviceA] -- please send message to B --> [SERVER] -- fcmSendAPI --> [DeviceB]
The server can be as simple as a PHP page, or a more complex XMPP implementation.
An example in Node.js can be found here:
Sending notifications between devices with Firebase Database and Cloud Messaging
Finally, after 2 months of trying to maintain reliable server script myself, I suddenly found OneSignal. It's completely free, supports device-to-device push messages on iOS, Android, WP and browsers.
Hope, I won't get flag for promotion spam, but it's currently the only (and easiest) way to be completely "backendless".
Also, it's completely secure way. Nobody can send push unless he knows special OS user id, which you can store in Firebase Database protected by rules.
UPD: It's not a replacement for Firebase. It has only push service and nothing else
UPD2: Firebase now has Functions, and examples of it usage has sending FCM. You now don't need any other server or service. Read more in official samples https://github.com/firebase/functions-samples
After lots of try finally i got one solution and its work perfectly
Step 1 :Include two library.
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.google.firebase:firebase-messaging:9.2.0'
Step 2 : In your MainActivity or from where you want to send notifications.
OkHttpClient mClient = new OkHttpClient();
String refreshedToken = "";//add your user refresh tokens who are logged in with firebase.
JSONArray jsonArray = new JSONArray();
jsonArray.put(refreshedToken);
Step 3: Create one async task which sends notifications to all devices.
public void sendMessage(final JSONArray recipients, final String title, final String body, final String icon, final String message) {
new AsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... params) {
try {
JSONObject root = new JSONObject();
JSONObject notification = new JSONObject();
notification.put("body", body);
notification.put("title", title);
notification.put("icon", icon);
JSONObject data = new JSONObject();
data.put("message", message);
root.put("notification", notification);
root.put("data", data);
root.put("registration_ids", recipients);
String result = postToFCM(root.toString());
Log.d("Main Activity", "Result: " + result);
return result;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject resultJson = new JSONObject(result);
int success, failure;
success = resultJson.getInt("success");
failure = resultJson.getInt("failure");
Toast.makeText(MainActivity.this, "Message Success: " + success + "Message Failed: " + failure, Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "Message Failed, Unknown error occurred.", Toast.LENGTH_LONG).show();
}
}
}.execute();
}
String postToFCM(String bodyString) throws IOException {
public static final String FCM_MESSAGE_URL = "https://fcm.googleapis.com/fcm/send";
final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(JSON, bodyString);
Request request = new Request.Builder()
.url(Url.FCM_MESSAGE_URL)
.post(body)
.addHeader("Authorization", "key=" + "your server key")
.build();
Response response = mClient.newCall(request).execute();
return response.body().string();
}
Step 4 : Call in onclick of your button
btnSend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMessage(jsonArray,"Hello","How r u","Http:\\google.com","My Name is Vishal");
}
});
I am using the Google Cloud Messaging (GCM) service for my Android app. I have implemented it according to all the rules, and it works. Well, almost.
Most often, I'd say in 60-70% of the cases I can successfully send a GCM message from my server, using the webservice as discussed on google webpages.
Normally, I get the following reply from the webservice, which indicates that I successfully sent the GCM message:
{
"multicast_id":8378088572050307085,
"success":1,
"failure":0,
"canonical_ids":0,
"results":
[
{
"message_id":"0:1363080282442710%7c4250c100000031"
}
]
}
This is saying: all OK, message sent.
However, in many cases I get a HTTP error when calling the webservice, that says:
Unable to read data from the transport connection: An established
connection was aborted by the software in your host machine.
This is the .NET message to tell me that calling a webservice (using HttpWebRequest and POST) failed.
This is some log messages that shows the problem:
This is the code I am using for calling the WS:
public static string SendMessage(string registrationId, string command, string extra, bool retry)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
request.Method = PostWebRequest;
request.KeepAlive = false;
GCMPostPacket json = new GCMPostPacket()
{
collapse_key = "1",
time_to_live = 60,
registration_ids = new List<string>(new string[] { registrationId }),
data = new GcmData()
{
message = command,
misc = extra
}
};
// Converting to JSON string
string jsonString = SICJsonProtocol.JSONHelper.Serialize<GCMPostPacket>(json);
byte[] byteArray = Encoding.UTF8.GetBytes(jsonString);
request.ContentType = "application/json";
request.ContentLength = byteArray.Length;
request.ProtocolVersion = HttpVersion.Version10;
request.Headers.Add(HttpRequestHeader.Authorization, "key=" + "MyVerySecretKey");
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
using (WebResponse response = request.GetResponse())
{
HttpStatusCode responseCode = ((HttpWebResponse)response).StatusCode;
if (responseCode.Equals(HttpStatusCode.Unauthorized) || responseCode.Equals(HttpStatusCode.Forbidden))
{
Console.WriteLine("Unauthorized - need new token");
}
else if (!responseCode.Equals(HttpStatusCode.OK))
{
Console.WriteLine("Response from web service not OK :");
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
}
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseLine = reader.ReadLine();
Console.WriteLine("************************");
Console.WriteLine("GCM send: " + responseCode + " | " + responseLine);
// This is the log shown in the image above
SRef.main.gui.ServiceUpdate("GCM send: " + responseCode + " | " + responseLine);
reader.Close();
response.Close();
return responseLine;
}
}
catch (Exception e)
{
// This is the log shown in the image above
SRef.main.gui.ServiceUpdate("Failed send GCM, " + (retry ? "retrying in 20 sec" : "not retrying") + ". Error=" + e.Message);
if (retry)
{
System.Threading.ThreadPool.QueueUserWorkItem(delegate(object obj)
{
try
{
System.Threading.Thread.Sleep(20000);
SendMessage(registrationId, command, extra, false);
}
catch (Exception ex)
{
}
});
}
return null;
}
}
Can anyone see if I am doing something wrong, or if I am missing something in general?
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
This error has nothing to do with GCM API in particular. It means that your client tried to contact the web service but the connection that was established has been severed in one of the network layers. Depending on where you get this error and the error message it could mean several things.
Your client decided to abort the connection due to a socket timeout. Increase the client read / socket timeout to improve the situation.
A load balancer that sits between the client and the server dropped the connection. Each party thinks that the other one dropped the connection.
Network timeouts are usually a huge pain since it is never clear where the connection was dropped and who dropped it. If increasing timeouts does not help I'd suggest sending the requests through a proxy that can sniff the HTTPS traffic (charles / TCPMON) or using Wireshark to see which packets are being dropped.
Your android app also has GCM monitoring that you can enable on the Statistics tab. Check if the GCM API reports a status message other than 200 OK on that graph. That will help narrow down the problem further. If there are no reports of status codes other than 200, it means GCM never got your API requests to begin with.