99

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

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

所以场景:

  • 安卓应用启动。
  • 注册 SMS 消息类型 X、Y 和 Z
  • 消息 P、Q、X、Y、Z 在一段时间内流入,全部存入收件箱
  • Android 应用程序检测到 X、Y、Z 的接收(可能是程序中断事件的一部分)
  • 过程 X,Y,Z
  • 愿望!!!X、Y、Z 从 Android 收件箱中删除

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

4

18 回答 18

87

android.provider.Telephony.SMS_RECEIVED“从 Android 1.6 开始,传入的SMS 消息广播(

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

在您的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>

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

编辑:从 KitKat 开始,这显然不再有效。

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

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

于 2011-06-02T06:29:41.567 回答
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 权限属性放在你的意图中!希望比我更聪明的人能告诉我为什么会这样。

于 2009-01-13T15:53:00.567 回答
24

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

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

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

但是,不是一个容易被阻止的人,我(通过处理程序)向自己发布了一条延迟消息,其中 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(这只会导致错误报告)。

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

于 2009-05-12T04:38:45.863 回答
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;
}

在 AndroidManifyt 中使用此权限

<uses-permission android:name="android.permission.WRITE_SMS"/>
于 2012-12-15T18:54:13.760 回答
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)} );
于 2011-08-16T12:56:33.680 回答
5

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

这里有更多信息

于 2009-01-08T21:23:56.353 回答
2

我认为这暂时不能完美地完成。有2个基本问题:

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

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

于 2009-06-08T13:56:07.827 回答
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 所说,通知仍然存在,甚至在打开通知面板时会显示消息。只有在点击消息时,我才能真正看到它是空的。

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

于 2009-06-12T13:08:18.310 回答
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"/>
于 2014-03-15T12:53:01.067 回答
1

看看这个链接,它会给你一个简单的逻辑思路:

https
: //gist.github.com/5178e798d9a00cac4ddb 调用deleteSMS()函数有一定的延迟,因为时间有细微的差别通知的内容以及实际保存的时间....,有关详细信息,还请查看此链接..........

http://htmlcoderhelper.com/how-to-delete-sms-from-收件箱-in-android-programmatically/

谢谢............

于 2010-12-27T10:10:05.923 回答
1

还要更新清单文件以删除您需要写入权限的短信。

<uses-permission android:name="android.permission.WRITE_SMS"/>
于 2011-08-08T12:11:51.240 回答
1

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

于 2010-06-21T17:34:22.403 回答
1

NowabortBroadcast();方法可用于限制传入消息进入收件箱。

于 2012-07-03T12:19:12.020 回答
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);
}
于 2010-12-28T10:44:48.080 回答
0

删除一条短信而不是对话的示例:

getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadID), "_id = ?", new String[]{id});
于 2011-01-22T02:37:19.130 回答
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;
}
于 2013-10-14T09:29:15.187 回答
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) {

}
于 2013-09-03T11:36:50.733 回答
-1

使用这种方法之一选择最后收到的短信并将其删除,在这种情况下,我将获得最多的短信并使用短信的线程和 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();
}
于 2012-12-10T18:06:50.783 回答