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

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

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

所以情景:

  • Android应用程序启动。
  • 注册SMS消息typesX,Y和Z
  • 消息P,Q,X,Y,Z在一段时间内stream入,全部存入收件箱
  • Android应用程序检测到收到X,Y,Z(大概是程序中断事件的一部分)
  • 处理X,Y,Z
  • Desirement! X,Y,Z从Android收件箱中删除

它已经完成了吗? 可以这样做吗?

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

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

在您的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 ,在onReceive()方法中,在对消息执行任何操作之前,只需调用abortBroadcast();

编辑:至于KitKat,这显然不工作了。

编辑2:更多信息如何在KitKat上做到这一点:

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

使用别人的build议,我觉得我的工作:

(使用SDK v1 R2)

这不是完美的,因为我需要删除整个对话,但是对于我们的目的来说,这是一个足够的妥协,因为我们至less知道所有的消息将被查看和validation。 我们的stream将可能需要然后侦听消息,捕获我们想要的消息,做一个查询来获取最近inbounded消息的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); 

注意:我无法删除内容:// sms / inbox /或content:// 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将收到的短信交给我的意图。 所以,不要把RECEIVE_SMS权限属性放在你的意图中! 希望有人比我更聪明,可以告诉我为什么这样。

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

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

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

然而,我并不是一个很容易被阻止的人,我(通过一个Handler)发布一个带有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()内容作为查询的一部分。

是的,消息被删除(hooray!)。 不幸的是,通知栏不更新:(

当你打开通知区域,你会看到消息坐在那里…但是当你点击它打开它 – 它消失了!

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

在操作系统内部,手机会调用MessagingNotification.updateNewMessageIndicator(Context) ,但是这个类已经隐藏在API中,我不想仅仅为了使指示器准确而复制所有的代码。

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

在AndroidManifiest中使用此权限

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

最好使用_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)} ); 

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

这里有一些更多的信息 。

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

  1. 当您尝试删除短信时,如何确保短信已经在收件箱中?
    注意,SMS_RECEIVED不是一个有序的广播。
    所以dmyung的解决scheme完全是运气好 即使道格答案的延误也不是保证。

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

我无法使用dmyung的解决scheme,它给了我一个exception,当得到消息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发送到系统之前实际​​上以某种方式拦截SMS,甚至在它到达收件箱之前。 不过,我非常怀疑这是可行的。 如果我错了,请纠正我。

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

 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"/> 

只需closures默认短信应用程序的通知。 处理您自己的所有短信通知!

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

https://gist.github.com/5178e798d9a00cac4ddb
只是调用deleteSMS()函数有一些延迟,因为通知的时间,当它实际上保存时,有一个细微的差异….详情看看这个链接还…….. ..

http://htmlcoderhelper.com/how-to-delete-sms-from-inbox-in-android-programmatically/

谢谢……….

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

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

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

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

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

你只要尝试下面的代码。它会删除所有电话中的所有短信(收到或发送)

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

试试这个,我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) { } 

使用这种方法之一来select最后收到的短信,并删除它,在这种情况下,我得到最上面的短信,并要删除使用线程和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(); }