Jak programowo usunąć SMS-a ze skrzynki odbiorczej w systemie Android?


98

W telefonach z systemem Android wiadomości SMS zarejestrowane w aplikacjach są również wysyłane do skrzynki odbiorczej urządzenia. Jednak aby uniknąć bałaganu, dobrze byłoby móc usunąć ze skrzynki odbiorczej wiadomości SMS specyficzne dla aplikacji, aby zmniejszyć potencjalne przepełnienie tych wiadomości.

Pytania w innych grupach dyskusyjnych Google dotyczące uzyskania ostatecznej odpowiedzi na temat programowego sposobu usuwania wiadomości SMS ze skrzynki odbiorczej Androida nie wydają się pilne.

A więc scenariusz:

  • Uruchomienie aplikacji na Androida.
  • zarejestrować typy wiadomości SMS X, Y i Z
  • wiadomości P, Q, X, Y, Z z biegiem czasu są przesyłane do skrzynki odbiorczej
  • Aplikacja na Androida wykrywa odebranie X, Y, Z (prawdopodobnie w ramach zdarzenia przerwania programu)
  • proces X, Y, Z
  • Pożądanie !!! X, Y, Z są usuwane ze skrzynki odbiorczej Androida

Czy to się stało? Czy da się to zrobić?


4
Uważam, że robienie czegokolwiek pożytecznego z możliwościami telefonu w Androidzie jest bardzo nieprzyjemnym doświadczeniem.
BobbyShaftoe

1
dobre pytanie kolego. szukałem czegoś podobnego: D cheers
Harsha MV

3
Najlepiej byłoby, gdyby SMS nie dotarł do skrzynki odbiorczej w pierwszej kolejności: stackoverflow.com/questions/1741628/…
Christopher Orr

Odpowiedzi:


87

„Począwszy od systemu Android 1.6, transmisje przychodzące wiadomości SMS ( android.provider.Telephony.SMS_RECEIVED) są dostarczane jako„ rozsyłanie uporządkowane ”- co oznacza, że ​​można wskazać systemowi, które komponenty powinny odebrać transmisję jako pierwsze.”

Oznacza to, że możesz przechwycić przychodzącą wiadomość i przerwać jej nadawanie.

W AndroidManifest.xmlpliku upewnij się, że masz ustawiony najwyższy priorytet:

<receiver android:name=".receiver.SMSReceiver" android:enabled="true">
    <intent-filter android:priority="1000">
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

W twojej BroadcastReceiver, w onReceive()metodzie przed wykonaniem coś z wiadomości, wystarczy zadzwonićabortBroadcast();

EDYCJA: Od KitKat, to już najwyraźniej nie działa.

EDIT2: Więcej informacji o tym, jak to zrobić na KitKat tutaj:

Usuń SMS-y z Androida w wersji 4.4.4 (wiersze, których dotyczy problem = 0 (zero), po usunięciu)




Najlepsza odpowiedź na to pytanie = D
Mike Brian Olivera

27

Korzystając z sugestii innych, myślę, że udało mi się:

(przy użyciu SDK v1 R2)

Nie jest doskonały, ponieważ muszę usunąć całą rozmowę, ale dla naszych celów jest to wystarczający kompromis, ponieważ przynajmniej będziemy wiedzieć, że wszystkie wiadomości zostaną przejrzane i zweryfikowane. Nasz przepływ prawdopodobnie będzie musiał następnie nasłuchiwać wiadomości, przechwytywać wiadomość, którą chcemy, wykonać zapytanie, aby uzyskać identyfikator wątku ostatnio odebranej wiadomości i wykonać wywołanie delete ().

W naszej działalności:

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

Uwaga: nie udało mi się usunąć treści: // sms / inbox / lub content: // sms / all /

Wygląda na to, że wątek ma pierwszeństwo, co ma sens, ale komunikat o błędzie tylko ośmielił mnie, żebym był bardziej zły. Próbując usunąć na sms / inbox / lub sms / all /, prawdopodobnie otrzymasz:

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)

Aby uzyskać dodatkowe informacje, umieść to w swoim manifeście dla swojego odbiorcy:

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

Zauważ, że tag odbiornika nie wygląda tak:

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

Kiedy miałem te ustawienia, Android dał mi szalone wyjątki uprawnień, które nie pozwalały android.phone na przekazywanie odebranych SMS-ów zgodnie z moim zamiarem. Więc NIE umieszczaj tego atrybutu uprawnienia RECEIVE_SMS w swojej intencji! Mam nadzieję, że ktoś mądrzejszy ode mnie może mi powiedzieć, dlaczego tak się stało.



24

Tak, miałem grać, i to jest możliwe, aby usunąć odebrany SMS. Niestety nie wszystko jest proste :(

Mam odbiornik, który odbiera przychodzące wiadomości SMS. Sposób, w jaki działa routing przychodzący SMS na Androida polega na tym, że fragment kodu odpowiedzialny za dekodowanie wiadomości wysyła Broadcast (używa sendBroadcast()metody - która niestety NIE jest wersją, która pozwala po prostu zadzwonić abortBroadcast()) za każdym razem, gdy nadejdzie wiadomość.

Mój odbiorca może, ale nie musi, zostać wywołany przed systemowym odbiornikiem SMS, aw każdym przypadku odebrana transmisja nie ma właściwości, która mogłaby odzwierciedlać _idkolumnę w tabeli SMS.

Jednak nie będąc osobą, której można tak łatwo zatrzymać, wysyłam sobie (za pośrednictwem Handlera) opóźnioną wiadomość z SmsMessage jako dołączonym obiektem. (Przypuszczam, że możesz też opublikować Runnable ...)

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

Opóźnienie ma na celu zapewnienie, że do czasu nadejścia wiadomości wszyscy odbiorcy rozgłoszeń zakończą pracę i wiadomość zostanie bezpiecznie umieszczona w tabeli SMS.

Kiedy otrzymam wiadomość (lub Runnable), oto co robię:

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

Używam adresu źródłowego i pola znacznika czasu, aby zapewnić bardzo wysokie prawdopodobieństwo usunięcia TYLKO interesującej mnie wiadomości. Gdybym chciał być jeszcze bardziej paranoikiem, mógłbym dołączyć msg.getMessageBody()treść jako część zapytania.

Tak, wiadomość JEST usunięta (hura!). Niestety pasek powiadomień nie jest aktualizowany :(

Po otwarciu obszaru powiadomień zobaczysz wiadomość tam dla Ciebie ... ale kiedy ją dotkniesz, aby ją otworzyć - zniknęła!

Dla mnie to nie jest wystarczająco dobre - chcę, aby wszystkie ślady wiadomości zniknęły - nie chcę, aby użytkownik myślał, że istnieje TXT, gdy go nie ma (spowodowałoby to tylko raporty o błędach).

Wewnętrznie w systemie operacyjnym połączenia telefoniczne MessagingNotification.updateNewMessageIndicator(Context), ale ja ta klasa została ukryta przed API i nie chciałem replikować całego tego kodu tylko po to, aby wskaźnik był dokładny.


Doug, to jest świetne. A propos, czy wiesz, czy konieczne jest wysłanie wiadomości do Handler? Zastanawiam się, czy SMS jest wstawiony do systemowej bazy danych SMS-ów przed wywołaniem i z odbiorników transmisji? Prawdopodobnie będę musiał zajrzeć do systemu operacyjnego, aby zobaczyć, gdzie następuje wstawienie, ale przypuszczam, że wstawienie SMS-a do jakiejś bazy danych ma miejsce przed poinformowaniem odbiorców transmisji. Masz wgląd w to, czy już to sprawdziłeś?
Hamy


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

użyj tego uprawnienia w AndroidManifiest

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

1
Jak otrzymujemy identyfikator sms?
Dev01


@ Dev01Jeśli chcesz usunąć konkretny sms, musisz mieć jego identyfikator, prawda? a jeśli nie, musisz sprawdzić identyfikator za pomocą adresu lub smsbody
Dr. aNdRO

6

Lepiej jest użyć _id i thread_id do usunięcia wiadomości.

Thread_id to coś przypisanego do wiadomości pochodzących od tego samego użytkownika. Jeśli więc użyjesz tylko thread_id, wszystkie wiadomości od nadawcy zostaną usunięte.

Jeśli użyjesz kombinacji _id, thread_id, usunie to dokładnie tę wiadomość, którą chcesz usunąć.

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

Musisz znaleźć identyfikator URI wiadomości. Ale kiedy już to zrobisz, myślę, że powinieneś być w stanie android.content.ContentResolver.delete (...) to.

Oto więcej informacji .


2

Myślę, że na razie nie można tego doskonale zrobić. Istnieją 2 podstawowe problemy:

  1. Jak możesz upewnić się, że SMS jest już w skrzynce odbiorczej, gdy próbujesz go usunąć?
    Zwróć uwagę, że SMS_RECEIVED nie jest zamówioną transmisją.
    Tak więc rozwiązaniem Dmyunga jest próba szczęścia; nawet opóźnienie w odpowiedzi Douga nie jest gwarancją.

  2. SmsProvider nie jest bezpieczny dla wątków. (Patrz http://code.google.com/p/android/issues/detail?id=2916#c0 )
    Fakt, że więcej niż jeden klient żąda usunięcia i wstawienia do niego w w tym samym czasie spowoduje uszkodzenie danych lub nawet natychmiastowy wyjątek w czasie wykonywania.


2

Nie mogłem zmusić go do pracy przy użyciu rozwiązania dmyung, dał mi wyjątek podczas uzyskiwania identyfikatora wiadomości lub identyfikatora wątku.

W końcu użyłem następującej metody, aby uzyskać identyfikator wątku:

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

Wtedy mogłem go usunąć. Jednak, jak powiedział Doug, powiadomienie nadal tam jest, nawet komunikat jest wyświetlany podczas otwierania panelu powiadomień. Dopiero stukając w wiadomość mogłem faktycznie zobaczyć, że jest pusty.

Więc wydaje mi się, że jedynym sposobem, aby to zadziałało, byłoby przechwycenie wiadomości SMS, zanim zostanie ona dostarczona do systemu, zanim dotrze nawet do skrzynki odbiorczej. Jednak bardzo wątpię, że jest to wykonalne. Proszę popraw mnie jeżeli się mylę.


Cóż, źle o przechwytywaniu wiadomości przed skrzynki: może pojawić się nadawanie android.provider.Telephony.SMS_RECEIVED, wystarczy tylko android.permission.RECEIVE_SMS permssion. Możesz nawet łatwo zatrzymać dotarcie wiadomości do skrzynki odbiorczej, wywołując abortBroadcast (), ponieważ jest to uporządkowana transmisja. PS Musi być zabawnie do poprawienia 2 lata później :)
lapis

2

Użyj tej funkcji, aby usunąć określony wątek wiadomości lub zmodyfikować go zgodnie ze swoimi potrzebami:

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

  }
}

Wywołaj tę funkcję poniżej:

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

Nie zapomnij dodać poniżej uprawnień do głównego festiwalu Androida:

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

1

Po prostu wyłącz powiadomienia dla domyślnej aplikacji sms. Przetwarzaj własne powiadomienia dla wszystkich wiadomości tekstowych!



1

Po prostu wypróbuj poniższy kod, aby usunąć wszystkie SMS-y, które są w telefonie (odebrane lub wysłane)

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

Zaktualizuj również plik manifestu, aby usunąć sms, którego potrzebujesz do zapisu.

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

1

abortBroadcast();Metoda Now może służyć do ograniczenia przychodzącej wiadomości do skrzynki odbiorczej.


0

Przykład usunięcia jednego SMS-a, a nie rozmowy:

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

Spróbuj tego jestem w 100% pewien, że to zadziała dobrze: - // po prostu wpisz tutaj adres konwersji, aby usunąć całą konwersję według adresu (nie zapomnij dodać uprawnień do odczytu i zapisu w mainfest) Oto kod:

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

Użyj jednej z tych metod, aby wybrać ostatnio otrzymany SMS i usunąć go, tutaj w tym przypadku otrzymuję najwięcej smsów i zamierzam usunąć za pomocą wątku i wartości identyfikatora 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();
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.