我只是查看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应用程序:(不发送消息。
我通过几个链接:Question1,Question2也article,但没有得到满意的答案。
application正在访问通知以获取消息,并回复它,我还尝试使用NotificationListenerService
阅读通知,并成功阅读消息:),但不能发送回复,我想知道他们如何在不打开应用程序的情况下在后台发送邮件。
答案 0 :(得分:1)
在有根设备上,您只需将一条消息插入数据库
/data/data/com.whatsapp/databases/msgstore.db
这样。
首先从数据库获取联系人。 WhatsApp在jid
列中将自己的ID用于联系人(而不是用户号码),必须获取该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();
}
答案 1 :(得分:0)
我还没有测试过,但是我认为可以通过 Read Notification Bar title, message using Accessibility Service Programmatically
和https://developer.android.com/reference/android/app/RemoteInput
来自doc:
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();