Como excluir um SMS da caixa de entrada no Android de forma programática?


98

Em telefones Android, as mensagens SMS registradas nos aplicativos também são enviadas para a caixa de entrada do dispositivo. No entanto, para evitar confusão, seria bom ser capaz de remover mensagens SMS específicas do aplicativo da caixa de entrada para reduzir o potencial estouro dessas mensagens.

As perguntas de outros grupos do Google sobre como obter uma resposta definitiva sobre uma forma programática de excluir mensagens SMS da caixa de entrada do Android não parecem ser urgentes.

Portanto, o cenário:

  • Inicialização do aplicativo Android.
  • registrar mensagens SMS tipos X, Y e Z
  • mensagens P, Q, X, Y, Z são transmitidas ao longo do tempo, todas depositadas na caixa de entrada
  • O aplicativo Android detecta o recebimento de X, Y, Z (provavelmente como parte do evento de interrupção do programa)
  • processo X, Y, Z
  • Desejo !!! X, Y, Z são excluídos da caixa de entrada do Android

Isso foi feito? Isso pode ser feito?


4
Descobri que fazer qualquer coisa útil com os recursos de telefone do Android é uma experiência muito desagradável.
BobbyShaftoe

1
boa pergunta, companheiro. eu estava procurando por algo semelhante: D cheers
Harsha MV

3
O melhor seria evitar que o SMS chegue à caixa de entrada: stackoverflow.com/questions/1741628/…
Christopher Orr

Respostas:


87

"A partir do Android 1.6, as transmissões de mensagens SMS recebidas ( android.provider.Telephony.SMS_RECEIVED) são entregues como uma" transmissão ordenada "- o que significa que você pode dizer ao sistema quais componentes devem receber a transmissão primeiro."

Isso significa que você pode interceptar a mensagem recebida e abortar a transmissão dela mais adiante.

Em seu AndroidManifest.xmlarquivo, certifique-se de definir a prioridade para a mais alta:

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

Na sua BroadcastReceiver, no onReceive()método, antes de realizar qualquer coisa com a sua mensagem, basta ligarabortBroadcast();

EDIT: A partir de KitKat, isso não funciona mais aparentemente.

EDIT2: Mais informações sobre como fazer no KitKat aqui:

Excluir SMS do Android em 4.4.4 (linhas afetadas = 0 (zero), após excluído)




A melhor resposta para esta = D
Mike Brian Olivera

27

Usando sugestões de outras pessoas, acho que comecei a trabalhar:

(usando SDK v1 R2)

Não é perfeito, uma vez que preciso excluir toda a conversa, mas para nossos propósitos, é um compromisso suficiente, pois pelo menos saberemos que todas as mensagens serão analisadas e verificadas. Nosso fluxo provavelmente precisará ouvir a mensagem, capturar a mensagem que queremos, fazer uma consulta para obter o thread_id da mensagem recebida recentemente e fazer a chamada delete ().

Em nossa atividade:

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

Observação: não consegui excluir content: // sms / inbox / ou content: // sms / all /

Parece que o tópico tem precedência, o que faz sentido, mas a mensagem de erro apenas me encorajou a ficar mais irritado. Ao tentar excluir em sms / inbox / ou sms / all /, você provavelmente obterá:

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)

Também para referência adicional, certifique-se de colocar isso no manifesto do receptor de intent:

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

Observe que a etiqueta do receptor não se parece com isto:

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

Quando eu tinha essas configurações, o android me deu algumas exceções de permissões malucas que não permitiam que o android.phone entregasse o SMS recebido conforme minha intenção. Portanto, NÃO coloque esse atributo de permissão RECEIVE_SMS em sua intenção! Espero que alguém mais sábio do que eu possa me dizer por que isso aconteceu.



24

Então, eu joguei e é possível deletar um SMS recebido. Infelizmente, nem tudo é fácil :(

Tenho um receptor que capta as mensagens SMS recebidas. Agora a forma como funciona o roteamento de entrada de SMS do Android é que o pedaço de código responsável por decodificar as mensagens envia um Broadcast (ele usa o sendBroadcast()método - que infelizmente NÃO é a versão que permite simplesmente ligar abortBroadcast()) sempre que uma mensagem chega.

Meu receptor pode ou não ser chamado antes do receptor SMS de Sistemas e, em qualquer caso, a transmissão recebida não tem nenhuma propriedade que possa refletir a _idcoluna na tabela SMS.

No entanto, não sendo alguém que pode ser interrompido tão facilmente, eu mesmo postarei (através de um Handler) uma mensagem atrasada com o SmsMessage como o objeto anexado. (Suponho que você também poderia postar um Runnable ...)

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

O atraso existe para garantir que, no momento em que a mensagem chegar, todos os receptores de Broadcast terão terminado suas tarefas e a mensagem estará armazenada com segurança na tabela de SMS.

Quando a mensagem (ou Runnable) é recebida, aqui está o que eu faço:

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

Eu uso o endereço de origem e o campo de carimbo de data / hora para garantir uma probabilidade muito alta de excluir SOMENTE a mensagem na qual estou interessado. Se eu quisesse ser ainda mais paranóico, poderia incluir o msg.getMessageBody()conteúdo como parte da consulta.

Sim, a mensagem foi excluída (hooray!). Infelizmente, a barra de notificação não é atualizada :(

Quando você abre a área de notificação, você verá a mensagem lá para você ... mas quando você toca nela para abri-la - ela se foi!

Para mim, isso não é bom o suficiente - quero que todos os rastros da mensagem desapareçam - não quero que o usuário pense que há um TXT quando não há (isso só causaria relatórios de bug).

Internamente no sistema operacional, os telefonemas chamam MessagingNotification.updateNewMessageIndicator(Context), mas essa classe foi ocultada da API e não queria replicar todo aquele código apenas para tornar o indicador preciso.


Doug, isso é ótimo. A propósito, você sabe se é necessário fazer o post para o Handler? Gostaria de saber se o SMS é inserido no banco de dados de SMS do sistema antes e dos receptores de broadcast serem chamados? Provavelmente terei que examinar o sistema operacional para ver onde ocorre a inserção, mas presumo que a inserção do SMS em algum banco de dados aconteça antes que os receptores de transmissão sejam informados. Tem alguma ideia sobre isso ou já verificou?
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;
}

use esta permissão em AndroidManifiest

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

1
Como obtemos id de sms?
Dev01


@ Dev01se você deseja deletar um determinado sms você deve ter seu id correto? e se não você tem que consultar o id com o endereço ou smsbody
Dr. aNdRO

6

É melhor usar _id e thread_id para excluir uma mensagem.

Thread_id é algo atribuído às mensagens vindas do mesmo usuário. Portanto, se você usar apenas thread_id, todas as mensagens do remetente serão excluídas.

Se vc usar a combinação de _id, thread_id, então irá deletar a mensagem exata que você está querendo deletar.

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

Você precisará encontrar o URI da mensagem. Mas, depois de fazer isso, acho que você deve conseguir android.content.ContentResolver.delete (...).

Aqui estão mais algumas informações .


2

Acho que isso não pode ser feito com perfeição por enquanto. Existem 2 problemas básicos:

  1. Como você pode ter certeza de que o sms já está na caixa de entrada ao tentar excluí-lo?
    Observe que SMS_RECEIVED não é uma transmissão ordenada.
    Portanto, a solução de dmyung é tentar a sorte completamente; mesmo a demora na resposta de Doug não é uma garantia.

  2. O SmsProvider não é thread-safe. (Consulte http://code.google.com/p/android/issues/detail?id=2916#c0 )
    O fato de que mais de um cliente está solicitando exclusão e inserção nele no ao mesmo tempo, causará corrupção de dados ou mesmo Exceção de tempo de execução imediata.


2

Não consegui fazer funcionar usando a solução de dmyung, ele me deu uma exceção ao obter o id da mensagem ou o id do thread.

No final, usei o seguinte método para obter o id do thread:

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

Então eu poderia excluí-lo. No entanto, como disse Doug, a notificação ainda está lá, mesmo a mensagem é exibida ao abrir o painel de notificação. Somente ao tocar na mensagem, pude realmente ver que ela está vazia.

Portanto, acho que a única maneira de isso funcionar seria de alguma forma interceptar o SMS antes de ele ser entregue ao sistema, antes mesmo de chegar à caixa de entrada. No entanto, duvido muito que isso seja viável. Por favor me corrija se eu estiver errado.


Bem, você está errado ao interceptar mensagens antes da caixa de entrada: você pode receber uma transmissão android.provider.Telephony.SMS_RECEIVED, você só precisa de uma permissão android.permission.RECEIVE_SMS. Você pode até facilmente impedir que a mensagem chegue à caixa de entrada chamando abortBroadcast (), pois é uma transmissão ordenada. PS Deve ser engraçado para ser corrigido 2 anos depois :)
lapis

2

Use esta função para excluir um tópico de mensagem específico ou modificar de acordo com suas necessidades:

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

  }
}

Chame esta função simplesmente abaixo:

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

Não se esqueça de adicionar a permissão do Android mainfest abaixo:

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

1

Basta desligar as notificações do aplicativo sms padrão. Processe suas próprias notificações para todas as mensagens de texto!



1

Você apenas tenta o seguinte código. Ele excluirá todos os sms que estão todos no telefone (recebidos ou enviados)

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

Além disso, atualize o arquivo de manifesto, pois para excluir um sms, você precisa de permissões de gravação.

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

1

Agora o abortBroadcast();método pode ser usado para restringir a mensagem recebida para ir para a caixa de entrada.


0

Amostra para excluir um SMS, não conversa:

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

Experimente, estou 100% certo de que funcionará bem: - // coloque o endereço de conversão aqui para excluir a conversão inteira por endereço (não se esqueça de adicionar permissão de leitura e gravação no mainfest) Aqui está o código:

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

Use um desses métodos para selecionar o último SMS recebido e excluí-lo, neste caso estou recebendo o principal sms e irei excluir usando o thread e o valor de id do 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();
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.