Как программно удалить смс из папки входящих в Android?

98

На телефонах Android SMS-сообщения, зарегистрированные в приложениях, также отправляются в почтовый ящик устройства. Однако для предотвращения беспорядка было бы неплохо иметь возможность удалять SMS-сообщения, специфичные для приложения, из почтового ящика, чтобы уменьшить потенциальное переполнение этих сообщений.

Вопросы в других группах Google о получении окончательного ответа о программном способе удаления SMS-сообщений из почтового ящика Android не кажутся актуальными.

Итак, сценарий:

  • Запуск Android-приложения.
  • зарегистрировать типы SMS-сообщений X, Y и Z
  • сообщения P, Q, X, Y, Z передаются с течением времени, и все они хранятся во входящих
  • Приложение Android обнаруживает получение X, Y, Z (предположительно как часть события прерывания программы)
  • процесс X, Y, Z
  • Желание !!! X, Y, Z удаляются из почтового ящика Android.

Это было сделано? Это можно сделать?

dmyung
источник
4
Я обнаружил, что делать что-нибудь полезное с телефонными возможностями Android очень неприятно.
BobbyShaftoe,
1
хороший вопрос товарищ. я искал что-то подобное: D ура
Harsha MV
3
Лучше всего было бы в первую очередь не допустить попадания SMS во входящие: stackoverflow.com/questions/1741628/…
Кристофер Орр,

Ответы:

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>

В вашем BroadcastReceiver, вonReceive() методе , прежде чем выполнять что-либо с вашим сообщением, просто вызовитеabortBroadcast();

РЕДАКТИРОВАТЬ: Что касается KitKat, это, по-видимому, больше не работает.

EDIT2: Подробнее о том, как это сделать на KitKat, можно здесь:

Удалить SMS с android на 4.4.4 (Затронутые строки = 0 (ноль) после удаления)

Виктор Фонич
источник
3
И обязательно посмотрите stackoverflow.com/questions/1741628/…
Майкл Леви,
Не могли бы вы увидеть здесь stackoverflow.com/questions/25988574/… ?
Гангадхар Нимбалли
Лучший ответ для this = D
Майк Брайан Оливера
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);

Примечание: мне не удалось удалить контент: // 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 в свои намерения! Надеюсь, кто-нибудь более мудрый, чем я, скажет мне, почему это было так.

dmyung
источник
Не могли бы вы увидеть здесь stackoverflow.com/questions/25988574/… ?
Гангадхар Нимбалли
24

Итак, у меня была игра, и это можно удалить получил SMS. К сожалению, не все гладко :(

У меня есть приемник, который принимает входящие SMS-сообщения. Теперь способ работы маршрутизации входящих SMS в Android заключается в том, что фрагмент кода, отвечающий за декодирование сообщений, отправляет широковещательную рассылку (он использует 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, когда его нет (это приведет только к сообщениям об ошибках).

Внутри ОС телефонные звонки MessagingNotification.updateNewMessageIndicator(Context), но я этот класс был скрыт от API, и я не хотел реплицировать весь этот код только для того, чтобы сделать индикатор точным.

Дуг
источник
Дуг, это здорово. В качестве вопроса, знаете ли вы, нужно ли отправлять пост обработчику? Интересно, вставляется ли СМС в базу СМС системы до вызова широковещательных приемников? Мне, вероятно, придется заглянуть в ОС, чтобы увидеть, где происходит вставка, но я предполагаю, что вставка SMS в некоторую базу данных происходит до того, как будут проинформированы широковещательные приемники. У вас есть какое-нибудь представление об этом или вы уже это проверяли?
Hamy
Не могли бы вы увидеть здесь stackoverflow.com/questions/25988574/… ?
Гангадхар Нимбалли
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"/>
Атиф Махмуд
источник
1
Как нам получить sms id?
Dev01
wisdomitsol.com/blog/android/sms/…
Атиф Махмуд,
@ Dev01 если вы хотите удалить конкретное смс, у вас должен быть его идентификатор, верно? а если нет, вы должны запросить идентификатор с помощью адреса или smsbody
доктор андРО
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)} );
Нареш Кавали
источник
Не могли бы вы увидеть здесь stackoverflow.com/questions/25988574/… ?
Гангадхар Нимбалли
5

Вам нужно будет найти URI сообщения. Но как только вы это сделаете, я думаю, вы сможете его android.content.ContentResolver.delete (...).

Вот еще информация .

Нил
источник
2

Я думаю, что пока это невозможно сделать идеально. Есть 2 основные проблемы:

  1. Как можно убедиться, что смс уже находится во входящих, когда вы пытаетесь его удалить?
    Обратите внимание, что SMS_RECEIVED не является заказанной рассылкой.
    Итак, решение dmyung - это попытка удачи; даже задержка с ответом Дуга не является гарантией.

  2. SmsProvider не поточно. (См http://code.google.com/p/android/issues/detail?id=2916#c0 )
    Тот факт , что более чем один клиенты запрашивающей удаления и вставки в него на в то же время вызовет повреждение данных или даже немедленное исключение времени выполнения.

an0
источник
2

Я не мог заставить его работать с помощью решения dmyung, оно дало мне исключение при получении идентификатора сообщения или идентификатора потока.

В конце концов, я использовал следующий метод, чтобы получить идентификатор потока:

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

Тогда я смогу его удалить. Однако, как сказал Дуг, уведомление все еще есть, даже если сообщение отображается при открытии панели уведомлений. Только при нажатии на сообщение я действительно увидел, что оно пустое.

Поэтому я думаю, что единственный способ, которым это сработает, - это как-то перехватить SMS до того, как оно будет доставлено в систему, прежде чем оно даже попадет в почтовый ящик. Однако я очень сомневаюсь, что это выполнимо. Пожалуйста, поправьте меня, если я ошибаюсь.

Стелиан Янку
источник
Ну, это не так о перехвате сообщений , прежде чем почтовый ящик: вы можете получить широковещательный android.provider.Telephony.SMS_RECEIVED, вам нужно всего лишь permssion android.permission.RECEIVE_SMS. Вы даже можете легко предотвратить попадание сообщения в почтовый ящик, вызвав abortBroadcast (), поскольку это заказная рассылка. PS Должно быть смешно, чтобы поправили через 2 года :)
Lapis
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

Просто отключите уведомления для смс-приложения по умолчанию. Обработайте свои собственные уведомления для всех текстовых сообщений!

Ной Сейдман
источник
1

Просто взгляните на эту ссылку, она даст вам краткое представление о логике:

https://gist.github.com/5178e798d9a00cac4ddb
Просто вызовите функцию deleteSMS () с некоторой задержкой, потому что есть небольшая разница между временем уведомления и когда оно на самом деле сохранено ...., подробнее см. также по этой ссылке ..........

http://htmlcoderhelper.com/how-to-delete-sms-from- inbox-in-android-программно /

Спасибо ..........

вив
источник
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);
}
Раджамохан Сугумаран
источник
1

Также обновите файл манифеста, чтобы удалить смс, вам нужны разрешения на запись.

<uses-permission android:name="android.permission.WRITE_SMS"/>
Васиф Кирмани
источник
1

Теперь abortBroadcast();можно использовать метод, чтобы ограничить входящее сообщение во входящие.

Арун Бадоле
источник
0

Пример удаления одного SMS, а не разговора:

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;
}
sharma_kunal
источник
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-сообщение и удалить его, в этом случае я получаю наибольшее количество смс и собираюсь удалить, используя поток и значение идентификатора смс,

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();
}
Пир Фахим Шах
источник