通过编程方式发送WhatsApp消息

27

我想以编程的方式发送 Whatsapp 消息,代码可以工作,但用户需要点击发送按钮。我需要应用程序完成所有操作(所有用户交互)。解决此问题的一种方法如下:

进入菜单按钮>设置>聊天,并勾选“回车即发送”选项

这是我正在使用的代码:

protected void sendwts(){
    String smsNumber = "2126123456789"; // E164 format without '+' sign
    Intent sendIntent = new Intent(Intent.ACTION_SEND);
    //  Intent sendIntent = new Intent(Intent.ACTION_SENDTO);
    sendIntent.setType("text/plain");
    sendIntent.putExtra(Intent.EXTRA_TEXT, "test \n");
    sendIntent.putExtra("jid", smsNumber + "@s.whatsapp.net"); //phone number without "+" prefix
    sendIntent.setPackage("com.whatsapp");

    startActivity(sendIntent);
}

谢谢你


1
您不能在未收到用户确认的情况下直接发送消息。WhatsApp没有提供此功能,我认为除非您使用SDK进行身份验证,否则没有任何应用程序提供此功能。 - ADM
我知道,我希望这个应用程序可以全天候运行以发送某些数据,客户希望在电力中断发生时通过短信或Whatsapp接收通知。 - Nizar
Whats App 避免在没有用户交互的情况下发送消息,这是良好的行为。 - Khalid Taha
1
突然答案出现了。哈哈。 - gumuruh
显示剩余3条评论
1个回答

58
你只能使用Android的无障碍API来完成此操作。
这个想法很简单,实际上你将让Android点击Whatsapp的发送按钮。
所以流程将是:
1.发送一个常规消息(使用当前意图),并在您的消息内容末尾添加后缀,例如“由MY_APP发送”。
2.一旦文本到达,您的辅助服务将被通知WhatsApp的EditText已填充。
3.如果WhatsApp的EditText中存在后缀,则您的辅助服务将单击发送按钮。(这是为了避免在用户自然键入常规消息时执行操作)。
以下是一个示例(如果您想使其更加严格,可以进行微调):
public class WhatsappAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent (AccessibilityEvent event) {
        if (getRootInActiveWindow () == null) {
            return;
        }

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

        // Whatsapp Message EditText id
        List<AccessibilityNodeInfoCompat> messageNodeList = rootInActiveWindow.findAccessibilityNodeInfosByViewId ("com.whatsapp:id/entry");
        if (messageNodeList == null || messageNodeList.isEmpty ()) {
            return;
        }

        // check if the whatsapp message EditText field is filled with text and ending with your suffix (explanation above)
        AccessibilityNodeInfoCompat messageField = messageNodeList.get (0);
        if (messageField.getText () == null || messageField.getText ().length () == 0 
            || !messageField.getText ().toString ().endsWith (getApplicationContext ().getString (R.string.whatsapp_suffix))) { // So your service doesn't process any message, but the ones ending your apps suffix
            return;
        }

        // Whatsapp send button id
        List<AccessibilityNodeInfoCompat> sendMessageNodeInfoList = rootInActiveWindow.findAccessibilityNodeInfosByViewId ("com.whatsapp:id/send");
        if (sendMessageNodeInfoList == null || sendMessageNodeInfoList.isEmpty ()) {
            return;
        }

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

        // Now fire a click on the send button
        sendMessageButton.performAction (AccessibilityNodeInfo.ACTION_CLICK);

        // Now go back to your app by clicking on the Android back button twice: 
        // First one to leave the conversation screen 
        // Second one to leave whatsapp
        try {
            Thread.sleep (500); // hack for certain devices in which the immediate back click is too fast to handle
            performGlobalAction (GLOBAL_ACTION_BACK);
            Thread.sleep (500);  // same hack as above
        } catch (InterruptedException ignored) {}
        performGlobalAction (GLOBAL_ACTION_BACK);
    }
}

然后在res -> xml -> whatsapp_service.xml中创建它的定义:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeWindowContentChanged"
    android:packageNames="com.whatsapp"
    android:accessibilityFeedbackType="feedbackSpoken"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"/>

然后在你的清单文件中声明:

<service
    android:name=".services.WhatsappAccessibilityService"
    android:label="Accessibility Service"
   android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/whatsapp_service"/>

    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService"/>
    </intent-filter>
</service>

最后一件事是检查你的应用是否启用了辅助功能服务,如果没有,则将用户重定向到设置页面:

private boolean isAccessibilityOn (Context context, Class<? extends AccessibilityService> clazz) {
    int accessibilityEnabled = 0;
    final String service = context.getPackageName () + "/" + clazz.getCanonicalName ();
    try {
        accessibilityEnabled = Settings.Secure.getInt (context.getApplicationContext ().getContentResolver (), Settings.Secure.ACCESSIBILITY_ENABLED);
    } catch (Settings.SettingNotFoundException ignored) {  }

    TextUtils.SimpleStringSplitter colonSplitter = new TextUtils.SimpleStringSplitter (":");

    if (accessibilityEnabled == 1) {
        String settingValue = Settings.Secure.getString (context.getApplicationContext ().getContentResolver (), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
        if (settingValue != null) {
            colonSplitter.setString (settingValue);
            while (colonSplitter.hasNext ()) {
                String accessibilityService = colonSplitter.next ();

                if (accessibilityService.equalsIgnoreCase (service)) {
                    return true;
                }
            }
        }
    }

    return false;
}

你将使用以下方式进行调用:

if (!isAccessibilityOn (context, WhatsappAccessibilityService.class)) {
    Intent intent = new Intent (Settings.ACTION_ACCESSIBILITY_SETTINGS);
    context.startActivity (intent);
}

这纯粹是针对解决方案技术层面的讨论。
现在,道德问题“你应该这样做吗?”,我认为答案非常明确:
除非你的目标是残疾人群体(这也是无障碍API的主要目的),否则你可能不应该这样做。

它可以工作。只是在findAccessibilityNodeInfosByViewId上我得到了null,之后它停止发送消息。我只能发送3-4个联系人中的10个。有人可以检查一下吗? - Harshal Benake
@HarshalBennake,你能帮忙解决这个问题吗?我尝试了这个解决方案,但只有在调试模式下才能运行,不能直接从Android Studio中运行应用程序。 - Hasmukh Kachhatiya
这个很完美,唯一的问题是当联系人没有WhatsApp账户时,它会卡住。 - Ravi
@Hasmukhkachhatiya 发送了兄弟。 - Neelay Srivastava
1
技术上是的,如果你把原生模块集成进去的话。 - Syed M. Sannan
显示剩余16条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接