1.导入Java-WebSocket依赖
implementation "org.java-websocket:Java-WebSocket:1.5.2"
2.AndroidManifest 添加权限和service 代码
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service android:name=".WebSocketService"></service>
3.服务包含心跳检测和连接操作
public class WebSocketService extends Service {
private final static String TAG = "WebSocketService";
public JWebSocketClient client;
private JWebSocketClientBinder mBinder = new JWebSocketClientBinder();
private final static int GRAY_SERVICE_ID = 1001;
private static final long CLOSE_RECON_TIME = 15000;//连接断开或者连接错误立即重连
private Notification notification;
//用于Activity和service通讯
public class JWebSocketClientBinder extends Binder {
public WebSocketService getService() {
return WebSocketService.this;
}
}
//灰色保活
public static class GrayInnerService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(GRAY_SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//初始化WebSocket
initSocketClient();
mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);//开启心跳检测
//设置service为前台服务,提高优先级
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
//Android4.3以下 ,隐藏Notification上的图标
startForeground(GRAY_SERVICE_ID, new Notification());
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
//Android4.3 - Android8.0,隐藏Notification上的图标
Intent innerIntent = new Intent(this, GrayInnerService.class);
startService(innerIntent);
startForeground(GRAY_SERVICE_ID, new Notification());
} else {
Intent nfIntent = new Intent(this, MainActivity.class);
@SuppressLint("UnspecifiedImmutableFlag") Notification.Builder builder = new Notification.Builder(this.getApplicationContext())
.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent
.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
.setPriority(Notification.PRIORITY_MIN)
.setContentTitle(getResources().getString(R.string.app_name))
.setContentText("正在前台运行") // 设置上下文内容
.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
//修改安卓8.1以上系统报错
NotificationChannel notificationChannel = new NotificationChannel("1", "CHANNEL_ONE_NAME", NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(false);//如果使用中的设备支持通知灯,则说明此通知通道是否应显示灯
notificationChannel.setShowBadge(false);//是否显示角标
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(notificationChannel);
builder.setChannelId("1");
}
// 获取构建好的Notification
notification = builder.build();
notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
startForeground(GRAY_SERVICE_ID, notification);
}
return START_STICKY;
}
//这里是处理webscoket
private void initSocketClient() {
String url = "ws://端口号:ip地址"; //协议标识符是ws
//ws://172.18.130.52:8089/webSocket/notice/117
//协议标识符是ws
//(如果加密,则为wss),服务器网址就是 URL。 此处增加了请求头不需要的将map去掉即可
URI uri = URI.create(url);
HashMap<String, String> map = new HashMap<>();
map.put("Authorization","eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjMyMjUwNTAzLTBlZmEtNDM5Mi1hYTQwLWRjNzk4YzE5M2Y3MSJ9.9mIXUU7UtdGm8ze6KhfSaeBPmeCelzd1RQn1B7akK-CF38MwVPwjqaknasjMiDI4WBUzX_2PRw2rQaYuOiSjlw");
client = new JWebSocketClient(uri,map) {
@Override
public void onMessage(String message) {
//message就是接收到的消息
Log.d(TAG, "WebSocketService收到的消息:" + message);
//这里我通过EvenBus获取接收的消息并更新ui
//EventBus.getDefault().post(new WebSocketEvent(message));
}
@Override
public void onOpen(ServerHandshake handShakeData) {//在webSocket连接开启时调用
//EventBus.getDefault().post("WebSocket 连接成功");
Log.d(TAG, "WebSocket 连接成功" );
}
@Override
public void onClose(int code, String reason, boolean remote) {//在连接断开时调用
Log.d(TAG, "onClose() 连接断开_reason:" + reason );
//EventBus.getDefault().post("onClose() 连接断开_reason:" + reason );
mHandler.removeCallbacks(heartBeatRunnable);
mHandler.postDelayed(heartBeatRunnable, CLOSE_RECON_TIME);//开启心跳检测
}
@Override
public void onError(Exception ex) {//在连接出错时调用
//EventBus.getDefault().post("onError() 连接出错:" + ex.getMessage() );
Log.d(TAG, "onError() 连接出错:" + ex.getMessage() );
mHandler.removeCallbacks(heartBeatRunnable);
mHandler.postDelayed(heartBeatRunnable, CLOSE_RECON_TIME);//开启心跳检测
}
};
connect();
}
/**
* 连接WebSocket
*/
private void connect() {
new Thread() {
@Override
public void run() {
try {
//connectBlocking多出一个等待操作,会先连接再发送,否则未连接发送会报错
client.connectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
/**
* 发送消息
*/
public void sendMsg(String msg) {
if (null != client) {
try {
client.send(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
closeConnect();
super.onDestroy();
}
/**
* 断开连接
*/
public void closeConnect() {
mHandler.removeCallbacks(heartBeatRunnable);
try {
if (null != client) {
client.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
client = null;
}
}
// -------------------------------------WebSocket心跳检测------------------------------------------------
private static final long HEART_BEAT_RATE = 5 * 1000;
//每隔10秒进行一次对长连接的心跳检测
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
if (client != null) {
if (client.isClosed()) {
reconnectWs();
Log.d(TAG, "心跳包检测WebSocket连接状态:已关闭" );
//EventBus.getDefault().post("WebSocket 已关闭");
} else if (client.isOpen()) {
Log.d(TAG, "心跳包检测WebSocket连接状态:已连接" );
//EventBus.getDefault().post("WebSocket 已连接");
} else {
//EventBus.getDefault().post("WebSocket 已断开");
Log.d(TAG, "心跳包检测WebSocket连接状态:已断开" );
}
} else {
//如果client已为空,重新初始化连接
initSocketClient();
Log.d(TAG, "心跳包检测WebSocket连接状态:client已为空,重新初始化连接" );
}
//每隔一定的时间,对长连接进行一次心跳检测
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
/**
* 开启重连
*/
private void reconnectWs() {
mHandler.removeCallbacks(heartBeatRunnable);
new Thread() {
@Override
public void run() {
try {
Log.d(TAG, "开启重连" );
client.reconnectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public class AuxiliaryService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startNotification();
return super.onStartCommand(intent, flags, startId);
}
/** 启动通知*/
private void startNotification(){
Notification notification = new Notification();
this.startForeground(GRAY_SERVICE_ID, notification);
stopSelf(); //关键 如果AuxiliaryService 没有与什么组件绑定 系统就会回收
stopForeground(true);
}
}
}
4.工具类
public class JWebSocketClient extends WebSocketClient {
public JWebSocketClient(URI serverUri ,Map<String,String> map) {
super(serverUri, new Draft_6455(),map);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.e("JWebSocketClient", "onOpen()");
//ToastUtils.show(getmContext(),"onOpen()");
}
@Override
public void onMessage(String message) {
Log.e("JWebSocketClient", "onMessage():"+message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.e("JWebSocketClient", "onClose()");
//ToastUtils.show(getmContext(),"onClose()");
}
@Override
public void onError(Exception ex) {
Log.e("JWebSocketClient", "onError()"+ex.getMessage());
//ToastUtils.show(getmContext(),"onError()");
}
}
5.在appliction启动也可以在其他地方看需求别忘了在清单文件注册
public class App extends Application {
public static Context mContext;
public WebSocketService mWebSocketService;
private final static String TAG = "Application";
private static final String DEVICE_TOKEN = "device_token";//设备token
@Override
public void onCreate() {
super.onCreate();
mContext=this;
//开启
startWebSocketService(DEVICE_TOKEN);
}
private static final long HEART_BEAT_RATE = 5 * 1000;//每隔1分钟发送空消息保持WebSocket长连接
public static Context getmContext() {
return mContext;
}
private Handler mHandler = new Handler();
private Runnable webSocketRunnable = new Runnable() {
@Override
public void run() {
if (mWebSocketService != null &&
mWebSocketService.client != null && mWebSocketService.client.isOpen()) {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("from","");
jsonObject.put("to", "");
mWebSocketService.sendMsg(jsonObject.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
//每隔一定的时间,对长连接进行一次心跳检测
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
public WebSocketService getWebSocketService() {
return mWebSocketService;
}
/**
* 开启并绑定WebSocket服务
*/
public void startWebSocketService(String deviceToken) {
Intent bindIntent = new Intent(this, WebSocketService.class);
bindIntent.putExtra(DEVICE_TOKEN, deviceToken);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//android8.0以上通过startForegroundService启动service
startForegroundService(bindIntent);
} else {
startService(bindIntent);
}
bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
mHandler.removeCallbacks(webSocketRunnable);
mHandler.postDelayed(webSocketRunnable, HEART_BEAT_RATE);//开启心跳检测
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//服务与活动成功绑定
mWebSocketService = ((WebSocketService.JWebSocketClientBinder) iBinder).getService();
Log.d(TAG, "WebSocket服务与Application成功绑定");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
//服务与活动断开
mWebSocketService = null;
Log.d(TAG, "WebSocket服务与Application成功断开: ");
}
};
}
6.至此就可简单实现Android端的代码后台有需要demo的可以私聊我