web-dev-qa-db-fra.com

Envoi et réception de SMS et de MMS dans Android (Kit Kat antérieur Android 4.4)

J'ai compris comment envoyer et recevoir SMS messages. Pour envoyer des messages SMS, j'ai dû appeler les méthodes sendTextMessage() et sendMultipartTextMessage() de la classe SmsManager. Pour recevoir les messages SMS, je devais enregistrer un destinataire dans le fichier AndroidMainfest.xml. Ensuite, j'ai dû remplacer la méthode onReceive() de la BroadcastReceiver. J'ai inclus des exemples ci-dessous.

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>

Cependant, je me demandais si vous pouviez envoyer et recevoir MMS messages de la même manière. Après quelques recherches, de nombreux exemples fournis sur des blogs transmettent simplement un Intent à l'application de messagerie native. J'essaie d'envoyer un MMS sans quitter ma demande. Il ne semble pas y avoir de moyen standard d’envoyer et de recevoir des MMS. Quelqu'un at-il obtenu cela au travail?

De plus, je suis conscient du fait que SMS/MMS ContentProvider ne fait pas partie du SDK officiel Android, mais je pensais que quelqu'un aurait pu l'implémenter. Toute aide est grandement appréciée.

Mise à jour

J'ai ajouté un BroadcastReceiver au fichier AndroidManifest.xml pour recevoir les messages 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>

Dans la classe MMSReceiver, la méthode onReceive() ne peut saisir que le numéro de téléphone à partir duquel le message a été envoyé. Comment récupérez-vous d'autres éléments importants d'un MMS, tels que le chemin du fichier vers la pièce jointe au média (image/audio/vidéo) ou le texte du 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...
    }
}

Selon le Documentation de Android.provider.Telephony :

Action en diffusion: un nouveau message textuel SMS a été reçu par le périphérique. L'intention aura les valeurs supplémentaires suivantes:

pdus - Un Object[] de byte[]s contenant les PDU constituant le message.

Les valeurs supplémentaires peuvent être extraites à l'aide de getMessagesFromIntent(Android.content.Intent) Si un BroadcastReceiver rencontre une erreur lors du traitement de cette intention, il doit définir le code de résultat de manière appropriée.

 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
 public static final String SMS_RECEIVED_ACTION = "Android.provider.Telephony.SMS_RECEIVED";

Action en diffusion: un nouveau message SMS basé sur les données a été reçu par le périphérique. L'intention aura les valeurs supplémentaires suivantes:

pdus - Un Object[] de byte[]s contenant les PDU constituant le message.

Les valeurs supplémentaires peuvent être extraites à l'aide de getMessagesFromIntent (Android.content.Intent). Si un BroadcastReceiver rencontre une erreur lors du traitement de cette intention, il doit définir le code de résultat de manière appropriée.

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String DATA_SMS_RECEIVED_ACTION = "Android.intent.action.DATA_SMS_RECEIVED";

Action en diffusion: un nouveau message WAP Push a été reçu par le périphérique. L'intention aura les valeurs supplémentaires suivantes:

transactionId (Integer) - L'ID de transaction WAP

pduType (Integer) - Le type de PDU WAP`

header (byte[]) - En-tête du message

data (byte[]) - Charge utile de données du message

contentTypeParameters (HashMap<String,String>) - Tous les paramètres associés au type de contenu (décodés à partir de l'en-tête WSP Content-Type)

Si un BroadcastReceiver rencontre une erreur lors du traitement de cette intention, il doit définir le code de résultat de manière appropriée. La valeur supplémentaire contentTypeParameters est la mappe des paramètres de contenu indexés par leur nom. Si des paramètres connus non attribués sont rencontrés, la clé de la carte sera "non affectée/0x ...", où "..." est la valeur hexadécimale du paramètre non attribué. Si un paramètre a No-Value, la valeur dans la carte sera null.

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WAP_Push_RECEIVED_ACTION = "Android.provider.Telephony.WAP_Push_RECEIVED";

Mise à jour # 2

J'ai compris comment passer des extras dans un PendingIntent pour qu'ils soient reçus par un BroadcastReceiver: extras Android PendingIntent, non reçus par BroadcastReceiver

Toutefois, l’extra est transmis au SendBroadcastReceiver et non au SMSReceiver . Comment puis-je passer un extra au SMSReceiver ?

Mise à jour # 3

Réception de MMS

Ainsi, après plus de recherches, j’ai vu quelques suggestions d’enregistrement d’une ContentObserver. De cette façon, vous pouvez détecter toute modification apportée au fournisseur de contenu content://mms-sms/conversations, vous permettant ainsi de détecter les MMS entrants. Voici l'exemple le plus proche pour que cela fonctionne que j'ai trouvé: Réception de MMS

Cependant, il existe une variable mainActivity de type ServiceController. Où la classe ServiceController est-elle implémentée? Existe-t-il d'autres implémentations d'un ContentObserver enregistré?

Envoi de MMS

En ce qui concerne l'envoi de MMS, je suis tombé sur cet exemple: Send MMS

Le problème est que j'ai essayé d'exécuter ce code sur mon Nexus 4, qui se trouve sur Android v4.2.2, et je reçois cette erreur:

Java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has Android.permission.WRITE_APN_SETTINGS.

L'erreur est renvoyée après avoir interrogé le Carriers ContentProvider dans la méthode getMMSApns() de la classe APNHelper.

final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);

Apparemment, vous ne pouvez pas lire les APN dans Android 4.2

Quelle est l'alternative pour toutes les applications qui utilisent des données mobiles pour effectuer des opérations (telles que l'envoi de MMS) et ne connaissent pas le paramètre APN par défaut présent dans l'appareil?

Mise à jour # 4

Envoi de MMS

J'ai essayé de suivre cet exemple: Send MMS

Comme @Sam l'a suggéré dans sa réponse:

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.

Alors maintenant, je ne reçois plus les erreurs SecurityException. Je teste maintenant un Nexus 5 sur Android KitKat. Après avoir exécuté le code exemple, il me donne un code de 200 réponses après l'appel de

MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);

Cependant, j’ai vérifié auprès de la personne à qui j’avais essayé d’envoyer le MMS à. Et ils ont dit qu'ils n'avaient jamais reçu le MMS.

131
toobsco42

J'ai eu exactement le même problème que vous décrivez ci-dessus (Galaxy Nexus sur t-mobile USA), c'est parce que les données mobiles sont désactivées.

Dans Jelly Bean, il s’agit de: Paramètres> Utilisation des données> Données mobiles

Notez que les données mobiles doivent être activées AVANT d’en envoyer un MMS OR. Si je reçois un MMS avec les données mobiles désactivées, je recevrai la notification d'un nouveau message et je le recevrai avec un bouton de téléchargement. Mais si je n'ai pas de données mobiles auparavant, la pièce jointe MMS entrante ne sera pas reçue. Même si je l'allume après la réception du message.

Pour une raison quelconque, lorsque votre opérateur téléphonique vous permet d'envoyer et de recevoir MMS, vous devez activer les données mobiles, même si vous utilisez le Wi-Fi. Si Mobile Data est activé, vous pourrez recevoir et envoyez des MMS, même si le Wi-Fi apparaît comme votre connexion Internet sur votre appareil.

C'est très pénible, car si vous ne l'avez pas activé, le message risque de se bloquer, même lorsque vous activez Mobile Data, et peut nécessiter un redémarrage de l'appareil.

15
Manan Sharma

Il n'y a pas de support officiel de l'API, ce qui signifie qu'il n'est pas documenté pour le public et que les bibliothèques peuvent changer à tout moment. Je me rends compte que vous ne voulez pas quitter l'application, mais voici comment vous le faites avec l'intention de quiconque de vous le demander.

public void sendData(int num){
    String fileString = "..."; //put the location of the file here
    Intent mmsIntent = new Intent(Intent.ACTION_SEND);
    mmsIntent.putExtra("sms_body", "text");
    mmsIntent.putExtra("address", num);
    mmsIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(fileString)));
    mmsIntent.setType("image/jpeg");
    startActivity(Intent.createChooser(mmsIntent, "Send"));

}

Je n'ai pas complètement compris comment faire des choses telles que le suivi de la livraison du message, mais cela devrait être envoyé.

Vous pouvez être averti de la réception de MMS de la même manière que SMS. Le filtre d'intention sur le récepteur devrait ressembler à ceci.

<intent-filter>
    <action Android:name="Android.provider.Telephony.WAP_Push_RECEIVED" />
    <data Android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
7
user1959417

Pour envoyer un mms pour Android 4.0 Api 14 ou supérieur sans autorisation d'écrire des paramètres d'apn, vous pouvez utiliser cette bibliothèque : récupérer les codes mnc et mcc depuis Android, puis appeler

Carrier c = Carrier.getCarrier(mcc, mnc);
if (c != null) {
    APN a = c.getAPN();
    if (a != null) {
        String mmsc = a.mmsc;
        String mmsproxy = a.proxy; //"" if none
        int mmsport = a.port; //0 if none
    }
}

Pour utiliser cela, ajoutez Jsoup et le fichier java du prisme droïde au chemin de génération, puis importez le fichier com.droidprism. *;

4
Sam Adamsh

Je ne pense pas qu'il existe un support SDK pour l'envoi de MMS dans Android. Regardez ici Au moins je n'ai pas encore trouvé. Mais un gars a prétendu l'avoir. Regardez ce post.

Envoyer MMS à partir de Mon application sous Android

3
Sahil Mahajan Mj