你还在用第三方的框架实现聊天和消息推送?快快试试吧
Socket.IO(官网)介绍
是一个跨平台的聊天框架,可以实现 web 端和移动端的实时聊天,简单说就是用来做聊天和消息推送的。最初以为项目做消息推送会直接使用第三方的,比如小米、极光啥的,但是,架构师说我们不用第三方的,自己要搭建消息推送,Socket.io技术很成熟了。所以就这样开始了Socket.io的学习之路。第一次接触Socket.io以为很难做,因为不了解,加上能找的资源有限(上网查找的都是英文资料,有关于Android端的Socke.io更是少之又少,除非你去stackoverflow里面去找,英语还得好),所以写篇文章记录下实现该功能流程以及遇到的问题。
官方Demo,Github的Demo,这两个 demo 都是一个聊天室,可以在里面聊天,刚开始弄这个的时候发现有好多哥们在那里,还找几个一起在做聊天功能的小伙伴,快快下载试试吧。
本文不说服务端的搭建和web端的实现,只是来说说 Android 端如何使用Socket.io实现消息推送功能。
(1)导包
Android Studio
导包,一共有两种情况(PS: Eclipse
用户也不要哭,下面会教你怎样获取到 JAR
)
第一种情况
compile 'com.github.nkzawa:socket.io-client:0.3.0'
-
第二种情况
compile ('io.socket:socket.io-client:0.7.0') { // excluding org.json which is provided by Android exclude group: 'org.json', module: 'json' }
注意:两个包的区别,如果你的项目没有用到 Https
,那么你可以使用两个当中的一个。如果有用到 Https
,那么你就要用二个包,不然你会连接不上 Https
的,具体的连接方式,以下会介绍。
第一种情况的导包获取到的 JAR
形式
第二种情况的导包获取到的 JAR
形式
PS: Android Studio
用户直接跳过(如果你想看看你的Studio下载的 JAR
放在那里也可以看看)。Eclipse
用户获取 Jar
,如果你会去远程仓库下载 Jar
,那么你就去吧,也就是几个 JAR
而已,不然的话你还是得借助 Android Studio
来获取 Jar
。
用Studio导入包后找到你的
External Libraries
,选中你的 JAR ,如engine.io-client-0.7.0
点击右键,点击Library Properties
,会弹出一个对话框,Copy 这个URL,打开我的电脑
,粘贴到导航栏点击确定就可以看到你的JAR
了,但是,这个JAR
是一个资源文件的JAR
,里面有源码的,我们不需要这个,点击back后退,一般会有三个文件夹,其中的一个就是你需要的JAR
了。流程图如下:
(2)代码使用
导完包剩下的就是代码的使用了。由于 Socket.io
封装得很好,所以我们能用到的类和方法不多,也就几个而已。
- 获取
Socket
和设置 url :mSocket = IO.socket( "http://192.168.205.125:10443" );
- 连接
mSocket.mSocket.connect();
。 - 发送消息
mSocket.emit( "newMessage", data );
,这里需要注意的是: data 是JSONObject
的类。 - 消息监听
mSocket.on( Socket.EVENT_CONNECT, onConnect );// 连接成功
- 断开连接
mSocket.disconnect();
。 - 断开消息监听
mSocket.off( Socket.EVENT_CONNECT, onConnect );
就是这么几个方法就可以实现消息推送或者实现聊天了。由于本文主要是实现消息推送的功能,所以把主要的代码放在了 Service
,顺便把流程写一下,方便初学者学习。
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
public class MessagePushService extends Service {
private static final String TAG = MessagePushService.class.getSimpleName();
private Socket mSocket;
private boolean isConnected;
/**
* 初始化Socket,Https的连接方式
*/
private void initSocketHttps() {
SSLContext sc = null;
TrustManager[] trustCerts = new TrustManager[] { new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted( X509Certificate[] chain, String authType )
throws CertificateException {
}
@Override
public void checkClientTrusted( X509Certificate[] chain, String authType )
throws CertificateException {
}
} };
try {
sc = SSLContext.getInstance( "TLS" );
sc.init( null, trustCerts, null );
IO.Options opts = new IO.Options();
opts.sslContext = sc;
opts.hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify( String s, SSLSession sslSession ) {
return true;
}
};
mSocket = IO.socket( "https://192.168.205.125:10443", opts );
} catch ( NoSuchAlgorithmException e ) {
e.printStackTrace();
} catch ( KeyManagementException e ) {
e.printStackTrace();
} catch ( URISyntaxException e ) {
e.printStackTrace();
}
}
/**
* 初始化Socket,Http的连接方式
*/
private void initSocketHttp() {
try {
mSocket = IO.socket( "http://192.168.205.125:10443" ); // 初始化Socket
} catch ( URISyntaxException e ) {
e.printStackTrace();
}
}
private void connectSocket() {
try {
mSocket.connect();
JSONObject jsonObject = new JSONObject();
jsonObject.put( "userName", "小王" ); // 这里一般是设置登录名
mSocket.emit( "loginName", jsonObject ); // 发送登录人
} catch ( JSONException e ) {
e.printStackTrace();
}
mSocket.on( Socket.EVENT_CONNECT, onConnect );// 连接成功
mSocket.on( Socket.EVENT_DISCONNECT, onDisconnect );// 断开连接
mSocket.on( Socket.EVENT_CONNECT_ERROR, onConnectError );// 连接异常
mSocket.on( Socket.EVENT_CONNECT_TIMEOUT, onConnectTimeoutError );// 连接超时
mSocket.on( "newMessage", onConnectMsg );// 监听消息事件回调
}
private void disConnectSocket() {
mSocket.disconnect();
mSocket.off( Socket.EVENT_CONNECT, onConnect );// 连接成功
mSocket.off( Socket.EVENT_DISCONNECT, onDisconnect );// 断开连接
mSocket.off( Socket.EVENT_CONNECT_ERROR, onConnectError );// 连接异常
mSocket.off( Socket.EVENT_CONNECT_TIMEOUT, onConnectTimeoutError );// 连接超时
mSocket.off( "newMessage", onConnectMsg );// 监听消息事件回调
}
private Emitter.Listener onConnectMsg = new Emitter.Listener() {
@Override
public void call( final Object... args ) {
// 在这里处理你的消息
Log.e( TAG, "服务器返回来的消息 : " + args[0] );
}
};
/**
* 实现消息回调接口
*/
private Emitter.Listener onConnect = new Emitter.Listener() {
@Override
public void call( final Object... args ) {
Log.e( TAG, "连接成功 " + args[0] );
if (!isConnected) { // 如果已经断开,重新发送
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put( "userName", "小王" ); // 这里一般是设置登录名
mSocket.emit( "loginName", jsonObject ); // 发送登录人
} catch ( JSONException e ) {
e.printStackTrace();
}
isConnected = true;
}
}
};
private Emitter.Listener onDisconnect = new Emitter.Listener() {
@Override
public void call( Object... args ) {
Log.e( TAG, "断开连接 " + args[0] );
isConnected = false;
}
};
private Emitter.Listener onConnectError = new Emitter.Listener() {
@Override
public void call( final Object... args ) {
Log.e( TAG, "连接 失败" + args[0] );
}
};
private Emitter.Listener onConnectTimeoutError = new Emitter.Listener() {
@Override
public void call( final Object... args ) {
Log.e( TAG, "连接 超时" + args[0] );
}
};
@Nullable
@Override
public IBinder onBind( Intent intent ) {
return null;
}
}
就这样完成了一个消息推送,不需要集成什么东西,也不用受制于人。