【问题标题】:Send message via whatsapp programmatically以编程方式通过whatsapp发送消息
【发布时间】:2018-09-14 05:34:05
【问题描述】:

我正在尝试通过 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);
}

谢谢

【问题讨论】:

  • 您只能将用户和他们的消息发送到 WhatsApp,您不能为他们按下按钮。
  • 您不能在没有用户发送确认的情况下直接发送消息。 Whats 应用程序不提供此类功能我认为除非您使用 SDK 进行身份验证,否则任何应用程序都不会提供此类功能。
  • 这是预期行为,您不能直接发送消息,用户需要点击whatsapp发送按钮
  • 我知道,我希望应用程序 24/7 运行以发送一些数据,客户端希望在断电时通过短信或 whtsapp 获得通知

标签: android whatsapp


【解决方案1】:

只能使用 Android 的 Accessibility API 来做到这一点。

这个想法很简单,你实际上会让 Android 执行点击 Whatsapp 的发送按钮。

所以流程将是:

  1. 发送一条常规消息(包含您当前使用的意图),并在消息内容的末尾添加一个后缀,例如“Sent by 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 -&gt; xml -&gt; 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);
}

这纯粹是解决方案的技术方面。

现在,“你应该那样做吗?”的伦理问题,我相信答案很明确:

除非您针对的是残障人士(这正是 Accessibility API 的目的),否则您可能应该这样做。

【讨论】:

  • 您好,谢谢您的回答。别担心,该应用程序是检测断电,而不是短信,我们决定使用whatsapp ..我尝试了您的解决方案,但事件 onAccessibilityEvent 是永远不会被调用,onServiceConnected 被称为思想,你能帮我更多吗..谢谢!
  • 事件 isAccessibilityOn 正在运行!并检测我何时打开whatsapp,但发送功能不起作用
  • @Nizar 检查邮件的后缀部分。
  • @Nizar 在上面代码中的所有条件上都放了一些日志,看看它在哪里退出,这样我们就可以缩小问题的范围。
  • @Nizar,很高兴我能帮上忙。顺便说一句,您会注意到我正在使用支持库的 AccessibilityNodeInfoCompatNOT AccessibilityNodeInfo 正是出于这个原因。 :)
猜你喜欢
  • 2014-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-06
  • 1970-01-01
  • 2018-08-22
相关资源
最近更新 更多