88 votes

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

J'ai compris comment envoyer et recevoir SMS messages. Pour envoyer SMS messages, j'ai dû appeler le sendTextMessage() et sendMultipartTextMessage() méthodes de l SmsManager classe. Pour recevoir SMS j'ai dû enregistrer un récepteur dans l'application AndroidMainfest.xml fichier. Ensuite, j'ai dû remplacer le onReceive() de la méthode 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 de manière similaire. Après avoir fait quelques recherches, de nombreux exemples fournis sur les blogs font simplement passer un Intent à l'application native de la messagerie. J'essaie d'envoyer un MMS sans quitter mon application. Il ne semble pas y avoir de moyen standard pour envoyer et recevoir MMS . Quelqu'un a-t-il réussi à faire fonctionner ce système ?

De plus, je suis conscient que le ContentProvider SMS/MMS ne fait pas partie de la version officielle de l'interface utilisateur. Android SDK mais je me disais que quelqu'un avait peut-être réussi à le mettre en œuvre. Toute aide est grandement appréciée.

Mise à jour

J'ai ajouté un BroadcastReceiver à la AndroidManifest.xml pour recevoir MMS messages

<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 fonction onReceive() est seulement capable de récupérer le numéro de téléphone d'où le message a été envoyé. Comment récupérer d'autres éléments importants d'un MMS comme le chemin d'accès à la pièce jointe (image/audio/vidéo) ou le texte de l'en-tête du message. 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 de diffusion : Un nouveau message SMS a été reçu par l'appareil. L'intention aura les valeurs supplémentaires suivantes :

pdus - An Object[] od byte[]s containing the PDUs that make up the message.

Les valeurs supplémentaires peuvent être extraites en utilisant 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 de diffusion : Un nouveau message SMS basé sur des données a été reçu par le dispositif. L'intention aura les valeurs supplémentaires suivantes :

pdus - An Object[] of byte[]s containing the PDUs that make up the message.

Les valeurs supplémentaires peuvent être extraites en utilisant 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 de diffusion : Un nouveau message WAP PUSH a été reçu par l'appareil. L'intention aura les valeurs supplémentaires suivantes :

transactionId (Integer) - The WAP transaction ID

pduType (Integer) - The WAP PDU type

header (byte[]) - The header of the message

data (byte[]) - The data payload of the message

contentTypeParameters (HashMap<String,String>) - Any parameters associated with the content type (decoded from the WSP Content-Type header)

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 une carte de paramètres de contenu dont la clé est leur nom. Si des paramètres connus non attribués sont rencontrés, la clé de la carte sera "unassigned/0x...", où "..." est la valeur hexagonale du paramètre non attribué. Si un paramètre a une valeur nulle, la valeur dans la carte sera nulle.

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";

Mise à jour n°2

J'ai trouvé comment passer des extras dans un fichier de type PendingIntent à recevoir par un BroadcastReceiver : Extras PendingIntent d'Android, non reçus par BroadcastReceiver

Cependant, le supplément est transmis à la SendBroadcastReceiver pas le Récepteur de SMS . Comment puis-je passer un extra à la Récepteur de SMS ?

Mise à jour n°3

Réception de MMS

Après avoir approfondi mes recherches, j'ai vu qu'il était possible d'enregistrer un nom de domaine. ContentObserver . De cette façon, vous pouvez détecter quand il y a des changements dans les content://mms-sms/conversations fournisseur de contenu, ce qui vous permet de détecter les MMS entrants. Voici l'exemple le plus proche de ce fonctionnement que j'ai trouvé : Réception de MMS

Cependant, il existe une variable mainActivity de type ServiceController . Où se trouve le ServiceController mis en œuvre ? Existe-t-il d'autres implémentations d'une classe enregistrée ContentObserver ?

Envoi de MMS

Quant à l'envoi de MMS, je suis tombé sur cet exemple : Envoyer des MMS

Le problème est que j'ai essayé d'exécuter ce code sur mon Nexus 4, qui est sous 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 se produit après l'interrogation de la base de données de l'UE. Carriers ContentProvider dans le getMMSApns() de la méthode APNHelper classe.

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 ces applications qui utilisent les données mobiles pour effectuer des opérations (comme l'envoi de MMS) et qui ne connaissent pas le paramètre APN par défaut présent dans l'appareil ?

Mise à jour n°4

Envoi de MMS

J'ai essayé de suivre cet exemple : Envoyer des 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.

Maintenant, je n'ai plus d'erreurs SecurityException. Je teste maintenant sur un Nexus 5 sous Android KitKat. Après avoir exécuté l'exemple de code, j'obtiens un code de réponse 200 après l'appel à

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

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

12voto

Lorsque j'ai 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, c'est : Paramètres > Utilisation des données > données mobiles

Notez que les données mobiles doivent être activées AVANT d'envoyer un MMS OU d'en recevoir un. Si je reçois un MMS alors que les données mobiles sont désactivées, je recevrai la notification d'un nouveau message et je recevrai le message avec un bouton de téléchargement. Mais si je n'ai pas de données mobiles activées au préalable, la pièce jointe du MMS entrant ne sera pas reçue. Même si je les active 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 des MMS, les données mobiles doivent être activées, même si vous utilisez le Wifi. Si les données mobiles sont activées, vous serez en mesure de recevoir et d'envoyer des MMS, même si le Wifi est affiché comme Internet sur votre appareil.

C'est une véritable plaie, car si vous ne l'avez pas activée, le message peut se bloquer très souvent, même en activant les données mobiles, et peut nécessiter un redémarrage de l'appareil.

6voto

user1959417 Points 116

Il n'y a pas de support officiel de l'api, ce qui signifie qu'elle n'est pas documentée 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 faire avec une intention pour tous ceux qui se posent la question.

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 encore complètement trouvé comment faire des choses comme le suivi de la livraison du message, mais cela devrait permettre de l'envoyer.

Vous pouvez être alerté de la réception d'un mms de la même manière qu'un 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>

2voto

Sahil Mahajan Mj Points 5754

Je ne pense pas qu'il y ait un support sdk pour l'envoi de mms dans Android. Regardez ici Du moins, je ne l'ai pas encore trouvé. Mais un type a prétendu l'avoir. Jetez un coup d'oeil à ce post.

Envoyer des MMS à partir de mon application sous Android

2voto

Sam Adams Points 917

Pour envoyer un mms pour Android 4.0 api 14 ou plus sans la permission d'écrire les paramètres 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 l'utiliser, ajoutez Jsoup et droid prism jar au chemin de construction, et importez com.droidprism.* ;

0voto

j2emanue Points 3456

Je ne comprends pas les frustrations. Pourquoi ne pas simplement faire un récepteur de diffusion qui filtre pour cette intention :

android.provider.Telephony.MMS_RECEIVED

J'ai vérifié un peu plus loin et vous pourriez avoir besoin d'un accès au niveau du système pour l'obtenir (téléphone rooté).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X