web-dev-qa-db-fra.com

Android Application se connectant au serveur Node.js à l'aide de Socket.io

J'ai du mal à obtenir mon Android pour me connecter à un serveur de chat socket.io. J'utilise socket.io-Java-client créé par Gottox qui se trouve ici: - https://github.com/Gottox/socket.io-Java-client

Le serveur s'exécute localement sur le port 7000. J'utilise l'émulateur Android, donc j'utilise 10.0.2.2:7000 pour accéder au serveur.

Toute aide serait appréciée, je n'ai pas beaucoup d'expérience avec SSL. Si je trouve une solution de travail, je la publierai également.

Serveur Node.js

var express = require('express');
var app = express();
var server = require('http').createServer(app).listen(7000);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(client){
    client.on('message', function(err, msg){
        client.broadcast.emit('message', msg);
    });
 });

package.json

{
  "name": "simplechat",
  "version": "0.0.1",
  "main": "app.js",
  "dependencies": {
    "express" : "~4.0.0",
    "socket.io" : "~0.9.13"
  }
}

Android: SendMessageActivity

public class SendMessageActivity extends Activity {

    private static final String SERVER_ADDRESS = "https://10.0.2.2:7000";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send_message);

        System.out.println("Sever: " + SERVER_ADDRESS);

        try {
            SocketIO socket = new SocketIO(new URL(SERVER_ADDRESS), new IOCallback() {
                @Override
                public void onDisconnect() {
                    System.out.println("disconnected");
                }

                @Override
                public void onConnect() {
                    System.out.println("connected");
                }

                @Override
                public void onMessage(String s, IOAcknowledge ioAcknowledge) {
                }

                @Override
                public void onMessage(JSONObject jsonObject, IOAcknowledge ioAcknowledge) {
                }

                @Override
                public void on(String event, IOAcknowledge ioAcknowledge, Object... objects) {
                }

                @Override
                public void onError(SocketIOException e) {
                    e.printStackTrace();
                }
            });

        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

Autorisations Android

<uses-permission
    Android:name="Android.permission.INTERNET">
</uses-permission>

Code d'erreur

08-09 16:07:28.224    8411-8441/com.example.puma.chatexample W/System.err﹕ io.socket.SocketIOException: Error while handshaking
08-09 16:07:28.225    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection.handshake(IOConnection.Java:322)
08-09 16:07:28.225    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection.access$600(IOConnection.Java:39)
08-09 16:07:28.225    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection$ConnectThread.run(IOConnection.Java:199)
08-09 16:07:28.226    8411-8441/com.example.puma.chatexample W/System.err﹕ Caused by: Java.lang.NullPointerException: Attempt to invoke virtual method 'javax.net.ssl.SSLSocketFactory javax.net.ssl.SSLContext.getSocketFactory()' on a null object reference
08-09 16:07:28.226    8411-8441/com.example.puma.chatexample W/System.err﹕ at io.socket.IOConnection.handshake(IOConnection.Java:302)
08-09 16:07:28.227    8411-8441/com.example.puma.chatexample W/System.err﹕ ... 2 more
28
Puma

J'ai en fait résolu le problème. J'ai utilisé l'IP locale de mon PC http://192.168.0.xxx:70 et l'application a pu se connecter au serveur de chat à partir de l'émulateur. Je ne sais pas pourquoi cela fonctionne, mais cela pourrait aider quelqu'un à l'avenir :)

Mise à jour:

C'est ainsi que j'ai fini par structurer le projet. J'ai créé une classe singleton pour gérer les connexions de socket Android (vous pouvez également le faire en tant que service). Lors de la réception d'un message, la classe singleton diffuse une intention au reste de l'application. La l'intention est ensuite captée par un récepteur de diffusion dans l'activité concernée.

Côté Android (singleton):

public class SocketSingleton {

    private static SocketSingleton instance;
    private static final String SERVER_ADDRESS = "http://1.2.3.4:1234";
    private SocketIO socket;
    private Context context;

    public static SocketSingleton get(Context context){
        if(instance == null){
            instance = getSync(context);
        }
        instance.context = context;
        return instance;
    }

    public static synchronized SocketSingleton getSync(Context context){
        if (instance == null) {
            instance = new SocketSingleton(context);
        }
        return instance;
    }

    public SocketIO getSocket(){
        return this.socket;
    }

    private SocketSingleton(Context context){
        this.context = context;
        this.socket = getChatServerSocket();
        this.friends = new ArrayList<Friend>();
    }

    private SocketIO getChatServerSocket(){
        try {
            SocketIO socket = new SocketIO(new URL(SERVER_ADDRESS), new IOCallback() {
                @Override
                public void onDisconnect() {
                    System.out.println("disconnected");
                }

                @Override
                public void onConnect() {
                    System.out.println("connected");
                }

                @Override
                public void on(String event, IOAcknowledge ioAcknowledge, Object... objects) {
                    if (event.equals("chatMessage")) {
                        JSONObject json = (JSONObject) objects[0];
                        ChatMessage chatMessage = new ChatMessage(json);

                        Intent intent = new Intent();
                        intent.setAction("newChatMessage");
                        intent.putExtra("chatMessage", chatMessage);
                        context.sendBroadcast(intent);
                    }
                }
                @Override
                public void onError(SocketIOException e) {
                    e.printStackTrace();
                }
            });
            return socket;
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
        return null;
    }
}

Côté Android (activité):

public class ChatActivity extends Activity {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chat);
    IntentFilter newChatMessageFilter = new IntentFilter("newChatMessage");
    this.registerReceiver(new MessageReceiver(), newChatMessageFilter);

    ...

    public class MessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            final ChatMessage chatMessage =(ChatMessage) intent.getExtras().get("chatMessage");
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mAdapter.add(chatMessage);
                    mAdapter.notifyDataSetChanged();
                }
            });
        }
    }
} 

Côté serveur:

var express = require('express');
var app = express();
var server = require('http').createServer(app).listen(1234);
var io = require('socket.io').listen(server);

io.sockets.on('connection', function(client){

    console.log("client connected: " + client.id);

    client.on("sendTo", function(chatMessage){
        console.log("Message From: " + chatMessage.fromName);
        console.log("Message To: " + chatMessage.toName);


        io.sockets.socket(chatMessage.toClientID).emit("chatMessage", {"fromName" : chatMessage.fromName,
                                                                    "toName" : chatMessage.toName,
                                                                    "toClientID" : chatMessage.toClientID,
                                                                    "msg" : chatMessage.msg});

    });
});
35
Puma

Je sais que cela ne répond pas vraiment aux messages de l'OP, mais pour ceux qui pourraient être intéressés, c'est un tutoriel que j'ai fait pour faire communiquer votre Android avec un serveur Node.js - sans aucune bibliothèque supplémentaire -:

https://causeyourestuck.io/2016/04/27/node-js-Android-tcpip/

Voici un avant-goût de ce à quoi il ressemble à la fin:

Client socket = new Client("192.168.0.8", 1234);
socket.setOnEventOccurred(new Client.OnEventOccurred() {
    @Override
    public void onMessage(String message) {
    }

    @Override
    public void onConnected(Socket socket) {
        socket.send("Hello World!");
        socket.disconnect();
    }

    @Override
    public void onDisconnected(Socket socket, String message) {
    }
});

socket.connect();
7
Omar Aflak

Puma a déjà expliqué comment mettre en œuvre une connexion socket à l'aide de SocketIO. Cela n'a rien de nouveau à apporter. Pourtant, c'est une tentative pour aider les autres débutants, tout en introduisant également l'implémentation de la bibliothèque Socket.io Java.

Socket.IO a son propre Java implémentation sur Github , que vous pouvez suivre pour créer une application socket pour Android/Java.

Côté Android:

Incluez ceci dans votre gradle de build

compile ('io.socket:socket.io-client:0.8.3') {
    // excluding org.json which is provided by Android
    exclude group: 'org.json', module: 'json'
}

Fournissez l'autorisation dans votre application:

<uses-permission Android:name="Android.permission.INTERNET" />

Code Android: La structure du code est similaire à la façon dont vous coderiez dans Node. Le message dans socket.on est similaire à socket.on du nœud ('message', ...)

import io.socket.client.Socket;
import io.socket.client.IO;
import io.socket.emitter.Emitter;

final Socket socket;
try{
socket = IO.socket("http://192.168.1.1:8080");

socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {

    @Override
    public void call(Object... args) {
        socket.emit("message", "hi");
        socket.disconnect();
    }

}).on("message", new Emitter.Listener() {
        //message is the keyword for communication exchanges
    @Override
    public void call(Object... args) {
        socket.emit("message", "hi");
    }

}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

    @Override
    public void call(Object... args) {}

});
    socket.connect();

}
catch(Exception e){

}

Côté Node.js

Créez des sockets normaux en utilisant socket.io

4
adityah

Votre réseau d'émulation est différent de celui de votre PC, comme je l'ai entendu. Donc, si vous pouviez changer, essayez ceci sur un téléphone réel connecté au même réseau que votre PC.

Vous ne pourrez probablement pas ping 10.0.2.2 de votre émulateur ou inversement de votre PC vers l'émulateur.

3
someguy234