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


98

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

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

因此场景:

  • Android App启动。
  • 注册短信类型X,Y和Z
  • 随着时间的流逝,消息P,Q,X,Y,Z流全部存储在收件箱中
  • Android应用程序检测到X,Y,Z的接收(可能是程序中断事件的一部分)
  • 过程X,Y,Z
  • 欲望!!!X,Y,Z已从Android收件箱中删除

完成了吗 能做到吗


4
我发现使用Android的电话功能做任何有用的事情都是非常不愉快的体验。
BobbyShaftoe

1
好问题的伙伴。我正在寻找类似的东西:D欢呼
Harsha MV 2010年

3
最好是防止短信到达摆在首位的收件箱:stackoverflow.com/questions/1741628/...
克里斯托弗·奥尔

Answers:


87

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

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

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>

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

编辑:自KitKat以来,这显然不再起作用。

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

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




最好的答案= D
Mike Brian Olivera

27

使用别人的建议,我想我可以使用它:

(使用SDK v1 R2)

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

在我们的活动中:

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);

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

看起来线程优先,这是有道理的,但是错误消息只会使我感到愤怒。在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)

同样,还提供其他参考,请确保将其放入您的意图接收者的清单中:

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

注意接收者标签看起来不是这样的:

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

当我进行了这些设置时,android给了我一些疯狂的权限异常,这些异常不允许android.phone将接收到的SMS传递给我。因此,请勿将RECEIVE_SMS权限属性放入您的意图中!希望有人比我聪明,可以告诉我为什么会这样。



24

所以,我有一出戏,它可以删除收到的短信。不幸的是,这并非一帆风顺。

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

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

但是,不是一个容易被阻止的人,我(通过处理程序)以SmsMessage作为附加对象发布了自己的延迟消息。(我想您也可以将自己发布为Runnable ...)

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

这样做有一定的延迟,以确保在消息到达时,所有广播接收器都将完成其填充,并且消息将被安全地保存在SMS表中。

当收到消息(或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())});

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

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

当您打开通知区域时,您会看到坐在那里的消息……但是当您点击它以打开它时,消息就消失了!

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

在OS内部,电话MessagingNotification.updateNewMessageIndicator(Context),但是我已经将该类从API中隐藏了,我不想为了确保指示器的准确性而复制所有代码。


道格,太好了。作为一个问题,您是否知道是否有必要向处理程序发布帖子?我想知道是否在调用广播接收器和广播接收器之前将SMS插入到系统SMS数据库中?我可能必须调查一下OS才能看到插入发生的位置,但我假设将SMS插入某些数据库是在通知广播接收者之前发生的。有对此的任何见解或您是否已经检查过?
哈米2010年


11
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;
}

在AndroidManifiedt中使用此权限

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

1
我们如何获得短信ID?
Dev01 2014年


@ Dev01如果要删除特定的短信,必须具有其ID对吗?如果不是的话,您必须使用地址或smsbody来查询ID
Dr. aNdRO '18

6

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

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

如果您使用_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)} );


5

您需要找到URI消息。但是一旦完成,我认为您应该可以android.content.ContentResolver.delete(...)。

这是更多信息


2

我认为暂时还不能完全做到这一点。有两个基本问题:

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

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


2

我无法使用dmyung的解决方案使其工作,它在获取消息ID或线程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;
}

然后我可以删除它。但是,正如Doug所说,通知仍然存在,即使在打开通知面板时也显示消息。只有点击消息时,我才能真正看到它为空。

因此,我想这是唯一可行的方法,实际上是在SMS到达系统之前,甚至在到达收件箱之前以某种方式拦截它。但是,我高度怀疑这是否可行。如果我错了,请纠正我。


好吧,在收件箱之前拦截消息错误的:您可以收到广播的android.provider.Telephony.SMS_RECEIVED,只需要一个android.permission.RECEIVE_SMS权限。您甚至可以通过调用abortBroadcast()轻松地阻止消息到达收件箱,因为它是有序广播。PS必须很有趣,才能在2年后得到纠正:)
青金石

2

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

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) {

  }
}

在下面简单地调用此函数:

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

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

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



1

您只需尝试以下代码,它将删除手机中所有的短信(已接收或已发送)

Uri uri = Uri.parse("content://sms");

ContentResolver contentResolver = getContentResolver();

Cursor cursor = contentResolver.query(uri, null, null, null,
  null);



while (cursor.moveToNext()) {

 long thread_id = cursor.getLong(1);
 Uri thread = Uri.parse("content://sms/conversations/"
   + thread_id);
 getContentResolver().delete(thread, null, null);
}



0

用于删除一条短信(而非对话)的示例:

getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadID), "_id = ?", new String[]{id});

0
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    SMSData sms = (SMSData) getListAdapter().getItem(position);
    Toast.makeText(getApplicationContext(), sms.getBody(),
            Toast.LENGTH_LONG).show();
    Toast.makeText(getApplicationContext(), sms.getNumber(),
            Toast.LENGTH_LONG).show();

    deleteSms(sms.getId());

}

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

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

0

试试这个,我100%肯定可以正常工作:-//只需将转换地址放在此处,即可按地址删除整个转换(不要忘记在mainfest中添加读取,写入权限)这是代码:

String address="put address only";

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(address)){
        getApplicationContext().getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);}
    }
} catch(Exception e) {

}

0

使用此方法之一选择最后收到的SMS并将其删除,在这种情况下,我得到的短信最多,并使用线程和短信的id值删除,

try {
    Uri uri = Uri.parse("content://sms/inbox");
    Cursor c = v.getContext().getContentResolver().query(uri, null, null, null, null);
    int i = c.getCount();

    if (c.moveToFirst()) {
    }
} catch (CursorIndexOutOfBoundsException ee) {
    Toast.makeText(v.getContext(), "Error :" + ee.getMessage(), Toast.LENGTH_LONG).show();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.