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

最后发布: 2009-01-07 04:25:01


问题

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

关于从Android收件箱中删除短信的程序化方式获得明确答案的其他Google网上论坛的问题似乎并不紧迫。

场景如下:

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

它完成了吗? 可以吗?

android sms
回答

“从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>

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

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

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

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


回答

使用别人的建议,我想我得到了它的工作:

(使用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);

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


回答

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

我有一个接收器,可以接收传入的短信。 现在,Android SMS传入路由的工作方式是负责解码消息的代码片段发送一个广播(它使用sendBroadcast()方法 - 不幸的是,这个版本不是让你只需要调用abortBroadcast() )到达。

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

但是,我不能轻易地停止(通过处理程序)使用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中隐藏了这个类,并且我不想仅仅为了使指标准确而复制所有代码。


回答

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


回答

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

这里有更多信息


回答

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

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. 当您尝试删除短信时,如何确保短信已经在收件箱中?
    请注意,SMS_RECEIVED不是有序广播。
    所以dmyung的解决方案是完全尝试一个人的运气; 即使延迟道格的回答也不是保证。

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


回答

我无法使用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。 但是,我非常怀疑这是可行的。 如果我错了,请纠正我。


回答

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


回答

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


回答

只需看看这个链接,它将简要介绍逻辑:

https://gist.github.com/5178e798d9a00cac4ddb
只是稍微调用deleteSMS()函数,因为通知时间和实际保存时间之间存在细微差别....有关详细信息,请查看此链接........ ..

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

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


回答

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

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


回答

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

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


回答

使用这种方法之一来选择最后收到的短信并删除它,在这种情况下,我得到最顶级的短信,并使用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();
}


回答

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

}


回答

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


回答

删除一条短信而非会话的示例:

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