Eu descobri como enviar e receber mensagens SMS. Para enviar mensagens SMS, tive que chamar os métodos sendTextMessage()
e sendMultipartTextMessage()
da SmsManager
classe. Para receber mensagens SMS, tive que registrar um receptor no AndroidMainfest.xml
arquivo. Então eu tive que substituir o onReceive()
método do BroadcastReceiver
. Eu incluí exemplos abaixo.
MainActivity.java
public class MainActivity extends Activity {
private static String SENT = "SMS_SENT";
private static String DELIVERED = "SMS_DELIVERED";
private static int MAX_SMS_MESSAGE_LENGTH = 160;
// ---sends an SMS message to another device---
public static void sendSMS(String phoneNumber, String message) {
PendingIntent piSent = PendingIntent.getBroadcast(mContext, 0, new Intent(SENT), 0);
PendingIntent piDelivered = PendingIntent.getBroadcast(mContext, 0,new Intent(DELIVERED), 0);
SmsManager smsManager = SmsManager.getDefault();
int length = message.length();
if(length > MAX_SMS_MESSAGE_LENGTH) {
ArrayList<String> messagelist = smsManager.divideMessage(message);
smsManager.sendMultipartTextMessage(phoneNumber, null, messagelist, null, null);
}
else
smsManager.sendTextMessage(phoneNumber, null, message, piSent, piDelivered);
}
}
//More methods of MainActivity ...
}
SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private static final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private Context mContext;
private Intent mIntent;
// Retrieve SMS
public void onReceive(Context context, Intent intent) {
mContext = context;
mIntent = intent;
String action = intent.getAction();
if(action.equals(ACTION_SMS_RECEIVED)){
String address, str = "";
int contactId = -1;
SmsMessage[] msgs = getMessagesFromIntent(mIntent);
if (msgs != null) {
for (int i = 0; i < msgs.length; i++) {
address = msgs[i].getOriginatingAddress();
contactId = ContactsUtils.getContactId(mContext, address, "address");
str += msgs[i].getMessageBody().toString();
str += "\n";
}
}
if(contactId != -1){
showNotification(contactId, str);
}
// ---send a broadcast intent to update the SMS received in the
// activity---
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("SMS_RECEIVED_ACTION");
broadcastIntent.putExtra("sms", str);
context.sendBroadcast(broadcastIntent);
}
}
public static SmsMessage[] getMessagesFromIntent(Intent intent) {
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
byte[][] pduObjs = new byte[messages.length][];
for (int i = 0; i < messages.length; i++) {
pduObjs[i] = (byte[]) messages[i];
}
byte[][] pdus = new byte[pduObjs.length][];
int pduCount = pdus.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
for (int i = 0; i < pduCount; i++) {
pdus[i] = pduObjs[i];
msgs[i] = SmsMessage.createFromPdu(pdus[i]);
}
return msgs;
}
/**
* The notification is the icon and associated expanded entry in the status
* bar.
*/
protected void showNotification(int contactId, String message) {
//Display notification...
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myexample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.WRITE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:debuggable="true"
android:icon="@drawable/ic_launcher_icon"
android:label="@string/app_name" >
<activity
//Main activity...
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
//Activity 2 ...
</activity>
//More acitivies ...
// SMS Receiver
<receiver android:name="com.myexample.receivers.SMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
No entanto, eu queria saber se você poderia enviar e receber mensagens MMS de maneira semelhante. Depois de fazer algumas pesquisas, muitos exemplos fornecidos em blogs simplesmente passam um Intent
para o aplicativo de mensagens nativo. Estou tentando enviar um MMS sem sair do meu aplicativo. Não parece haver uma maneira padrão de enviar e receber MMS. Alguém conseguiu fazer isso funcionar?
Além disso, estou ciente de que o SMS / MMS ContentProvider não faz parte do SDK oficial do Android, mas estava pensando que alguém poderia implementá-lo. Qualquer ajuda é muito apreciada.
Atualizar
Adicionei um BroadcastReceiver
ao AndroidManifest.xml
arquivo para receber mensagens MMS
<receiver android:name="com.sendit.receivers.MMSReceiver" >
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
Na classe MMSReceiver, o onReceive()
método só pode capturar o phoneNumber do qual a mensagem foi enviada. Como você pega outras coisas importantes de um MMS, como o caminho do arquivo para o anexo de mídia (imagem / áudio / vídeo) ou o texto no MMS?
MMSReceiver.java
public class MMSReceiver extends BroadcastReceiver {
private final String DEBUG_TAG = getClass().getSimpleName().toString();
private static final String ACTION_MMS_RECEIVED = "android.provider.Telephony.WAP_PUSH_RECEIVED";
private static final String MMS_DATA_TYPE = "application/vnd.wap.mms-message";
// Retrieve MMS
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String type = intent.getType();
if(action.equals(ACTION_MMS_RECEIVED) && type.equals(MMS_DATA_TYPE)){
Bundle bundle = intent.getExtras();
Log.d(DEBUG_TAG, "bundle " + bundle);
SmsMessage[] msgs = null;
String str = "";
int contactId = -1;
String address;
if (bundle != null) {
byte[] buffer = bundle.getByteArray("data");
Log.d(DEBUG_TAG, "buffer " + buffer);
String incomingNumber = new String(buffer);
int indx = incomingNumber.indexOf("/TYPE");
if(indx>0 && (indx-15)>0){
int newIndx = indx - 15;
incomingNumber = incomingNumber.substring(newIndx, indx);
indx = incomingNumber.indexOf("+");
if(indx>0){
incomingNumber = incomingNumber.substring(indx);
Log.d(DEBUG_TAG, "Mobile Number: " + incomingNumber);
}
}
int transactionId = bundle.getInt("transactionId");
Log.d(DEBUG_TAG, "transactionId " + transactionId);
int pduType = bundle.getInt("pduType");
Log.d(DEBUG_TAG, "pduType " + pduType);
byte[] buffer2 = bundle.getByteArray("header");
String header = new String(buffer2);
Log.d(DEBUG_TAG, "header " + header);
if(contactId != -1){
showNotification(contactId, str);
}
// ---send a broadcast intent to update the MMS received in the
// activity---
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("MMS_RECEIVED_ACTION");
broadcastIntent.putExtra("mms", str);
context.sendBroadcast(broadcastIntent);
}
}
}
/**
* The notification is the icon and associated expanded entry in the status
* bar.
*/
protected void showNotification(int contactId, String message) {
//Display notification...
}
}
De acordo com a documentação do android.provider.Telephony :
Ação de transmissão: Uma nova mensagem SMS baseada em texto foi recebida pelo dispositivo. A intenção terá os seguintes valores extras:
pdus
- UmObject[]
debyte[]
s contendo as PDUs que compõem a mensagem.Os valores extras podem ser extraídos usando
getMessagesFromIntent(android.content.Intent)
Se um BroadcastReceiver encontrar um erro ao processar essa intenção, ele deverá definir o código de resultado adequadamente.@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
Ação de transmissão: Uma nova mensagem SMS baseada em dados foi recebida pelo dispositivo. A intenção terá os seguintes valores extras:
pdus
- UmObject[]
debyte[]
s contendo as PDUs que compõem a mensagem.Os valores extras podem ser extraídos usando getMessagesFromIntent (android.content.Intent). Se um BroadcastReceiver encontrar um erro durante o processamento dessa intenção, ele deverá definir o código do resultado adequadamente.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
Ação de transmissão: Uma nova mensagem WAP PUSH foi recebida pelo dispositivo. A intenção terá os seguintes valores extras:
transactionId (Integer)
- O ID da transação WAP
pduType (Integer)
- O tipo de WAP PDU`
header (byte[])
- O cabeçalho da mensagem
data (byte[])
- A carga útil de dados da mensagem
contentTypeParameters (HashMap<String,String>)
- Quaisquer parâmetros associados ao tipo de conteúdo (decodificados no cabeçalho WSP Content-Type)Se um BroadcastReceiver encontrar um erro durante o processamento dessa intenção, ele deverá definir o código do resultado adequadamente. O valor extra contentTypeParameters é um mapa dos parâmetros de conteúdo codificados por seus nomes. Se algum parâmetro conhecido não atribuído for encontrado, a chave do mapa será 'não atribuído / 0x ...', onde '...' é o valor hexadecimal do parâmetro não atribuído. Se um parâmetro tiver No-Value, o valor no mapa será nulo.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
Atualização # 2
Eu descobri como passar extras em a PendingIntent
para serem recebidos por um BroadcastReceiver
:
Android PendingIntent extras, não recebidos por BroadcastReceiver
No entanto, o extra é passado para o SendBroadcastReceiver e não para o SMSReceiver . Como posso passar um extra para o SMSReceiver ?
Atualização # 3
Recebendo MMS
Então, depois de fazer mais pesquisas, vi algumas sugestões de registro de um ContentObserver
. Dessa forma, você pode detectar quando há alguma alteração no content://mms-sms/conversations
Provedor de Conteúdo, consequentemente permitindo detectar MMS de entrada. Aqui está o exemplo mais próximo para que isso funcione, que eu encontrei: Recebendo MMS
No entanto, não é uma variável mainActivity
do tipo ServiceController
. Onde a ServiceController
classe é implementada? Existem outras implementações de um registrado ContentObserver
?
Enviando MMS
Quanto ao envio de MMS, me deparei com este exemplo: Enviar MMS
O problema é que tentei executar esse código no meu Nexus 4, que está no Android v4.2.2, e estou recebendo este erro:
java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has android.permission.WRITE_APN_SETTINGS.
O erro é gerado após consultar o Carriers
ContentProvider no getMMSApns()
método da APNHelper
classe.
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
Aparentemente, você não pode ler APNs no Android 4.2
Qual é a alternativa para todos os aplicativos que usam dados móveis para realizar operações (como enviar MMS) e não conhecem a configuração padrão de APN presente no dispositivo?
Atualização # 4
Enviando MMS
Eu tentei seguir este exemplo: Enviar MMS
Como @Sam sugeriu em sua resposta:
You have to add jsoup to the build path, the jar to the build path and import com.droidprism.*; To do that in android, add the jars to the libs directory first, then configure the project build path to use the jars already in the libs directory, then on the build path config click order and export and check the boxes of the jars and move jsoup and droidprism jar to the top of the build order.
Então agora eu não recebo mais os erros SecurityException. Agora estou testando um Nexus 5 no Android KitKat. Depois de executar o código de amostra, ele me fornece um código de 200 respostas após a chamada para
MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);
No entanto, verifiquei com a pessoa para quem tentei enviar o MMS. E eles disseram que nunca receberam o MMS.