如何以编程方式从Android的收件箱中删除短信?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/419184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:07:54  来源:igfitidea点击:

How to delete an SMS from the inbox in Android programmatically?

androidsms

提问by dmyung

On Android phones SMS messages registered to applications also get sent to the device's inbox. However to prevent clutter, it'd be nice to be able to remove application specific SMS messages from the inbox to reduce the potential overflow of those messages.

在 Android 手机上,注册到应用程序的 SMS 消息也会发送到设备的收件箱。但是,为了防止混乱,最好能够从收件箱中删除特定于应用程序的 SMS 消息以减少这些消息的潜在溢出。

Questions on other Google groups on getting a definitive answer on a programmatic way to delete SMS messages from the Android inbox don't seem to be pressing.

其他 Google 小组关于以编程方式从 Android 收件箱中删除 SMS 消息的明确答案的问题似乎并不紧迫。

So the scenario:

所以场景:

  • Android App startup.
  • register SMS message types X,Y and Z
  • messages P,Q,X,Y,Z stream in over the course of time, all deposited in inbox
  • Android application detects receipt of X,Y,Z (presumably as part of the program interrupt event)
  • process X,Y,Z
  • Desirement!!!X,Y,Z are deleted from the Android inbox
  • 安卓应用启动。
  • 注册 SMS 消息类型 X、Y 和 Z
  • 消息 P、Q、X、Y、Z 随时间流进来,全部存放在收件箱中
  • Android 应用程序检测到 X、Y、Z 的接收(大概是程序中断事件的一部分)
  • 处理 X,Y,Z
  • 愿望!!!X、Y、Z 从 Android 收件箱中删除

Has it been done? Can it be done?

已经完成了吗?可以做到吗?

回答by Viktor Fonic

"As of Android 1.6, incoming SMS message broadcasts (android.provider.Telephony.SMS_RECEIVED) are delivered as an "ordered broadcast" — meaning that you can tell the system which components should receive the broadcast first."

“从 Android 1.6 开始,传入的 SMS 消息广播 ( android.provider.Telephony.SMS_RECEIVED) 作为“有序广播”传送——这意味着您可以告诉系统哪些组件应该首先接收广播。”

This means that you can intercept incoming message and abort broadcasting of it further on.

这意味着您可以拦截传入的消息并进一步中止它的广播。

In your AndroidManifest.xmlfile, make sure to have priority set to highest:

在您的AndroidManifest.xml文件中,确保将优先级设置为最高:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

In your BroadcastReceiver, in onReceive()method, before performing anything with your message, simply call abortBroadcast();

在您的BroadcastReceiver, inonReceive()方法中,在对您的消息执行任何操作之前,只需调用abortBroadcast();

EDIT: As of KitKat, this doesn't work anymore apparently.

编辑:从 KitKat 开始,这显然不再起作用。

EDIT2: More info on how to do it on KitKat here:

EDIT2:有关如何在 KitKat 上执行此操作的更多信息:

Delete SMS from android on 4.4.4 (Affected rows = 0(Zero), after deleted)

在 4.4.4 上从 android 删除短信(受影响的行 = 0(零),删除后)

回答by dmyung

Using suggestions from others, I think I got it to work:

使用其他人的建议,我想我可以做到:

(using SDK v1 R2)

(使用 SDK v1 R2)

It's not perfect, since i need to delete the entire conversation, but for our purposes, it's a sufficient compromise as we will at least know all messages will be looked at and verified. Our flow will probably need to then listen for the message, capture for the message we want, do a query to get the thread_id of the recently inbounded message and do the delete() call.

这并不完美,因为我需要删除整个对话,但就我们的目的而言,这是一个足够的妥协,因为我们至少会知道所有消息都会被查看和验证。然后我们的流程可能需要监听消息,捕获我们想要的消息,执行查询以获取最近入站消息的 thread_id 并执行 delete() 调用。

In our Activity:

在我们的活动中:

Uri uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null); 
int id = c.getInt(0);
int thread_id = c.getInt(1); //get the thread_id
getContentResolver().delete(Uri.parse("content://sms/conversations/" + thread_id),null,null);

Note: I wasn't able to do a delete on content://sms/inbox/ or content://sms/all/

注意:我无法删除 content://sms/inbox/ 或 content://sms/all/

Looks like the thread takes precedence, which makes sense, but the error message only emboldened me to be angrier. When trying the delete on sms/inbox/ or sms/all/, you will probably get:

看起来线程优先,这是有道理的,但错误消息只会让我更加愤怒。在 sms/inbox/ 或 sms/all/ 上尝试删除时,您可能会得到:

java.lang.IllegalArgumentException: Unknown URL
    at com.android.providers.telephony.SmsProvider.delete(SmsProvider.java:510)
    at android.content.ContentProvider$Transport.delete(ContentProvider.java:149)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:149)

For additional reference too, make sure to put this into your manifest for your intent receiver:

为了获得更多参考,请确保将其放入您的意图接收器的清单中:

<receiver android:name=".intent.MySmsReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
</receiver>

Note the receiver tag does not look like this:

请注意,接收者标签不是这样的:

<receiver android:name=".intent.MySmsReceiver" 
    android:permission="android.permission.RECEIVE_SMS">

When I had those settings, android gave me some crazy permissions exceptions that didn't allow android.phone to hand off the received SMS to my intent. So, DO NOT put that RECEIVE_SMS permission attribute in your intent! Hopefully someone wiser than me can tell me why that was the case.

当我有这些设置时,android 给了我一些疯狂的权限异常,不允许 android.phone 将收到的 SMS 交给我的意图。所以,不要把 RECEIVE_SMS 权限属性放在你的意图中!希望比我更聪明的人能告诉我为什么会这样。

回答by Doug

So, I had a play, and it ispossible to delete a received SMS. Unfortunately it's not all plain sailing :(

所以,我玩了一下可以删除收到的短信。不幸的是,这并非一帆风顺:(

I have a receiver that picks up on incoming SMS messages. Now the way the Android SMS incoming routing works is that the piece of code responsible for decoding the messages sends a Broadcast (it uses the sendBroadcast()method - which unfortunately is NOT the version that lets you simply call abortBroadcast()) whenever a message arrives.

我有一个接收器可以接收收到的 SMS 消息。现在,Android SMS 传入路由的工作方式是,负责解码消息的代码段会在消息到达时发送广播(它使用该sendBroadcast()方法 - 不幸的是,这不是让您简单地调用的版本abortBroadcast())。

My receiver may or may not be called before the Systems SMS receiver, and in any case the received broadcast has no property that could reflect the _idcolumn in the SMS table.

我的接收器可能会或可能不会在系统 SMS 接收器之前被调用,并且在任何情况下接收到的广播都没有可以反映_idSMS 表中的列的属性。

However, not being one to be stopped that easily I post myself (via a Handler) a delayed message with the SmsMessage as the attached object. (I suppose you could post yourself a Runnable too...)

然而,我不是那么容易被阻止的人,我(通过处理程序)向自己发布了一条延迟消息,并将 SmsMessage 作为附加对象。(我想你也可以给自己贴一个 Runnable ......)

handler.sendMessageDelayed(handler.obtainMessage(MSG_DELETE_SMS, msg), 2500);

The delay is there to ensure that by the time the message arrives all of the Broadcast receivers will have finished their stuff and the message will be safely ensconced in the SMS table.

延迟是为了确保在消息到达时所有广播接收器都将完成他们的工作,并且消息将安全地存放在 SMS 表中。

When the message (or Runnable) is received here is what I do:

当这里收到消息(或 Runnable)时,我会这样做:

case MSG_DELETE_SMS:
    Uri deleteUri = Uri.parse("content://sms");
    SmsMessage msg = (SmsMessage)message.obj;

    getContentResolver().delete(deleteUri, "address=? and date=?", new String[] {msg.getOriginatingAddress(), String.valueOf(msg.getTimestampMillis())});

I use the originating address and timestamp field to ensure a very high probability of deleting ONLY the message I am interested in. If I wanted to be even more paranoid I could include the msg.getMessageBody()content as part of the query.

我使用原始地址和时间戳字段来确保只删除我感兴趣的消息的可能性非常高。如果我想更加偏执,我可以将msg.getMessageBody()内容作为查询的一部分。

Yes, the message IS deleted (hooray!). Unfortunately the notification bar is not updated :(

是的,该消息已被删除(万岁!)。不幸的是,通知栏没有更新:(

When you open up the notification area you'll see the message sitting there for you... but when you tap on it to open it up - it's gone!

当您打开通知区域时,您会看到为您准备的消息......但是当您点击它打开它时 - 它不见了!

To me, this isn't quite good enough - I want all trace of the message to disappear - I don't want the user to think there is a TXT when there isn't (that would only cause bug reports).

对我来说,这还不够好 - 我希望消息的所有痕迹都消失 - 我不希望用户认为没有 TXT(这只会导致错误报告)。

Internally in the OS the phone calls MessagingNotification.updateNewMessageIndicator(Context), but I that class has been hidden from the API, and I did not want to replicate all of that code just for the sake of making the indicator accurate.

在操作系统内部,电话会调用MessagingNotification.updateNewMessageIndicator(Context),但我对 API 隐藏了该类,我不想仅仅为了使指标准确而复制所有这些代码。

回答by Atif Mahmood

public boolean deleteSms(String smsId) {
    boolean isSmsDeleted = false;
    try {
        mActivity.getContentResolver().delete(Uri.parse("content://sms/" + smsId), null, null);
        isSmsDeleted = true;

    } catch (Exception ex) {
        isSmsDeleted = false;
    }
    return isSmsDeleted;
}

use this permission in AndroidManifiest

在 AndroidManifyingt 中使用此权限

<uses-permission android:name="android.permission.WRITE_SMS"/>

回答by Naresh Kavali

Its better to use the _id and thread_id to delete a message.

最好使用 _id 和 thread_id 来删除消息。

Thread_id is something assigned to the messages coming from same user. So, if you use only thread_id, all the messages from the sender will get deleted.

Thread_id 是分配给来自同一用户的消息的东西。因此,如果您仅使用 thread_id,则来自发件人的所有消息都将被删除。

If u use the combination of _id, thread_id, then it will delete the exact message you are looking to delete.

如果您使用 _id、thread_id 的组合,那么它将删除您要删除的确切消息。

Uri thread = Uri.parse( "content://sms");
int deleted = contentResolver.delete( thread, "thread_id=? and _id=?", new String[]{String.valueOf(thread_id), String.valueOf(id)} );

回答by Neil

You'll need to find the URIof the message. But once you do I think you should be able to android.content.ContentResolver.delete(...) it.

您需要找到消息的URI。但是一旦你这样做了,我认为你应该能够 android.content.ContentResolver.delete(...) 它。

Here's some more info.

这里有更多信息

回答by an0

I think this can not be perfectly done for the time being. There are 2 basic problems:

我认为这暂时无法完美完成。有2个基本问题:

  1. How can you make sure the sms is already in the inbox when you try to delete it?
    Notice that SMS_RECEIVED is not an ordered broadcast.
    So dmyung's solution is completely trying one's luck; even the delay in Doug's answer is not a guarantee.

  2. The SmsProvider is not thread safe.(refer to http://code.google.com/p/android/issues/detail?id=2916#c0)
    The fact that more than one clients are requesting delete and insert in it at the same time will cause data corruption or even immediate Runtime Exception.

  1. 当您尝试删除短信时,如何确保该短信已在收件箱中?
    请注意 SMS_RECEIVED 不是有序广播。
    所以dmyung的解决方案完全是碰运气;即使道格的回答延迟也不能保证。

  2. SmsProvider 不是线程安全的。(请参阅http://code.google.com/p/android/issues/detail?id=2916#c0
    事实上,不止一个客户端请求删除并在同时会导致数据损坏甚至立即运行时异常。

回答by Stelian Iancu

I couldn't get it to work using dmyung's solution, it gave me an exception when getting either the message id or thread id.

我无法使用 dmyung 的解决方案让它工作,它在获取消息 ID 或线程 ID 时给了我一个异常。

In the end, I've used the following method to get the thread id:

最后,我使用了以下方法来获取线程 ID:

private long getThreadId(Context context) {
    long threadId = 0;

    String SMS_READ_COLUMN = "read";
    String WHERE_CONDITION = SMS_READ_COLUMN + " = 0";
    String SORT_ORDER = "date DESC";
    int count = 0;

    Cursor cursor = context.getContentResolver().query(
                    SMS_INBOX_CONTENT_URI,
          new String[] { "_id", "thread_id", "address", "person", "date", "body" },
                    WHERE_CONDITION,
                    null,
                    SORT_ORDER);

    if (cursor != null) {
            try {
                count = cursor.getCount();
                if (count > 0) {
                    cursor.moveToFirst();
                    threadId = cursor.getLong(1);                              
                }
            } finally {
                    cursor.close();
            }
    }


    return threadId;
}

Then I could delete it. However, as Doug said, the notification is still there, even the message is displayed when opening the notification panel. Only when tapping the message I could actually see that it's empty.

那我就可以删了。但是,正如道格所说,通知仍然存在,甚至在打开通知面板时显示消息。只有在点击消息时,我才能真正看到它是空的。

So I guess the only way this would work would be to actually somehow intercept the SMS before it's delivered to the system, before it even reaches the inbox. However, I highly doubt this is doable. Please correct me if I'm wrong.

所以我想这唯一可行的方法是在短信发送到系统之前以某种方式拦截它,甚至在它到达收件箱之前。但是,我非常怀疑这是可行的。如果我错了,请纠正我。

回答by Ashish Sahu

Use this function to delete specific message thread or modify according your needs:

使用此功能删除特定的消息线程或根据您的需要进行修改:

public void delete_thread(String thread) 
{ 
  Cursor c = getApplicationContext().getContentResolver().query(
  Uri.parse("content://sms/"),new String[] { 
  "_id", "thread_id", "address", "person", "date","body" }, null, null, null);

 try {
  while (c.moveToNext()) 
      {
    int id = c.getInt(0);
    String address = c.getString(2);
    if (address.equals(thread)) 
        {
     getApplicationContext().getContentResolver().delete(
     Uri.parse("content://sms/" + id), null, null);
    }

       }
} catch (Exception e) {

  }
}

Call this function simply below:

在下面简单地调用这个函数:

delete_thread("54263726");//you can pass any number or thread id here

Don't forget to add android mainfest permission below:

不要忘记在下面添加android mainfest权限:

<uses-permission android:name="android.permission.WRITE_SMS"/>

回答by Noah Seidman

Just turn off notifications for the default sms app. Process your own notifications for all text messages!

只需关闭默认短信应用的通知即可。处理您自己的所有短信通知!