You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用Android无障碍API结合后缀自动点击WhatsApp发送按钮

校园应用WhatsApp批量发送功能:后缀触发无障碍服务实现自动发送

首先感谢朋友的分享,让我接触到Android无障碍工具的相关知识。我正在开发一款校园应用,核心需求是向家长的WhatsApp批量发送学生记录——在列表视图中录入学生的WhatsApp号码后,点击按钮就能自动给所有号码发送消息。已知发送WhatsApp消息需要手动点击发送按钮,希望通过无障碍服务实现自动点击;目前已经能通过代码引导用户开启无障碍服务,现在需要解决的是如何用特定后缀触发无障碍服务执行自动发送操作。

我当前的无障碍服务代码

AccessibilityNodeInfoCompat rootInActiveWindow = AccessibilityNodeInfoCompat.wrap(getRootInActiveWindow());

// 定位WhatsApp消息输入框
List<AccessibilityNodeInfoCompat> messageNodeList = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.whatsapp:id/entry");
if (messageNodeList == null || messageNodeList.isEmpty()) {
    return;
}

// 检查输入框内容是否以指定后缀结尾
AccessibilityNodeInfoCompat messageField = messageNodeList.get(0);
if (messageField.getText() == null || messageField.getText().length() == 0 
    || !messageField.getText().toString().endsWith(getApplicationContext().getString(R.string.whatsapp_suffix))) {
    return;
}

// 定位WhatsApp发送按钮
List<AccessibilityNodeInfoCompat> sendMessageNodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.whatsapp:id/send");
if (sendMessageNodeInfoList == null || sendMessageNodeInfoList.isEmpty()) {
    return;
}

AccessibilityNodeInfoCompat sendMessageButton = sendMessageNodeInfoList.get(0);
if (!sendMessageButton.isVisibleToUser()) {
    return;
}

// 触发发送按钮点击
sendMessageButton.performAction(AccessibilityNodeInfo.ACTION_CLICK);

// 返回应用:先退出聊天界面,再退出WhatsApp
try {
    Thread.sleep(500); // 适配部分设备,避免返回操作过快失效
    performGlobalAction(GLOBAL_ACTION_BACK);
    Thread.sleep(500);
} catch (InterruptedException ignored) {}
performGlobalAction(GLOBAL_ACTION_BACK);
}

// 检查无障碍服务状态,未开启则跳转系统设置
if (!isAccessibilityOn(context, WhatsappAccessibilityService.class)) {
    Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
    context.startActivity(intent);
}

我当前的发送消息代码

send.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        try {
            String suffix;
            suffix = String.valueOf(R.string.whatsapp_suffix);

            PackageManager packageManager = MainActivity.this.getPackageManager();
            Intent i = new Intent(Intent.ACTION_VIEW);
           
            if (i.resolveActivity(packageManager) != null) {
                MainActivity.this.startActivity(i);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }
});

实现后缀触发的关键修正与步骤

1. 修复发送消息代码的核心问题

当前发送代码没有正确构造WhatsApp跳转链接,也未传入包含触发后缀的消息内容,导致无障碍服务无法检测到触发条件。修改后的代码如下:

// 维护待发送的家长号码队列(批量发送用)
private Queue<String> parentPhoneQueue = new LinkedList<>();

// 初始化队列(示例,实际从列表视图读取所有号码)
private void initPhoneQueue() {
    parentPhoneQueue.add("+8613xxxxxxxxx"); // 号码需带国家码
    parentPhoneQueue.add("+8613yyyyyyyyy");
}

// 发送按钮点击事件
send.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        initPhoneQueue();
        sendNextMessage(); // 开始发送第一个号码
    }
});

// 发送单个号码的逻辑
private void sendNextMessage() {
    if (parentPhoneQueue.isEmpty()) {
        Toast.makeText(this, "所有消息已发送完成", Toast.LENGTH_SHORT).show();
        return;
    }

    try {
        String targetPhone = parentPhoneQueue.poll();
        // 替换为实际的学生记录内容
        String studentRecord = "学生张三的本月考勤:全勤";
        // 获取触发后缀(注意用getString,不要用String.valueOf拿资源ID)
        String triggerSuffix = getString(R.string.whatsapp_suffix);
        // 拼接完整消息(记录+后缀)
        String fullMessage = studentRecord + triggerSuffix;

        // 构造WhatsApp跳转URI,编码消息避免乱码
        String whatsappUri = "https://api.whatsapp.com/send?phone=" + targetPhone + "&text=" + Uri.encode(fullMessage);

        Intent sendIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(whatsappUri));
        sendIntent.setPackage("com.whatsapp"); // 指定仅打开WhatsApp

        if (sendIntent.resolveActivity(getPackageManager()) != null) {
            startActivity(sendIntent);
        } else {
            Toast.makeText(this, "未安装WhatsApp", Toast.LENGTH_SHORT).show();
        }
    } catch (Exception e) {
        e.printStackTrace();
        sendNextMessage(); // 发送失败则跳过当前号码,继续下一个
    }
}

2. 确保无障碍服务的触发逻辑生效

你的无障碍服务已经有后缀判断逻辑,但需要补充以下配置确保正常工作:

  • 在AndroidManifest.xml中正确注册无障碍服务:
<service
    android:name=".WhatsappAccessibilityService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_config" />
</service>
  • 在res/xml目录下创建accessibility_config.xml,配置仅监听WhatsApp事件:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeWindowStateChanged|typeViewTextChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagDefault"
    android:canPerformGestures="true"
    android:canRetrieveWindowContent="true"
    android:description="@string/accessibility_desc"
    android:packageNames="com.whatsapp" />
  • 确保R.string.whatsapp_suffix是一个特殊字符串(比如"[AutoSend_CampusApp]"),避免用户输入内容误触发服务。

3. 批量发送的流程衔接

当无障碍服务完成发送并返回应用后,需要触发下一个号码的发送。可以通过本地广播实现:

  • 在无障碍服务的返回操作后发送广播:
// 发送完消息并返回应用后
Intent broadcastIntent = new Intent("com.yourpackage.SEND_NEXT");
sendBroadcast(broadcastIntent);
  • 在MainActivity中注册广播接收器:
private BroadcastReceiver sendNextReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        sendNextMessage();
    }
};

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(sendNextReceiver, new IntentFilter("com.yourpackage.SEND_NEXT"));
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(sendNextReceiver);
}

内容的提问来源于stack exchange,提问作者Maria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:22:13