fix:
update:在线状态移到桌面,更换二维码
This commit is contained in:
2024-08-29 18:00:49 +08:00
parent 7ba8603363
commit a049a16738
8 changed files with 496 additions and 1 deletions

View File

@@ -28,6 +28,7 @@ android {
// 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
}
buildConfigField "String", "WEBSOCKET_URL", '"wss://led.aolelearn.com/wss/device"'
}
dataBinding {
@@ -175,6 +176,8 @@ dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'
//磁盘缓存
implementation 'com.jakewharton:disklrucache:2.0.2'
//Java WebSocket
implementation "org.java-websocket:Java-WebSocket:1.5.3"
//glide
implementation 'com.github.bumptech.glide:glide:4.13.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1'

View File

@@ -178,7 +178,21 @@
android:name=".alarm.AlarmService"
android:enabled="true"
android:exported="true" />
<service
android:name=".service.SocketService"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.SCREEN_OFF" />
<action android:name="android.intent.action.SCREEN_ON" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<action android:name="android.intent.action.FACTORY_RESET" />
<action android:name="android.intent.action.MASTER_CLEAR" />
<data android:scheme="package" />
</intent-filter>
</service>
<!-- <service-->
<!-- android:name=".service.main.MainService"-->
<!-- android:enabled="true"-->

View File

@@ -40,6 +40,7 @@ import com.uiui.zyos.fragment.user.UserFragment;
import com.uiui.zyos.jxw.JxwPackageConfig;
import com.uiui.zyos.manager.AmapManager;
import com.uiui.zyos.manager.RemoteManager;
import com.uiui.zyos.service.SocketService;
import com.uiui.zyos.utils.ApkUtils;
import com.uiui.zyos.utils.OpenApkUtils;
import com.uiui.zyos.utils.Utils;
@@ -193,6 +194,12 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
// } catch (Exception e) {
// Log.e(TAG, "openPackageWithArgs: " + e.getMessage());
// }
Intent intent = new Intent(MainActivity.this, SocketService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
@Override

View File

@@ -0,0 +1,398 @@
package com.uiui.zyos.service;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import com.blankj.utilcode.util.NetworkUtils;
import com.google.gson.JsonObject;
import com.uiui.zyos.BuildConfig;
import com.uiui.zyos.R;
import com.uiui.zyos.activity.main.MainActivity;
import com.uiui.zyos.manager.RemoteManager;
import com.uiui.zyos.utils.ActivationUtil;
import com.uiui.zyos.utils.ServiceAliveUtils;
import com.uiui.zyos.utils.Utils;
import com.uiui.zyos.websocket.JWebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
/**
* 【有道云笔记】学生项目-用户端websocket对接.md
* https://note.youdao.com/s/Pbv87efV
* <p>
* 【有道云笔记】学生项目-设备端websocket对接.md
* https://note.youdao.com/s/Ea0tebj8
* <p>
* 【有道云笔记】学生项目-管理端websocket对接.md
* https://note.youdao.com/s/MazEq49Q
* <p>
* 老人在线websocket重构了按照这个重新对接跟之前售后差不多是一样的。
* <p>
* 1.设备未激活 不链接websocket 形成不了关联设备激活后才链接websocket
* 2.已激活的设备设备若已链接websocket用户确认绑定后断开websocket 等待5秒 再重新链接websocket 以刷新用户关联
* 3.设备用户解除绑定后断开websocket 等待5秒 再重新链接websocket 以刷新用户关联
*/
public class SocketService extends Service implements NetworkUtils.OnNetworkStatusChangedListener {
private final static String TAG = "JWebSocketClientService";
public JWebSocketClient mJWebSocketClient;
// private SocketServiceBinder mBinder = new SocketServiceBinder();
@Override
public void onDisconnected() {
Log.i(TAG, "网络断开连接");
}
@Override
public void onConnected(NetworkUtils.NetworkType networkType) {
Log.i(TAG, "网络已连接");
}
//用于Activity和service通讯
public class SocketServiceBinder extends Binder {
public SocketService getService() {
return SocketService.this;
}
}
// private ServiceConnection mServiceConnection = new ServiceConnection() {
// @Override
// public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// Log.e(TAG, "onServiceConnected: componentName = " + componentName);
// boolean isServiceRunning = ServiceAliveUtils.isServiceAlive(SocketService.this, ManagerService.class.getName());
// Log.e(TAG, "onServiceConnected: isServiceRunning = " + isServiceRunning);
// if (!isServiceRunning) {
// startService(new Intent(SocketService.this, ManagerService.class));
// }
// }
//
// @Override
// public void onServiceDisconnected(ComponentName componentName) {
// Log.e(TAG, "onServiceDisconnected: ");
// // 断开链接
// startService(new Intent(SocketService.this, ManagerService.class));
// // 重新绑定
// bindService(new Intent(SocketService.this, ManagerService.class), mServiceConnection, Context.BIND_IMPORTANT);
// }
// };
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: ");
NetworkUtils.registerNetworkStatusChangedListener(this);
registerScreenLockReceiver();
if (ActivationUtil.isActivation(SocketService.this)) {
//初始化websocket
initSocketClient();
startLoop();
} else {
Log.e(TAG, "onCreate: 未激活不连接");
}
// boolean isServiceRunning = ServiceAliveUtils.isServiceAlive(this, MainService.class.getName());
// Log.e(TAG, "onCreate: isServiceRunning = " + isServiceRunning);
// if (!isServiceRunning) {
// startService(new Intent(this, MainService.class));
// }
// bindService(new Intent(this, ManagerService.class), mServiceConnection, Context.BIND_IMPORTANT);
mNotificationManagerCompat = NotificationManagerCompat.from(this);
createNotificationChannel();
// showNotification();
sendSimpleNotification();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: ");
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
NetworkUtils.unregisterNetworkStatusChangedListener(this);
dispose();
closeConnect();
if (mScreenLockReceiver != null) {
unregisterReceiver(mScreenLockReceiver);
}
// unbindService(mServiceConnection);
}
private static final String CHANNEL_ID = "CHANNEL_ID";
private static final String CHANNEL_NAME = "系统通知";
private static final String CHANNEL_DESCRIPTION = "学习课堂通知";
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = CHANNEL_NAME;
String description = CHANNEL_DESCRIPTION;
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
private NotificationManagerCompat mNotificationManagerCompat;
private int NotificationID = 1;
private void sendSimpleNotification() {
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "CHANNEL_ID")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("学习课堂正在运行")
// .setContentText("测试内容")
.setAutoCancel(false)
.setShowWhen(false)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setOnlyAlertOnce(true)
.setPriority(NotificationCompat.PRIORITY_MAX);
// notificationId is a unique int for each notification that you must define
// mNotificationManagerCompat.notify(NotificationID, builder.build());
startForeground(NotificationID, builder.build());
}
private ScreenLockReceiver mScreenLockReceiver;
private void registerScreenLockReceiver() {
if (null == mScreenLockReceiver) {
mScreenLockReceiver = new ScreenLockReceiver();
}
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_SHUTDOWN);
filter.addAction(Intent.ACTION_FACTORY_RESET);
filter.addAction(Intent.ACTION_MASTER_CLEAR);
registerReceiver(mScreenLockReceiver, filter);
}
private class ScreenLockReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.e(TAG, "onReceive:" + action);
if (TextUtils.isEmpty(action)) {
Log.e(TAG, "onReceive: is NULL");
return;
}
switch (action) {
case Intent.ACTION_BOOT_COMPLETED:
case Intent.ACTION_USER_PRESENT:
case Intent.ACTION_SCREEN_ON:
sendMsgScreen();
break;
case Intent.ACTION_SCREEN_OFF:
case Intent.ACTION_SHUTDOWN:
case Intent.ACTION_FACTORY_RESET:
case Intent.ACTION_MASTER_CLEAR:
sendMsgScreen();
break;
default:
break;
}
}
}
private Disposable mDisposable;
private void dispose() {
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
mDisposable = null;
}
}
private void startLoop() {
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
mDisposable = null;
}
mDisposable = Observable.interval(30, TimeUnit.SECONDS)
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long s) throws Exception {
Log.d(TAG, "startLoop accept: " + s);
Log.i(TAG, "心跳包检测websocket连接状态");
if (!ActivationUtil.isActivation(SocketService.this)) {
dispose();
}
//每隔一定的时间,对长连接进行一次心跳检测
if (Utils.isScreenOn(SocketService.this)) {
if (mJWebSocketClient != null) {
if (mJWebSocketClient.isOpen()) {
Log.i(TAG, "websocket已连接");
sendPingMsg();
} else if (mJWebSocketClient.isClosed()) {
Log.i(TAG, "websocket重连中");
reconnectWs();
}
} else {
//如果client已为空重新初始化连接
initSocketClient();
}
} else {
Log.i(TAG, "websocket息屏不重连");
}
}
});
}
/**
* 初始化websocket连接
*/
private void initSocketClient() {
URI uri = URI.create(BuildConfig.WEBSOCKET_URL + "?sn=" + RemoteManager.getInstance().getSerial());
mJWebSocketClient = new JWebSocketClient(uri) {
@Override
public void onMessage(String message) {
Log.i(TAG, "onMessage: 收到服务器发来的消息:" + message);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
super.onOpen(handshakedata);
Log.i(TAG, "onOpen: websocket连接成功");
sendPingMsg();
}
@Override
public void onClose(int code, String reason, boolean remote) {
super.onClose(code, reason, remote);
Log.e(TAG, "onClose: websocket连接关闭:" + reason);
mJWebSocketClient = null;
}
@Override
public void onError(Exception ex) {
super.onError(ex);
Log.e(TAG, "onError: websocket连接错误:" + ex.getMessage());
mJWebSocketClient = null;
}
};
connect();
}
/**
* 连接websocket
*/
private void connect() {
try {
//connectBlocking多出一个等待操作会先连接再发送否则未连接发送会报错
Log.i(TAG, "connect: websocket连接中");
mJWebSocketClient.connectBlocking();
} catch (Exception e) {
Log.i(TAG, "connect: " + e.getMessage());
}
}
/**
* 开启重连
*/
private void reconnectWs() {
Log.e(TAG, "reconnectWs: ");
try {
Log.i(TAG, "reconnectWs: 开启重连");
mJWebSocketClient.reconnectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 断开连接
*/
private void closeConnect() {
Log.e(TAG, "closeConnect: ");
try {
if (null != mJWebSocketClient) {
mJWebSocketClient.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
mJWebSocketClient = null;
}
}
/**
* 发送消息
*/
public void sendPingMsg() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("sn", RemoteManager.getInstance().getSerial());
jsonObject.addProperty("type", "ping");
if (null != mJWebSocketClient) {
Log.i(TAG, "sendPingMsg: 发送的消息:" + jsonObject.toString());
mJWebSocketClient.send(jsonObject.toString());
}
}
public void sendMsgScreen() {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("sn", RemoteManager.getInstance().getSerial());
if (Utils.isScreenOn(SocketService.this)) {
jsonObject.addProperty("type", "device_open_screen");
} else {
jsonObject.addProperty("type", "device_close_screen");
//熄屏状态
}
if (null != mJWebSocketClient) {
Log.i(TAG, "sendMsgScreen 发送的消息" + jsonObject.toString());
try {
mJWebSocketClient.send(jsonObject.toString());
} catch (Exception e) {
Log.i(TAG, "sendMsgScreen: sendMsg Exception: " + e.getLocalizedMessage());
}
} else {
Log.i(TAG, "sendMsgScreen: 未连接");
initSocketClient();
}
}
}

View File

@@ -0,0 +1,37 @@
package com.uiui.zyos.utils;
import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ServiceAliveUtils {
public static boolean isServiceAlive(Context context, String className) {
boolean isServiceRunning = false;
ActivityManager manager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (manager == null) {
return false;
}
List<ActivityManager.RunningServiceInfo> serviceInfos = manager.getRunningServices(Integer.MAX_VALUE);
List<String> serviceClass = serviceInfos.stream().map(new Function<ActivityManager.RunningServiceInfo, String>() {
@Override
public String apply(ActivityManager.RunningServiceInfo runningServiceInfo) {
return runningServiceInfo.service.getClassName();
}
}).collect(Collectors.toList());
// for (ActivityManager.RunningServiceInfo service : serviceInfos) {
// if (className.equals(service.service.getClassName())) {
// isServiceRunning = true;
// }
// }
if (serviceClass.contains(className)) {
isServiceRunning = true;
}
Log.e("ServiceAliveUtils", className + " isServiceAlice: " + isServiceRunning);
return isServiceRunning;
}
}

View File

@@ -0,0 +1,36 @@
package com.uiui.zyos.websocket;
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.i("JWebSocketClient", "onOpen()");
}
@Override
public void onMessage(String message) {
Log.i("JWebSocketClient", "onMessage()");
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.i("JWebSocketClient", "onClose():" + reason);
}
@Override
public void onError(Exception ex) {
Log.i("JWebSocketClient", "onError():" + ex.getMessage());
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -13,7 +13,7 @@
android:layout_height="wrap_content">
<ImageView
android:layout_width="@dimen/dp_270"
android:layout_width="@dimen/dp_432"
android:layout_height="@dimen/dp_270"
android:adjustViewBounds="true"
android:scaleType="centerCrop"