update 兼容主动添加好友;可变回复内容前缀;其他已知问题优化

This commit is contained in:
尹甲仑
2022-08-26 14:59:55 +08:00
parent cab42890c8
commit 96f15bb969
6 changed files with 109 additions and 69 deletions

View File

@@ -139,6 +139,8 @@ public class WeworkMessageBean {
public String receivedName; public String receivedName;
//内容移除了@me //内容移除了@me
public String receivedContent; public String receivedContent;
//回复内容前缀
public String prefix;
//想要at的昵称 //想要at的昵称
public String at; public String at;
//原始内容text //原始内容text

View File

@@ -59,6 +59,7 @@ object WeworkController {
* @param message#originalContent 原始消息的内容 * @param message#originalContent 原始消息的内容
* @param message#textType 原始消息的消息类型 * @param message#textType 原始消息的消息类型
* @param message#receivedContent 回复内容 * @param message#receivedContent 回复内容
* @param message#prefix 回复内容前缀
* @see WeworkMessageBean.TEXT_TYPE * @see WeworkMessageBean.TEXT_TYPE
*/ */
@RequestMapping @RequestMapping

View File

@@ -5,7 +5,6 @@ import android.view.accessibility.AccessibilityNodeInfo
import androidx.core.text.isDigitsOnly import androidx.core.text.isDigitsOnly
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import org.yameida.worktool.Constant import org.yameida.worktool.Constant
import org.yameida.worktool.Demo
import org.yameida.worktool.model.WeworkMessageBean import org.yameida.worktool.model.WeworkMessageBean
import org.yameida.worktool.service.WeworkController.mainLoopRunning import org.yameida.worktool.service.WeworkController.mainLoopRunning
import org.yameida.worktool.utils.* import org.yameida.worktool.utils.*
@@ -73,7 +72,8 @@ object WeworkLoopImpl {
val nameList = passFriendRequest() val nameList = passFriendRequest()
if (nameList.isEmpty()) if (nameList.isEmpty())
break break
Demo.test2(nameList[0]) //todo 可自定义执行任务
// Demo.test2(nameList[0])
} }
} }
return true return true
@@ -105,6 +105,7 @@ object WeworkLoopImpl {
val title = titleList.joinToString() val title = titleList.joinToString()
LogUtils.v("聊天: $title") LogUtils.v("聊天: $title")
log("聊天: $title") log("聊天: $title")
//聊天消息列表 1ListView 0RecycleView xViewGroup
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
LogUtils.v("消息条数: " + list.childCount) LogUtils.v("消息条数: " + list.childCount)

View File

@@ -45,6 +45,7 @@ object WeworkOperationImpl {
* @param originalContent 原始消息的内容 * @param originalContent 原始消息的内容
* @param textType 原始消息的消息类型 * @param textType 原始消息的消息类型
* @param receivedContent 回复内容 * @param receivedContent 回复内容
* @param prefix 回复内容前缀
* @see WeworkMessageBean.TEXT_TYPE * @see WeworkMessageBean.TEXT_TYPE
*/ */
fun replyMessage( fun replyMessage(
@@ -52,11 +53,13 @@ object WeworkOperationImpl {
receivedName: String?, receivedName: String?,
originalContent: String, originalContent: String,
textType: Int, textType: Int,
receivedContent: String receivedContent: String,
prefix: String = "[自动回复]"
): Boolean { ): Boolean {
for (title in titleList) { for (title in titleList) {
if (WeworkRoomUtil.intoRoom(title)) { if (WeworkRoomUtil.intoRoom(title)) {
if (WeworkTextUtil.longClickMessageItem( if (WeworkTextUtil.longClickMessageItem(
//聊天消息列表 1ListView 0RecycleView xViewGroup
AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView), AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView),
textType, textType,
receivedName, receivedName,
@@ -65,7 +68,7 @@ object WeworkOperationImpl {
) )
) { ) {
LogUtils.v("开始回复") LogUtils.v("开始回复")
sendChatMessage(receivedContent, "[自动回复]") sendChatMessage(receivedContent, prefix)
LogUtils.d("$title: 回复成功") LogUtils.d("$title: 回复成功")
WeworkLoopImpl.getChatMessageList() WeworkLoopImpl.getChatMessageList()
return true return true
@@ -73,9 +76,9 @@ object WeworkOperationImpl {
LogUtils.d("$title: 回复失败 直接发送答案") LogUtils.d("$title: 回复失败 直接发送答案")
error("$title: 回复失败 直接发送答案 $receivedContent") error("$title: 回复失败 直接发送答案 $receivedContent")
if (receivedName == null) { if (receivedName == null) {
sendChatMessage(receivedContent, "[自动回复]$originalContent\n") sendChatMessage(receivedContent, "$prefix$originalContent\n")
} else { } else {
sendChatMessage(receivedContent, "[自动回复]$originalContent】@$receivedName\n") sendChatMessage(receivedContent, "$prefix$originalContent】@$receivedName\n")
} }
WeworkLoopImpl.getChatMessageList() WeworkLoopImpl.getChatMessageList()
} }
@@ -108,6 +111,7 @@ object WeworkOperationImpl {
for (title in titleList) { for (title in titleList) {
if (WeworkRoomUtil.intoRoom(title)) { if (WeworkRoomUtil.intoRoom(title)) {
if (WeworkTextUtil.longClickMessageItem( if (WeworkTextUtil.longClickMessageItem(
//聊天消息列表 1ListView 0RecycleView xViewGroup
AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView), AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView),
textType, textType,
receivedName, receivedName,
@@ -167,63 +171,6 @@ object WeworkOperationImpl {
return true return true
} }
fun getGroupQrcode(groupName: String): Boolean {
if (WeworkRoomUtil.intoRoom(groupName) && WeworkRoomUtil.intoGroupManager()) {
val tvList = AccessibilityUtil.findAllOnceByClazz(getRoot(), Views.TextView)
tvList.forEachIndexed { index, tv ->
if (tv.text != null && tv.text.contains("微信用户创建")) {
if (index + 1 < tvList.size) {
val tvQr = tvList[index + 1]
AccessibilityUtil.performClick(tvQr)
}
}
}
AccessibilityUtil.findOneByText(getRoot(), "保存到相册")
val startTime = System.currentTimeMillis()
var currentTime = startTime
while (currentTime - startTime <= Constant.CHANGE_PAGE_INTERVAL * 5) {
AccessibilityUtil.findOnceByClazz(getRoot(), Views.ProgressBar) ?: break
sleep(Constant.POP_WINDOW_INTERVAL / 5)
currentTime = System.currentTimeMillis()
}
if (AccessibilityUtil.findTextAndClick(getRoot(), "保存到相册")) {
sleep(Constant.CHANGE_PAGE_INTERVAL)
val fileDirPath = "/storage/emulated/0/DCIM/WeixinWork"
val fileDir = FileUtils.getFileByPath(fileDirPath)
if (fileDir.isDirectory) {
for (file in fileDir.listFiles().filter { it.name.endsWith(".jpg") }) {
val fileTime = file.name.replace("mmexport", "")
.replace(".jpg", "")
LogUtils.v("fileTime: $fileTime")
if (fileTime.isNotBlank()) {
if (fileTime.toLong() > currentTime) {
LogUtils.d("找到最新保存二维码图片: $fileTime")
try {
val bitmap = ImageUtils.bytes2Bitmap(file.readBytes())
val mDecoder = QRCodeDecoder.Builder().build()
val qrcode = mDecoder.decode(bitmap)
LogUtils.e("group: $groupName qrcode: $qrcode")
val weworkMessageBean = WeworkMessageBean()
weworkMessageBean.type = WeworkMessageBean.GET_GROUP_QRCODE
weworkMessageBean.groupName = groupName
weworkMessageBean.qrcode = qrcode
WeworkController.weworkService.webSocketManager.send(
weworkMessageBean
)
return true
} catch (e: Exception) {
e.printStackTrace()
LogUtils.e(e)
}
}
}
}
}
}
}
return false
}
/** /**
* 进入群聊并修改群配置 * 进入群聊并修改群配置
* 群名称、群公告、拉人、踢人 * 群名称、群公告、拉人、踢人
@@ -443,7 +390,7 @@ object WeworkOperationImpl {
friend: WeworkMessageBean.Friend friend: WeworkMessageBean.Friend
): Boolean { ): Boolean {
goHome() goHome()
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView, Views.ListView, Views.ViewGroup)
if (list != null) { if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list) val frontNode = AccessibilityUtil.findFrontNode(list)
val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView) val textViewList = AccessibilityUtil.findAllOnceByClazz(frontNode, Views.TextView)
@@ -452,9 +399,19 @@ object WeworkOperationImpl {
val multiButton: AccessibilityNodeInfo = textViewList[textViewList.size - 1] val multiButton: AccessibilityNodeInfo = textViewList[textViewList.size - 1]
AccessibilityUtil.performClick(multiButton) AccessibilityUtil.performClick(multiButton)
sleep(Constant.POP_WINDOW_INTERVAL) sleep(Constant.POP_WINDOW_INTERVAL)
val listViewList = AccessibilityUtil.findAllByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findAllByClazz(getRoot(), Views.ListView).lastOrNull()
if (!listViewList.isNullOrEmpty()) { if (list != null) {
if (AccessibilityUtil.findTextAndClick(listViewList.last(), "添加客户", "添加居民", "加微信")) { val button = AccessibilityUtil.findOneByText(list, "添加客户", "添加居民", "加微信")
if (button != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
AccessibilityUtil.performClick(button)
sleep(Constant.POP_WINDOW_INTERVAL)
if (AccessibilityUtil.findOnceByText(list, "添加客户", "添加居民", "加微信") != null) {
AccessibilityUtil.clickByNode(WeworkController.weworkService, button)
}
} else {
AccessibilityUtil.performClick(button)
}
AccessibilityUtil.findTextAndClick(getRoot(), "搜索手机号添加") AccessibilityUtil.findTextAndClick(getRoot(), "搜索手机号添加")
AccessibilityUtil.findTextInput(getRoot(), friend.phone.trim()) AccessibilityUtil.findTextInput(getRoot(), friend.phone.trim())
if (AccessibilityUtil.findTextAndClick(getRoot(), "网络查找手机")) { if (AccessibilityUtil.findTextAndClick(getRoot(), "网络查找手机")) {
@@ -585,6 +542,7 @@ object WeworkOperationImpl {
* extraText 转发是否附加一条文本 * extraText 转发是否附加一条文本
*/ */
private fun relaySelectTarget(selectList: List<String>, extraText: String? = null): Boolean { private fun relaySelectTarget(selectList: List<String>, extraText: String? = null): Boolean {
//聊天消息列表 1ListView 0RecycleView xViewGroup
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list, 2) val frontNode = AccessibilityUtil.findFrontNode(list, 2)
@@ -730,6 +688,7 @@ object WeworkOperationImpl {
LogUtils.e("未找到添加成员按钮") LogUtils.e("未找到添加成员按钮")
return false return false
} }
//群详情列表
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list, 2) val frontNode = AccessibilityUtil.findFrontNode(list, 2)
@@ -797,6 +756,7 @@ object WeworkOperationImpl {
LogUtils.e("未找到删除成员按钮") LogUtils.e("未找到删除成员按钮")
return false return false
} }
//群详情列表
val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOneByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list, 2) val frontNode = AccessibilityUtil.findFrontNode(list, 2)
@@ -888,10 +848,14 @@ object WeworkOperationImpl {
* 发送消息+@at * 发送消息+@at
*/ */
private fun sendChatMessage(text: String, prefix: String = "", at: String? = null) { private fun sendChatMessage(text: String, prefix: String = "", at: String? = null) {
val voiceFlag = AccessibilityUtil.findOnceByText(getRoot(), "按住 说话", "按住说话", exact = true)
if (voiceFlag != null) {
AccessibilityUtil.performClickWithSon(AccessibilityUtil.findFrontNode(voiceFlag))
}
var atFailed = false var atFailed = false
if (!at.isNullOrEmpty()) { if (!at.isNullOrEmpty()) {
AccessibilityUtil.findTextInput(getRoot(), "@") AccessibilityUtil.findTextInput(getRoot(), "@")
val atFlag = AccessibilityUtil.findOneByText(getRoot(), "选择提醒的人", timeout = 2000) val atFlag = AccessibilityUtil.findOneByText(getRoot(), "选择提醒的人", timeout = 2000, exact = true)
if (atFlag != null) { if (atFlag != null) {
val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView) val rv = AccessibilityUtil.findOneByClazz(getRoot(), Views.RecyclerView)
if (rv != null) { if (rv != null) {
@@ -926,7 +890,8 @@ object WeworkOperationImpl {
} }
} }
val content = if (atFailed) "@$at $prefix$text" else "$prefix$text" val content = if (atFailed) "@$at $prefix$text" else "$prefix$text"
if (AccessibilityUtil.findTextInput(getRoot(), content, append = !atFailed)) { val append = !at.isNullOrEmpty() && !atFailed
if (AccessibilityUtil.findTextInput(getRoot(), content, append = append)) {
val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button) val sendButton = AccessibilityUtil.findAllByClazz(getRoot(), Views.Button)
.firstOrNull { it.text == "发送" } .firstOrNull { it.text == "发送" }
if (sendButton != null) { if (sendButton != null) {
@@ -993,6 +958,9 @@ object WeworkOperationImpl {
list.refresh() list.refresh()
} }
if (AccessibilityUtil.findTextAndClick(getRoot(), "确定")) { if (AccessibilityUtil.findTextAndClick(getRoot(), "确定")) {
sleep(Constant.POP_WINDOW_INTERVAL)
//可能有两次确定 另一次为添加新tag
AccessibilityUtil.findTextAndClick(getRoot(), "确定")
return true return true
} }
} }
@@ -1000,4 +968,64 @@ object WeworkOperationImpl {
return false return false
} }
/**
* 获取群二维码并上传后台
*/
fun getGroupQrcode(groupName: String): Boolean {
if (WeworkRoomUtil.intoRoom(groupName) && WeworkRoomUtil.intoGroupManager()) {
val tvList = AccessibilityUtil.findAllOnceByClazz(getRoot(), Views.TextView)
tvList.forEachIndexed { index, tv ->
if (tv.text != null && tv.text.contains("微信用户创建")) {
if (index + 1 < tvList.size) {
val tvQr = tvList[index + 1]
AccessibilityUtil.performClick(tvQr)
}
}
}
AccessibilityUtil.findOneByText(getRoot(), "保存到相册")
val startTime = System.currentTimeMillis()
var currentTime = startTime
while (currentTime - startTime <= Constant.CHANGE_PAGE_INTERVAL * 5) {
AccessibilityUtil.findOnceByClazz(getRoot(), Views.ProgressBar) ?: break
sleep(Constant.POP_WINDOW_INTERVAL / 5)
currentTime = System.currentTimeMillis()
}
if (AccessibilityUtil.findTextAndClick(getRoot(), "保存到相册")) {
sleep(Constant.CHANGE_PAGE_INTERVAL)
val fileDirPath = "/storage/emulated/0/DCIM/WeixinWork"
val fileDir = FileUtils.getFileByPath(fileDirPath)
if (fileDir.isDirectory) {
for (file in fileDir.listFiles().filter { it.name.endsWith(".jpg") }) {
val fileTime = file.name.replace("mmexport", "")
.replace(".jpg", "")
LogUtils.v("fileTime: $fileTime")
if (fileTime.isNotBlank()) {
if (fileTime.toLong() > currentTime) {
LogUtils.d("找到最新保存二维码图片: $fileTime")
try {
val bitmap = ImageUtils.bytes2Bitmap(file.readBytes())
val mDecoder = QRCodeDecoder.Builder().build()
val qrcode = mDecoder.decode(bitmap)
LogUtils.e("group: $groupName qrcode: $qrcode")
val weworkMessageBean = WeworkMessageBean()
weworkMessageBean.type = WeworkMessageBean.GET_GROUP_QRCODE
weworkMessageBean.groupName = groupName
weworkMessageBean.qrcode = qrcode
WeworkController.weworkService.webSocketManager.send(
weworkMessageBean
)
return true
} catch (e: Exception) {
e.printStackTrace()
LogUtils.e(e)
}
}
}
}
}
}
}
return false
}
} }

View File

@@ -184,6 +184,7 @@ object AccessibilityUtil {
} }
nodeInfo = nodeInfo.parent nodeInfo = nodeInfo.parent
} }
LogUtils.e("performClick failed! ${nodeInfo?.className}")
return false return false
} }

View File

@@ -57,6 +57,7 @@ object WeworkRoomUtil {
*/ */
fun getRoomTitle(print: Boolean = true): ArrayList<String> { fun getRoomTitle(print: Boolean = true): ArrayList<String> {
val titleList = arrayListOf<String>() val titleList = arrayListOf<String>()
//聊天消息列表 1ListView 0RecycleView xViewGroup
val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
val frontNode = findFrontNode(list.parent.parent) val frontNode = findFrontNode(list.parent.parent)
@@ -102,6 +103,7 @@ object WeworkRoomUtil {
AccessibilityUtil.performClick(searchButton) AccessibilityUtil.performClick(searchButton)
AccessibilityUtil.findTextInput(getRoot(), title.replace("", "").replace("-.*$".toRegex(), "")) AccessibilityUtil.findTextInput(getRoot(), title.replace("", "").replace("-.*$".toRegex(), ""))
sleep(Constant.CHANGE_PAGE_INTERVAL) sleep(Constant.CHANGE_PAGE_INTERVAL)
//消息页搜索结果列表
val selectListView = findOneByClazz(getRoot(), Views.ListView) val selectListView = findOneByClazz(getRoot(), Views.ListView)
val imageView = AccessibilityUtil.findOnceByClazz(selectListView, Views.ImageView) val imageView = AccessibilityUtil.findOnceByClazz(selectListView, Views.ImageView)
if (imageView != null) { if (imageView != null) {
@@ -129,6 +131,7 @@ object WeworkRoomUtil {
if (AccessibilityUtil.findOnceByText(getRoot(), "全部群成员", "微信用户创建") != null) { if (AccessibilityUtil.findOnceByText(getRoot(), "全部群成员", "微信用户创建") != null) {
return true return true
} }
//群详情列表
val list = findOneByClazz(getRoot(), Views.ListView) val list = findOneByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list.parent.parent) val frontNode = AccessibilityUtil.findFrontNode(list.parent.parent)
@@ -153,6 +156,7 @@ object WeworkRoomUtil {
if (AccessibilityUtil.findOneByText(getRoot(), "设置聊天背景") != null) { if (AccessibilityUtil.findOneByText(getRoot(), "设置聊天背景") != null) {
return true return true
} }
//同群详情列表
val list = findOneByClazz(getRoot(), Views.ListView) val list = findOneByClazz(getRoot(), Views.ListView)
if (list != null) { if (list != null) {
val frontNode = AccessibilityUtil.findFrontNode(list.parent.parent) val frontNode = AccessibilityUtil.findFrontNode(list.parent.parent)
@@ -210,6 +214,7 @@ object WeworkRoomUtil {
* listview前兄弟控件 && text包含外部群 * listview前兄弟控件 && text包含外部群
*/ */
private fun isExternalGroup(): Boolean { private fun isExternalGroup(): Boolean {
//聊天消息列表 1ListView 0RecycleView xViewGroup
val listView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView, limitDepth = null, depth = 0) val listView = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView, limitDepth = null, depth = 0)
if (listView != null) { if (listView != null) {
val frontNode = findFrontNode(listView) val frontNode = findFrontNode(listView)
@@ -226,8 +231,10 @@ object WeworkRoomUtil {
* 有列表和输入框 * 有列表和输入框
*/ */
private fun isSingleChat(): Boolean { private fun isSingleChat(): Boolean {
//聊天消息列表 1ListView 0RecycleView xViewGroup
val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView) val list = AccessibilityUtil.findOnceByClazz(getRoot(), Views.ListView)
val editText = AccessibilityUtil.findOnceByClazz(getRoot(), Views.EditText) val editText = AccessibilityUtil.findOnceByClazz(getRoot(), Views.EditText)
?: AccessibilityUtil.findOnceByText(getRoot(), "按住 说话", "按住说话", exact = true)
if (list != null && editText != null) { if (list != null && editText != null) {
return true return true
} }