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
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});
});
});
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();
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.
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){ }
Créez des sockets normaux en utilisant socket.io
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.