webscoket依赖
implementation "org.java-websocket:Java-WebSocket:1.4.0"
清单文件中加入相关权限及service
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.simin.webscoket">
<uses-permission android:name="android.permission.INTERNET" />
<!-- 解锁屏幕需要的权限 -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<!-- 申请电源锁需要的权限 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--震动权限-->
<uses-permission android:name="android.permission.VIBRATE" />
<!--android 9.0之后使用前台服务,需要添加权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<service
android:name="com.simin.webscoket.im.JWebSocketClientService"
android:enabled="true"
android:exported="true" />
<service
android:name="com.simin.webscoket.im.JWebSocketClientService$GrayInnerService"
android:enabled="true"
android:exported="false"
android:process=":gray" />
<activity
android:name="com.simin.webscoket.MainActivity"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
JWebSocketClientService
package com.simin.webscoket.im;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.simin.webscoket.MainActivity;
import com.simin.webscoket.R;
import com.simin.webscoket.util.Util;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import static android.support.v4.app.NotificationCompat.VISIBILITY_PUBLIC;
public class JWebSocketClientService extends Service {
public JWebSocketClient client;
private JWebSocketClientBinder mBinder = new JWebSocketClientBinder();
private final static int GRAY_SERVICE_ID = 1001;
//灰色保活
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;
}
}
PowerManager.WakeLock wakeLock;//锁屏唤醒
//获取电源锁,保持该服务在屏幕熄灭时仍然获取CPU时,保持运行
@SuppressLint("InvalidWakeLockTag")
private void acquireWakeLock() {
if (null == wakeLock) {
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "PostLocationService");
if (null != wakeLock) {
wakeLock.acquire();
}
}
}
//用于Activity和service通讯
public class JWebSocketClientBinder extends Binder {
public JWebSocketClientService getService() {
return JWebSocketClientService.this;
}
}
@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 < 18) {
//Android4.3以下 ,隐藏Notification上的图标
startForeground(GRAY_SERVICE_ID, new Notification());
} else if (Build.VERSION.SDK_INT > 18 && Build.VERSION.SDK_INT < 25) {
//Android4.3 - Android7.0,隐藏Notification上的图标
Intent innerIntent = new Intent(this, GrayInnerService.class);
startService(innerIntent);
startForeground(GRAY_SERVICE_ID, new Notification());
} else {
//Android7.0以上app启动后通知栏会出现一条"正在运行"的通知
startForeground(GRAY_SERVICE_ID, new Notification());
}
acquireWakeLock();
return START_STICKY;
}
@Override
public void onDestroy() {
closeConnect();
super.onDestroy();
}
public JWebSocketClientService() {
}
/**
* 初始化websocket连接
* "ws://192.168.10.10:5101"服务器地址
*/
private void initSocketClient() {
URI uri = URI.create("ws://192.168.10.10:5101");
client = new JWebSocketClient(uri) {
@Override
public void onMessage(String message) {
Log.e("JWebSocketClientService", "收到的消息:" + message);
Intent intent = new Intent();
intent.setAction("com.xch.servicecallback.content");
intent.putExtra("message", message);
sendBroadcast(intent);
checkLockAndShowNotification(message);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
super.onOpen(handshakedata);
Log.e("JWebSocketClientService", "websocket连接成功");
//发送connect给服务器表示连接
sendMsg("connect");
}
};
connect();
}
/**
* 连接websocket
*/
private void connect() {
new Thread() {
@Override
public void run() {
try {
//connectBlocking多出一个等待操作,会先连接再发送,否则未连接发送会报错
client.connectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
/**
* 发送消息
*
* @param msg
*/
public void sendMsg(String msg) {
if (null != client) {
Log.e("JWebSocketClientService", "发送的消息:" + msg);
client.send(msg);
//发送消息后每隔60秒心跳检测发送ping给服务器证明是连接状态
mHandler1.removeCallbacks(mRunnable);//重置计时器
mHandler1.postDelayed(mRunnable, 60000);
}
}
/**
* 断开连接
*/
private void closeConnect() {
try {
if (null != client) {
client.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
client = null;
}
}
// -----------------------------------消息通知--------------------------------------------------------
/**
* 检查锁屏状态,如果锁屏先点亮屏幕
*
* @param content
*/
private void checkLockAndShowNotification(String content) {
//管理锁屏的一个服务
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (km.inKeyguardRestrictedInputMode()) {//锁屏
//获取电源管理器对象
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
if (!pm.isScreenOn()) {
@SuppressLint("InvalidWakeLockTag") PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");
wl.acquire(); //点亮屏幕
wl.release(); //任务结束后释放
}
sendNotification(content);
} else {
sendNotification(content);
}
}
/**
* 发送通知
*
* @param content
*/
private void sendNotification(String content) {
Intent intent = new Intent();
intent.setClass(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this)
.setAutoCancel(true)
// 设置该通知优先级
.setPriority(Notification.PRIORITY_MAX)
.setSmallIcon(R.drawable.icon)
.setContentTitle("收到一条新消息")
.setContentText(content)
.setVisibility(VISIBILITY_PUBLIC)
.setWhen(System.currentTimeMillis())
// 向通知添加声音、闪灯和振动效果
.setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_ALL | Notification.DEFAULT_SOUND)
.setContentIntent(pendingIntent)
.build();
notifyManager.notify(1, notification);//id要保证唯一
}
// -------------------------------------websocket心跳检测------------------------------------------------
private static final long HEART_BEAT_RATE = 10 * 1000;//每隔10秒进行一次对长连接的心跳检测
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
Log.e("JWebSocketClientService", "心跳包检测websocket连接状态");
if (client != null) {
if (client.isClosed()) {
reconnectWs();
}
} else {
//如果client已为空,重新初始化连接
client = null;
initSocketClient();
}
//每隔一定的时间,对长连接进行一次心跳检测
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
// -------------------------------------websocket心跳检测60秒------------------------------------------------
private Handler mHandler1 = new Handler();
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
//开启心跳检测
System.out.println("心跳检测60秒发送ping给服务器");
client.send("ping");
//每隔一定的时间,心跳检测60秒
mHandler1.postDelayed(this, 60000);
}
};
/**
* 开启重连
*/
private void reconnectWs() {
mHandler.removeCallbacks(heartBeatRunnable);
new Thread() {
@Override
public void run() {
try {
Log.e("JWebSocketClientService", "开启重连");
client.reconnectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
JWebSocketClient
package com.simin.webscoket.im;
import android.util.Log;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
public class JWebSocketClient extends WebSocketClient {
public JWebSocketClient(URI serverUri) {
super(serverUri, new Draft_6455());
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.e("JWebSocketClient", "onOpen()");
}
@Override
public void onMessage(String message) {
Log.e("JWebSocketClient", "onMessage()");
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.e("JWebSocketClient", "onClose()");
}
@Override
public void onError(Exception ex) {
Log.e("JWebSocketClient", "onError()");
}
}
MainActivity
package com.simin.webscoket;
import android.annotation.TargetApi;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import com.simin.webscoket.adapter.Adapter_ChatMessage;
import com.simin.webscoket.im.JWebSocketClient;
import com.simin.webscoket.im.JWebSocketClientService;
import com.simin.webscoket.modle.ChatMessage;
import com.simin.webscoket.util.Util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Context mContext;
private JWebSocketClient client;
private JWebSocketClientService.JWebSocketClientBinder binder;
private JWebSocketClientService jWebSClientService;
private EditText et_content;
private ListView listView;
private Button btn_send;
private List<ChatMessage> chatMessageList = new ArrayList<>();//消息列表
private Adapter_ChatMessage adapter_chatMessage;
private ChatMessageReceiver chatMessageReceiver;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("MainActivity", "服务与活动成功绑定");
binder = (JWebSocketClientService.JWebSocketClientBinder) iBinder;
jWebSClientService = binder.getService();
client = jWebSClientService.client;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("MainActivity", "服务与活动成功断开");
}
};
private class ChatMessageReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String message=intent.getStringExtra("message");
ChatMessage chatMessage=new ChatMessage();
chatMessage.setContent(message);
chatMessage.setIsMeSend(0);
chatMessage.setIsRead(1);
chatMessage.setTime(System.currentTimeMillis()+"");
chatMessageList.add(chatMessage);
initChatMsgListView();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_main);
mContext=MainActivity.this;
//启动服务
startJWebSClientService();
//绑定服务
bindService();
//注册广播
doRegisterReceiver();
//检测通知是否开启
checkNotification(mContext);
findViewById();
initView();
}
/**
* 绑定服务
*/
private void bindService() {
Intent bindIntent = new Intent(mContext, JWebSocketClientService.class);
bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
}
/**
* 启动服务(websocket客户端服务)
*/
private void startJWebSClientService() {
Intent intent = new Intent(mContext, JWebSocketClientService.class);
startService(intent);
}
/**
* 动态注册广播
*/
private void doRegisterReceiver() {
chatMessageReceiver = new ChatMessageReceiver();
IntentFilter filter = new IntentFilter("com.xch.servicecallback.content");
registerReceiver(chatMessageReceiver, filter);
}
private void findViewById() {
listView = findViewById(R.id.chatmsg_listView);
btn_send = findViewById(R.id.btn_send);
et_content = findViewById(R.id.et_content);
btn_send.setOnClickListener(this);
}
private void initView() {
//监听输入框的变化
et_content.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (et_content.getText().toString().length() > 0) {
btn_send.setVisibility(View.VISIBLE);
} else {
btn_send.setVisibility(View.GONE);
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_send:
String content = et_content.getText().toString();
if (content.length() <= 0) {
Util.showToast(mContext, "消息不能为空哟");
return;
}
if (client != null && client.isOpen()) {
jWebSClientService.sendMsg(content);
//暂时将发送的消息加入消息列表,实际以发送成功为准(也就是服务器返回你发的消息时)
ChatMessage chatMessage=new ChatMessage();
chatMessage.setContent(content);
chatMessage.setIsMeSend(1);
chatMessage.setIsRead(1);
chatMessage.setTime(System.currentTimeMillis()+"");
chatMessageList.add(chatMessage);
initChatMsgListView();
et_content.setText("");
} else {
Util.showToast(mContext, "连接已断开,请稍等或重启App哟");
}
break;
default:
break;
}
}
private void initChatMsgListView(){
adapter_chatMessage = new Adapter_ChatMessage(mContext, chatMessageList);
listView.setAdapter(adapter_chatMessage);
listView.setSelection(chatMessageList.size());
}
/**
* 检测是否开启通知
*
* @param context
*/
private void checkNotification(final Context context) {
if (!isNotificationEnabled(context)) {
new AlertDialog.Builder(context).setTitle("温馨提示")
.setMessage("你还未开启系统通知,将影响消息的接收,要去开启吗?")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setNotification(context);
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).show();
}
}
/**
* 如果没有开启通知,跳转至设置界面
*
* @param context
*/
private void setNotification(Context context) {
Intent localIntent = new Intent();
//直接跳转到应用通知设置的代码:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
localIntent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
localIntent.putExtra("app_package", context.getPackageName());
localIntent.putExtra("app_uid", context.getApplicationInfo().uid);
} else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
localIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
localIntent.addCategory(Intent.CATEGORY_DEFAULT);
localIntent.setData(Uri.parse("package:" + context.getPackageName()));
} else {
//4.4以下没有从app跳转到应用通知设置页面的Action,可考虑跳转到应用详情页面,
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 9) {
localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
localIntent.setData(Uri.fromParts("package", context.getPackageName(), null));
} else if (Build.VERSION.SDK_INT <= 8) {
localIntent.setAction(Intent.ACTION_VIEW);
localIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
localIntent.putExtra("com.android.settings.ApplicationPkgName", context.getPackageName());
}
}
context.startActivity(localIntent);
}
/**
* 获取通知权限,监测是否开启了系统通知
*
* @param context
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private boolean isNotificationEnabled(Context context) {
String CHECK_OP_NO_THROW = "checkOpNoThrow";
String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo appInfo = context.getApplicationInfo();
String pkg = context.getApplicationContext().getPackageName();
int uid = appInfo.uid;
Class appOpsClass = null;
try {
appOpsClass = Class.forName(AppOpsManager.class.getName());
Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE,
String.class);
Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
int value = (Integer) opPostNotificationValue.get(Integer.class);
return ((Integer) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
具体代码请在demo链接中查找