【问题标题】:Auto Reply to WhatsApp message in background在后台自动回复 WhatsApp 消息
【发布时间】:2019-06-17 04:30:17
【问题描述】:

我刚刚查看了Application,正在后台自动回复 WhatsApp 消息。我也尝试这样做,但无法成功。 我试过了:

 Intent sendIntent = new Intent();
 sendIntent.setAction(Intent.ACTION_SEND);
 sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
 sendIntent.setType("text/plain");
 sendIntent.setPackage("com.whatsapp");
 startActivity(sendIntent);

但它打开了 WhatsApp 应用程序 :(,不发送消息。

我浏览了几个链接:Question1Question2 以及 article,但没有得到满意的答案。

application正在访问通知以获取消息并回复它,我也尝试使用NotificationListenerService阅读通知,并成功阅读消息:),但无法发送回复,我想知道他们如何在不打开应用程序的情况下在后台发送消息。

【问题讨论】:

  • 您需要一个号码才能发送消息。您必须发送到特定号码。
  • @AAShakil 你检查过我上面提到的应用程序,它没有接受任何用户输入,它直接回复 WhatsApp 消息。
  • 老实说,我认为他们对click to chat 做了一个解决方法。您可以尝试在自定义 web 视图中打开它并通过代码单击按钮。但不确定
  • @Rocky 你有解决办法吗!

标签: android android-notifications whatsapp accessibilityservice


【解决方案1】:

我没有对此进行测试,但我认为这可以通过 Read Notification Bar title, message using Accessibility Service Programmatically

https://developer.android.com/reference/android/app/RemoteInput

来自文档:

 public static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
 Notification.Action action = new Notification.Action.Builder(
         R.drawable.reply, "Reply", actionIntent)
         .addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT)
                 .setLabel("Quick reply").build())
         .build();

【讨论】:

    【解决方案2】:

    在有根设备上,您可以简单地将消息插入数据库 /data/data/com.whatsapp/databases/msgstore.db 像这样。

    首先从数据库中获取联系人。 WhatsApp 在jid 列中使用自己的联系人 ID(不是用户号码),必须得到它和 display name

     class Contact{
    public String jid;
    public String displayName;
    public Contact(String displayName,String jid){
    this.displayName = displayName;
    this.jid = jid;
    }
    }
    public List<Contact> getContacts(){
         Shell.SU.run("am force-stop com.whatsapp");
         Shell.SU.run("chmod 777 /data/data/com.whatsapp");
                            db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/com.whatsapp/databases/wa.db"), null);
                            List<Contact> contactList = new LinkedList<>();
                            String selectQuery = "SELECT  jid, display_name FROM wa_contacts where phone_type is not null and is_whatsapp_user = 1";
                            Cursor cursor = db.rawQuery(selectQuery, null);
                            if (cursor.moveToFirst()) {
                                do {
                                    Contact contact = new Contact(cursor.getString(1), cursor.getString(0));
                                    contactList.add(contact);
                                } while (cursor.moveToNext());
                            }
                            db.close();
    }
    

    然后像这样发送消息

        private void sendBigMessage(String jid, String msg, String file, String mimeType) {
    
         Shell.SU.run("am force-stop com.whatsapp");
     db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/com.whatsapp/databases/msgstore.db"), null);
    
                long l1;
                long l2;
                int k;
                String query2, query1;
    
                Random localRandom = new Random(20L);
                l1 = System.currentTimeMillis();
                l2 = l1 / 1000L;
                k = localRandom.nextInt();
    
                int mediaType = 0;
    
                if (mimeType == null || mimeType.length() < 2)
                    mediaType = 0;
                else
                    mediaType = (mimeType.contains("video")) ? 3
                            : (mimeType.contains("image")) ? 1
                            : (mimeType.contains("audio")) ? 2
                            : 0;
    
                ContentValues initialValues = new ContentValues();
                initialValues.put("key_remote_jid", jid);
                initialValues.put("key_from_me", 1);
                initialValues.put("key_id", l2 + "-" + k);
                initialValues.put("status", 1);
                initialValues.put("needs_push", 0);
                initialValues.put("timestamp", l1);
                initialValues.put("media_wa_type", mediaType);
                initialValues.put("media_name", file);
                initialValues.put("latitude", 0.0);
                initialValues.put("longitude", 0.0);
                initialValues.put("received_timestamp", l1);
                initialValues.put("send_timestamp", -1);
                initialValues.put("receipt_server_timestamp", -1);
                initialValues.put("receipt_device_timestamp", -1);
                initialValues.put("raw_data", -1);
                initialValues.put("recipient_count", 0);
                initialValues.put("media_duration", 0);
    
                if (!TextUtils.isEmpty(file) && !TextUtils.isEmpty(mimeType)) {
                    //boolean isVideo = mimeType.contains("video");
                    Bitmap bMap = null;
                    File spec;
                    if (mediaType == 3) {
                        spec = new File(vidFolder, file);
                        bMap = ThumbnailUtils.createVideoThumbnail(spec.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
                    } else if(mediaType == 2) {
                        spec = new File(audFolder, file);
                    }else{
                        spec = new File(imgFolder, file);
                        bMap = BitmapFactory.decodeFile(spec.getAbsolutePath());
                    }
                    long mediaSize = (file.equals("")) ? 0 : spec.length();
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    if(mediaType == 1 || mediaType ==3) {
                        bMap = Bitmap.createScaledBitmap(bMap, 100, 59, false);
                        bMap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
                    }
                    byte[] bArray = bos.toByteArray();
    
                    MediaData md = new MediaData();
                    md.fileSize = mediaSize;
                    md.file = spec;
                    md.autodownloadRetryEnabled = true;
                    byte[] arr = SerializationUtils.serialize(md);
    
                    initialValues.put("thumb_image", arr);
                    initialValues.put("quoted_row_id", 0);
                    //initialValues.put("media_mime_type", mimeType);
                    //initialValues.put("media_hash", "9vZ3oZyplgiZ40jJvo/sLNrk3c1fuLOA+hLEhEjL+rg=");
                    initialValues.put("raw_data", bArray);
                    initialValues.put("media_size", mediaSize);
                    initialValues.put("origin", 0);
                    initialValues.put("media_caption", msg);
                } else
                    initialValues.put("data", msg);
    
                long idm = db.insert("messages", null, initialValues);
    
                query1 = " insert into chat_list (key_remote_jid) select '" + jid
                        + "' where not exists (select 1 from chat_list where key_remote_jid='" + jid + "');";
    
                query2 = " update chat_list set message_table_id = (select max(messages._id) from messages) where chat_list.key_remote_jid='" + jid + "';";
    
    
                ContentValues values = new ContentValues();
                values.put("docid", idm);
                values.put("c0content", "null  ");
                db.insert("messages_fts_content", null, values);
    
    
                db.execSQL(query1 + query2);
     db.close();
            }
    

    【讨论】:

    • 我想知道在非 root 设备上执行此操作。
    • 在非 root 设备上,可能有 Google 现在和 WhatsApp 用来通信的广播接收器。不幸的是,它不公开
    • 实际上这不起作用。在我的应用程序上,我有权读取和写入外部存储器,Whatsapp 被 su 命令正确终止,但 SQLiteDatabase.openOrCreateDatabase 命令无法打开数据库。我收到以下日志:错误代码:1806 (SQLITE_CANTOPEN_EACCES) 原因:应用程序无权打开指定的数据库文件
    • @Gaucho 我目前正忙于工作,我会看看这个问题并回复你
    • @Gaucho,调用 chmod 添加权限Shell.SU.run("chmod 777 /data/data/com.whatsapp");。查看更新的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-06
    相关资源
    最近更新 更多