承香墨影
最快捷的技术进阶之路
题图:by Pleasantblake
Hi,大家好,我是承香墨影!
前两天写了一篇文章,讲 Android 的辅助模式,今天再补充一个实际的例子,看看实际使用 Accessibility 进行开发的整个流程!
还不了解辅助模式(Accessibility)的,可以先看看之前的文章☞「Android 的辅助模式」。
Accessibility 的例子
网上很多例如抢微信红包、Apk 安装的例子,今天写个新的例子,希望大家对整个流程有一个概念。
首先,为了简化流程,提前在微信里打开某一篇待分享的文章,我们只需要处理后续模拟一直到分享完成的整个步骤。
拆分一下步骤:
微信文章页面,点击右上角“···”按钮。
弹出选择框,点击“分享给朋友”。
进入分享选择页,选择右上角“多选”按钮。
找到列表里“承香墨影”,选中。
找到右上角,点击“发送”。
在分享弹窗上的输入框中,输入“分享给你一篇好文章”。
分享弹窗上,点击“发送”。
在开始编写代码之前,我们还需要一些准备工作,拿到一些必要的信息,例如不同页面上,控件对应的 ViewID。
准备工作
分析步骤之后,我们接下来就需要找到不同页面下,我们要操作的关键节点(NodeInfo),那些按钮的 ID,通过 ID 去查找关键节点是一个比较稳妥的方法。
查找 ViewId,可以使用 Android Device Monitor,可以在 Tools → Android → Android Device Monitor
打开。
Android Device Monitor 非常好用,只需要选中我们需要查找的 View,就会自动显示它的信息。
Android Device Monitor,不太稳定,有些设备可能无法进入此页面,推荐直接换个设备或者使用模拟器。
例如这里找到的 “···” 按钮的 ID,就是 com.tencent.mm:id/hh
,并且是一个 ImageButton,如果上面有文字,还可以看到它的 Text 内容,后续可以根据 Text 的内容进行简单的筛选。
根据上面的步骤,查找到不同页面的 ID:
微信文章页面,"···" 按钮:
com.tencent.mm:id/hh
。弹出选择框,“分享给朋友” 按钮:
com.tencent.mm:id/ge
。进入分享选择页,"多选"按钮:
com.tencent.mm:id/hg
。联系人列表每一项中 名称 的TextView:
com.tencent.mm:id/lp
。右上角,"发送" 按钮:
com.tencent.mm:id/hg
。分享弹窗上的输入框:
com.tencent.mm:id/anb
。分享弹窗上,“发送”按钮:
com.tencent.mm:id/an3
。
准备工作做好之后,就开始写具体的逻辑代码了。
编写转发小工具
准备工作做好了,就开始编写转发小工具了。整个小工具的核心功能,其实就是找到 NodeInfo ,然后点击或者填入文本数据。
1. 找到NodeInfo
我们可以通过 findAccessibilityNodeInfoByViewId()
方法,找到 ViewId 对应的 NodeInfo ,前面的准备工作,已经把 ViewId 找到了。但是一般这个方法可能会找到很多个 NodeInfo,所以我们还需要根据文本去做一次筛选。
private fun findNodeInfo(viewId: String, findText: String = "", containsText: String = ""): AccessibilityNodeInfo? {
var mNodeInfo = rootInActiveWindow
var items = mNodeInfo.findAccessibilityNodeInfosByViewId(viewId)
var isEquals = !TextUtils.isEmpty(findText)
for (item in items) {
if (TextUtils.isEmpty(findText) && TextUtils.isEmpty(containsText)) {
// 如果两个都不传递,就点击最先找到的 Node
return item
}
if (isEquals) {
if (item.text.toString().equals(findText)) {
return item
}
} else {
if (item.text.toString().contains(containsText)) {
return item
}
}
}
return null
}
一个通用的方法,我们根据找到的 NodeInfo 中的 Text 再做一次筛选,找到最符合我们要求的 NodeInfo 再返回。注意这里为 Text 的条件做了区分,可以使用 equals()
也可以使用 contains()
。
2. 模拟点击
找到关键的 NodeInfo 之后,我们就可以通过 performAction()
方法,向他传递一个 AccessibilityNodeInfo.ACTION_CLICK
事件即可。
private fun nodeClick(node: AccessibilityNodeInfo?) {
var clickNode = node;
while (clickNode != null) {
if (clickNode.isClickable) {
clickNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)
break;
}
clickNode = node?.parent
}
}
private fun findNodeClick(viewId: String, findText: String = "", containsText: String = "") {
Thread.sleep(1000);
var findNodeInfo = findNodeInfo(viewId, findText, containsText)
if (findNodeInfo != null) {
nodeClick(findNodeInfo)
}
}
为了避免上一个事件执行之后,页面没有立刻响应,我们在所有的事件执行之前,都强行 sleep(1000)
。
3. 在文本框里输入内容
最后分享弹窗之上,还有一个文本框,我们需要填入内容“分享给你一篇好文章”。
private fun nodeSetText(node: AccessibilityNodeInfo?, text: String) {
Thread.sleep(1000);
var argument = Bundle()
argument.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text)
node?.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, argument)
}
到此,基础的几个主要的方法就已经实现了。
4. 将整个流程串联起来
fun startWeForwarding() {
var wechatIntent = packageManager!!.getLaunchIntentForPackage("com.tencent.mm")
startActivity(wechatIntent);
var mNodeInfo = rootInActiveWindow
if (mNodeInfo != null) {
findNodeClick(WENZHANG_JIAHAO)
findNodeClick(SEND_FRIEND_BTN, "发送给朋友")
findNodeClick(SHARE_MULTI_SELECT, "多选")
findNodeClick(SHARE_ITEM_NAME, "承香墨影")
findNodeClick(SEND_BTN, containsText = "发送")
var editNodeInfo = findNodeInfo(EDIT_MESSAGE)
nodeSetText(editNodeInfo,"分享给你一篇好文章")
findNodeClick(DIALOG_SEND_BTN,"发送")
}
}
最后看看执行的效果:
小结
辅助模式的权限很大,至于它能实现什么功能,完全靠你的想象力。
「联机圆桌」????一年 50 个优质问题,上桌联机学习。
公众号后台回复成长『成长』,将会得到我准备的学习资料,也能回复『加群』,一起学习进步;你还能回复『提问』,向我发起提问。
推荐阅读:
![](https://i-blog.csdnimg.cn/blog_migrate/73933f04a5850878fb2eb0a6c9da96da.png)
听说喜欢留言的人,运气都不会太差