From 473e2c2d89102df62cd7edf3ca28c8f94f2b6a5e Mon Sep 17 00:00:00 2001 From: tanjianbin <632190820@qq.com> Date: Mon, 11 May 2026 14:32:27 +0800 Subject: [PATCH] change --- .../java/org/yameida/worktool/Constant.kt | 2 +- .../main/java/org/yameida/worktool/Demo.kt | 56 --------- .../worktool/activity/ListenActivity.kt | 49 +++++--- .../worktool/service/WeworkController.kt | 4 +- .../worktool/service/WeworkLoopImpl.kt | 6 +- .../yameida/worktool/service/WeworkService.kt | 7 +- .../worktool/utils/FloatWindowHelper.kt | 22 +++- .../worktool/utils/WebSocketManager.java | 113 +++++++++++------- app/src/main/res/layout/activity_listen.xml | 21 ++-- .../floatwindow/DefaultFloatService.kt | 15 ++- .../yameida/floatwindow/FloatWindowManager.kt | 7 +- 11 files changed, 165 insertions(+), 137 deletions(-) delete mode 100644 app/src/main/java/org/yameida/worktool/Demo.kt diff --git a/app/src/main/java/org/yameida/worktool/Constant.kt b/app/src/main/java/org/yameida/worktool/Constant.kt index 341f319..12973e1 100644 --- a/app/src/main/java/org/yameida/worktool/Constant.kt +++ b/app/src/main/java/org/yameida/worktool/Constant.kt @@ -58,7 +58,7 @@ object Constant { SPUtils.getInstance().put(weworkCorpName + "weworkMP", value) } var encryptType: Int = SPUtils.getInstance().getInt("encryptType", 0) - var autoReply: Int = SPUtils.getInstance().getInt("autoReply", 1) + var autoReply: Int = SPUtils.getInstance().getInt("autoReply", 0) var groupStrict: Boolean get() = SPUtils.getInstance().getBoolean("groupStrict", false) set(value) = SPUtils.getInstance().put("groupStrict", value) diff --git a/app/src/main/java/org/yameida/worktool/Demo.kt b/app/src/main/java/org/yameida/worktool/Demo.kt deleted file mode 100644 index 818375a..0000000 --- a/app/src/main/java/org/yameida/worktool/Demo.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.yameida.worktool - -import com.blankj.utilcode.util.TimeUtils -import org.yameida.worktool.model.WeworkMessageBean -import org.yameida.worktool.service.MyLooper -import org.yameida.worktool.service.WeworkController -import org.yameida.worktool.service.WeworkLoopImpl -import org.yameida.worktool.service.getRoot -import org.yameida.worktool.utils.AccessibilityUtil -import java.util.* - -/** - * 示例 - */ -object Demo { - - fun test(flag: Boolean) { - if (!flag) return - - MyLooper.getInstance().removeCallbacksAndMessages(null) - - //打印当前视图树 -// AccessibilityUtil.printNodeClazzTree(getRoot()) - - } - - fun test2(name: String) { - val time = TimeUtils.date2String(Date(), "MMddHHmm") - val groupName = "测试群$time" - val json = """ - { - "socketType":2, - "list":[ - { - "type":203, - "titleList":[ - "$name" - ], - "receivedContent":"你好~我是机器人,你可以@我和我聊天,你也可以通过API文档来让我发送消息或完成建群等任务。接口文档:https://www.apifox.cn/apidoc/project-1035094/api-23520034" - }, - { - "type": 206, - "groupName": "$groupName", - "selectList": [ - "$name", - "甲仑" - ], - "groupAnnouncement": "(自动拉群+自动群公告) WorkTool欢迎大家~WorkTool管家是机器人,有问题可以在QQ群反馈~@我可以聊天~" - } - ] - } - """.trimIndent() - MyLooper.onMessage(null, json) - } - -} \ No newline at end of file diff --git a/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt b/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt index d8ed0f1..5b1a3e4 100644 --- a/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt +++ b/app/src/main/java/org/yameida/worktool/activity/ListenActivity.kt @@ -22,6 +22,7 @@ import org.yameida.worktool.utils.* import org.yameida.worktool.utils.capture.MediaProjectionHolder import org.yameida.worktool.utils.envcheck.CheckHook import org.yameida.worktool.utils.envcheck.CheckRoot +import kotlin.random.Random class ListenActivity : AppCompatActivity() { @@ -59,6 +60,7 @@ class ListenActivity : AppCompatActivity() { override fun onDestroy() { super.onDestroy() unregisterReceiver(openWsReceiver) + FloatWindowHelper.hideWindow() } override fun onResume() { @@ -75,16 +77,11 @@ class ListenActivity : AppCompatActivity() { iv_settings.setOnClickListener { SettingsActivity.enterActivity(this) } - et_channel.setText(Constant.robotId) - bt_save.setOnClickListener { - val channel = et_channel.text.toString().trim() - Constant.robotId = channel - ToastUtils.showLong("保存成功") - sendBroadcast(Intent(Constant.WEWORK_NOTIFY).apply { - putExtra("type", "modify_channel") - }) - HttpUtil.getMyConfig(toast = false) - MobclickAgent.onProfileSignIn(channel) + tv_channel.text = Constant.robotId.ifBlank { "未生成" } + bt_reset_channel.setOnClickListener { + val channel = generateDefaultRobotId() + tv_channel.text = channel + saveChannel(channel, toast = "重置成功") } tv_host.text = Constant.host tv_host.setOnClickListener { @@ -185,13 +182,35 @@ class ListenActivity : AppCompatActivity() { } private fun initData() { - Constant.robotId = "2038521871751249921" - Constant.host = "ws://8.166.130.74:18680" + // 链接号为空时自动生成一次并持久化,避免每次启动覆盖用户手动保存的链接号 + if (Constant.robotId.isBlank()) { + Constant.robotId = generateDefaultRobotId() + tv_channel.text = Constant.robotId + } // HttpUtil.checkUpdate() HttpUtil.getMyConfig(toast = false) CacheUtil.autoDelete() } + private fun generateDefaultRobotId(): String { + val suffix = Random.nextInt(1000, 9999) + return "${System.currentTimeMillis()}$suffix" + } + + private fun saveChannel(channel: String, toast: String) { + if (channel.isBlank()) { + ToastUtils.showLong("链接号不能为空") + return + } + Constant.robotId = channel + ToastUtils.showLong(toast) + sendBroadcast(Intent(Constant.WEWORK_NOTIFY).apply { + putExtra("type", "modify_channel") + }) + HttpUtil.getMyConfig(toast = false) + MobclickAgent.onProfileSignIn(channel) + } + private fun initNotification() { if (!Constant.enableMediaProject) { return @@ -206,7 +225,7 @@ class ListenActivity : AppCompatActivity() { }, Context.BIND_AUTO_CREATE) //开启屏幕录制权限 if (MediaProjectionHolder.mMediaProjection == null) { - bt_save.postDelayed({ + window.decorView.postDelayed({ fastStartActivity(this, GetScreenShotActivity::class.java) }, 1000) } @@ -282,8 +301,8 @@ class ListenActivity : AppCompatActivity() { .setNegativeButton("", null) .setPositiveButton("", null) val show = positiveButton.show() - bt_save.postDelayed({ show.dismiss() }, 5000) - bt_save.postDelayed({ + window.decorView.postDelayed({ show.dismiss() }, 5000) + window.decorView.postDelayed({ packageManager.getLaunchIntentForPackage(Constant.PACKAGE_NAMES)?.apply { this.flags = Intent.FLAG_ACTIVITY_NEW_TASK startActivity(this) diff --git a/app/src/main/java/org/yameida/worktool/service/WeworkController.kt b/app/src/main/java/org/yameida/worktool/service/WeworkController.kt index 6975faf..c5380c3 100644 --- a/app/src/main/java/org/yameida/worktool/service/WeworkController.kt +++ b/app/src/main/java/org/yameida/worktool/service/WeworkController.kt @@ -1,7 +1,6 @@ package org.yameida.worktool.service import com.blankj.utilcode.util.* -import org.yameida.worktool.Demo import org.yameida.worktool.annotation.RequestMapping import org.yameida.worktool.model.ExecCallbackBean import org.yameida.worktool.model.WeworkMessageBean @@ -159,7 +158,6 @@ object WeworkController { @RequestMapping fun test(message: WeworkMessageBean? = null) { LogUtils.d(message) - Demo.test(true) } /** @@ -640,4 +638,4 @@ object WeworkController { return WeworkGetImpl.getCorpList(message) } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt b/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt index 41fe5b2..84147d3 100644 --- a/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt +++ b/app/src/main/java/org/yameida/worktool/service/WeworkLoopImpl.kt @@ -7,7 +7,6 @@ import androidx.core.text.isDigitsOnly import com.blankj.utilcode.util.* import com.hjq.toast.ToastUtils import org.yameida.worktool.Constant -import org.yameida.worktool.Demo import org.yameida.worktool.MyApplication import org.yameida.worktool.activity.GetScreenShotActivity import org.yameida.worktool.model.WeworkMessageBean @@ -176,8 +175,7 @@ object WeworkLoopImpl { val nameList = passFriendRequest() if (nameList.isEmpty()) break - //todo 可自定义执行任务 -// Demo.test2(nameList[0]) + // todo 可自定义执行任务 } } return true @@ -1020,4 +1018,4 @@ object WeworkLoopImpl { return false } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/yameida/worktool/service/WeworkService.kt b/app/src/main/java/org/yameida/worktool/service/WeworkService.kt index 52a2dc8..d5ba25c 100644 --- a/app/src/main/java/org/yameida/worktool/service/WeworkService.kt +++ b/app/src/main/java/org/yameida/worktool/service/WeworkService.kt @@ -13,11 +13,9 @@ import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener import org.yameida.worktool.Constant -import org.yameida.worktool.Demo import org.yameida.worktool.observer.MultiFileObserver import org.yameida.worktool.utils.* import java.lang.Exception -import kotlin.concurrent.thread /** * 企业微信辅助服务 @@ -47,8 +45,6 @@ class WeworkService : AccessibilityService() { MyLooper.init() //初始化图片接收 initObserver() - //开发者可以在这里添加测试代码 启动时调用一次 - thread { Demo.test(AppUtils.isAppDebug()) } //监听是否修改链接号并重新长连接 registerReceiver(object : BroadcastReceiver() { @@ -116,6 +112,7 @@ class WeworkService : AccessibilityService() { //隐藏软键盘模式 softKeyboardController.showMode = SHOW_MODE_AUTO webSocketManager.close(1000, "service Destroy") + FloatWindowHelper.hideWindow() } inner class EchoWebSocketListener : WebSocketListener() { @@ -172,4 +169,4 @@ class WeworkService : AccessibilityService() { }) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/yameida/worktool/utils/FloatWindowHelper.kt b/app/src/main/java/org/yameida/worktool/utils/FloatWindowHelper.kt index c3e3c08..d35f138 100644 --- a/app/src/main/java/org/yameida/worktool/utils/FloatWindowHelper.kt +++ b/app/src/main/java/org/yameida/worktool/utils/FloatWindowHelper.kt @@ -31,6 +31,7 @@ import kotlin.concurrent.thread object FloatWindowHelper { var isPause = false + private var bound = false fun showWindow() { LogUtils.d("FloatWindowHelper.showWindow()") @@ -39,7 +40,23 @@ object FloatWindowHelper { val app = Utils.getApp() val intent = Intent(app, DefaultFloatService::class.java) - app.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + if (!bound) { + bound = app.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } + } + + fun hideWindow() { + LogUtils.d("FloatWindowHelper.hideWindow()") + val app = Utils.getApp() + FloatWindowManager.hide(DefaultFloatService::class.java) + if (bound) { + try { + app.unbindService(serviceConnection) + } catch (ignore: Exception) { + } + bound = false + } + app.stopService(Intent(app, DefaultFloatService::class.java)) } /** @@ -143,7 +160,8 @@ object FloatWindowHelper { override fun onServiceDisconnected(name: ComponentName?) { LogUtils.i("DefaultFloatService 服务断开") + bound = false } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java b/app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java index 5882f0f..8dd5343 100644 --- a/app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java +++ b/app/src/main/java/org/yameida/worktool/utils/WebSocketManager.java @@ -22,32 +22,37 @@ import java.util.concurrent.TimeUnit; import okhttp3.OkHttpClient; import okhttp3.Request; +import okhttp3.Response; import okhttp3.WebSocket; import okhttp3.WebSocketListener; +import okio.ByteString; public class WebSocketManager { public static final String HEARTBEAT = "{\"type\":" + WeworkMessageBean.HEART_BEAT + "}"; private static final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + private static final OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .pingInterval(25, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .build(); public static Map webSocketManager = new ConcurrentHashMap<>(); - private static final int reconnectInt = 5000; //毫秒 private static final long heartBeatRate = 5; //秒 private Map messageIdMap = new ConcurrentHashMap<>(); private ScheduledFuture task; private WebSocket socket; private String url; private WebSocketListener listener; - private boolean connecting = false; + private volatile boolean connecting = false; + private volatile boolean manuallyClosed = false; + private volatile boolean opened = false; private long lastConnectedTime = 0L; public WebSocketManager(String url, WebSocketListener listener) { Log.e(url, "新建链接"); this.url = url; this.listener = listener; - OkHttpClient client = new OkHttpClient(); - Request request = new Request.Builder().url(url).build(); - this.socket = client.newWebSocket(request, listener); - socket.send("{\"td\":" + System.currentTimeMillis() + "}"); + this.socket = client.newWebSocket(new Request.Builder().url(url).build(), innerListener); webSocketManager.put(url, this); task = heartCheckStart(); } @@ -83,7 +88,7 @@ public class WebSocketManager { public void send(WeworkMessageListBean msg, boolean log) { String json = GsonUtils.toJson(msg); - boolean success = socket.send(json); + boolean success = socket != null && socket.send(json); if (log && success) LogUtils.d(url, json, "通讯消息发送成功!"); if (!success) @@ -91,14 +96,19 @@ public class WebSocketManager { } public void send(String msg) { - boolean success = socket.send(msg); + boolean success = socket != null && socket.send(msg); LogUtils.e(url, msg, (success ? "通讯消息发送成功!" : "通讯消息发送失败!")); } public void close(int code, String reason) { - task.cancel(true); + manuallyClosed = true; + if (task != null) { + task.cancel(true); + } Log.e("url", "task 取消"); - this.socket.close(code, reason); + if (this.socket != null) { + this.socket.close(code, reason); + } Log.e(url, "链接关闭"); } @@ -112,44 +122,25 @@ public class WebSocketManager { } public void reConnect() { + if (manuallyClosed || connecting) { + return; + } connecting = true; + opened = false; Log.e(url, "重连"); - boolean isConnect = false; - int interval = reconnectInt; - while (true) { - try { - isConnect = connect(); - if (isConnect) { - connecting = false; - break; - } - } catch (Exception e) { - e.printStackTrace(); - } - try { - Thread.sleep(interval); - if (interval < 600000) { - interval *= 2; - } - } catch (InterruptedException e) { - e.printStackTrace(); + try { + if (socket != null) { + socket.cancel(); } + } catch (Exception ignore) { } - } - - private boolean connect() { - WebSocket s = new OkHttpClient().newWebSocket(new Request.Builder().url(url).build(), listener); - if (s.send(WebSocketManager.HEARTBEAT)) { - this.socket = s; - s.send("{\"td\":" + System.currentTimeMillis() + "}"); - return true; - } - return false; + socket = client.newWebSocket(new Request.Builder().url(url).build(), innerListener); } private ScheduledFuture heartCheckStart() { lastConnectedTime = System.currentTimeMillis(); Runnable r = () -> { + if (manuallyClosed) return; SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 Log.d(url, "心跳检测" + df.format(new Date()));// new Date()为获取当前系统时间 if (!connecting && (socket == null || !socket.send(HEARTBEAT))) { @@ -159,7 +150,7 @@ public class WebSocketManager { reConnect(); //重连后刷新连接时间 lastConnectedTime = System.currentTimeMillis(); - } else if (System.currentTimeMillis() % 1000 == 0) { + } else if (opened && System.currentTimeMillis() % 1000 == 0) { socket.send("{\"td\":" + System.currentTimeMillis() + "}"); } if (!Constant.INSTANCE.getEnableMediaProject()) { @@ -176,4 +167,46 @@ public class WebSocketManager { public static WebSocketManager getWebSocketManager(String id) { return webSocketManager.get(id); } + + private final WebSocketListener innerListener = new WebSocketListener() { + @Override + public void onOpen(WebSocket webSocket, Response response) { + opened = true; + connecting = false; + lastConnectedTime = System.currentTimeMillis(); + listener.onOpen(webSocket, response); + } + + @Override + public void onMessage(WebSocket webSocket, String text) { + listener.onMessage(webSocket, text); + } + + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + listener.onMessage(webSocket, bytes); + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + opened = false; + connecting = false; + listener.onClosing(webSocket, code, reason); + } + + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + opened = false; + connecting = false; + listener.onClosed(webSocket, code, reason); + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + opened = false; + connecting = false; + WeworkController.INSTANCE.setEnableLoopRunning(false); + listener.onFailure(webSocket, t, response); + } + }; } diff --git a/app/src/main/res/layout/activity_listen.xml b/app/src/main/res/layout/activity_listen.xml index e5413d3..5ff525e 100644 --- a/app/src/main/res/layout/activity_listen.xml +++ b/app/src/main/res/layout/activity_listen.xml @@ -326,11 +326,14 @@ android:textColor="@color/color_333333" android:textSize="@dimen/setting_start_font_size" /> - @@ -344,17 +347,17 @@ android:orientation="vertical">