Надсилання та отримання SMS та MMS в Android (до Kit Kat Android 4.4)


131

Я придумав, як надсилати та отримувати SMS. Щоб надсилати SMS-повідомлення, мені довелося зателефонувати в клас sendTextMessage()та sendMultipartTextMessage()методи SmsManager. Щоб отримувати SMS-повідомлення, мені довелося зареєструвати приймач у AndroidMainfest.xmlфайлі. Тоді мені довелося перекрити onReceive()метод BroadcastReceiver. Я включив приклади нижче.

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>

Однак мені було цікаво, чи можете ви надсилати та отримувати MMS-повідомлення подібним чином. Провівши деякі дослідження, багато прикладів, що надаються в блогах, просто переходять Intentдо рідної програми Messaging. Я намагаюся надіслати MMS, не виходячи із заявки. Здається, не існує стандартного способу надсилання та отримання MMS. Хтось змусив це працювати?

Крім того, мені відомо, що SMS / MMS ContentProvider не є частиною офіційного пакета SDK для Android, але я думав, що хтось, можливо, зміг це здійснити. Будь-яка допомога дуже цінується.

Оновлення

Я додав файл BroadcastReceiverу AndroidManifest.xmlфайл для отримання 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>

У класі MMSReceiver onReceive()метод може лише захопити номер телефону, з якого було надіслане повідомлення. Як ви захоплюєте інші важливі речі з MMS, наприклад, шлях до файлу до вкладення медіа (зображення / аудіо / відео) або текст у 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...
    }
}

Відповідно до Документації на android.provider.Телефонія :

Дія трансляції: пристрій отримав нове текстове SMS-повідомлення. У намірі будуть такі додаткові значення:

pdus- An Object[]з byte[]S , що містять блоки PDU , які складають повідомлення.

Додаткові значення можуть бути вилучені за допомогою, getMessagesFromIntent(android.content.Intent) якщо BroadcastReceiver під час обробки цього наміру зіткнеться з помилкою, він повинен встановити код результату відповідним чином.

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

Дія трансляції: пристрій отримав нове SMS-повідомлення на основі даних. У намірі будуть такі додаткові значення:

pdus- An Object[]з byte[]S , що містять блоки PDU , які складають повідомлення.

Додаткові значення можна отримати за допомогою getMessagesFromIntent (android.content.Intent). Якщо BroadcastReceiver зіткнувся з помилкою під час обробки цього наміру, він повинен відповідним чином встановити код результату.

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

Дія трансляції: пристрій отримав нове повідомлення про WAP PUSH. У намірі будуть такі додаткові значення:

transactionId (Integer) - ідентифікатор транзакції WAP

pduType (Integer) - Тип PDU WAP`

header (byte[]) - Заголовок повідомлення

data (byte[]) - Навантаження даних повідомлення

contentTypeParameters (HashMap<String,String>) - Будь-які параметри, пов'язані з типом вмісту (декодується із заголовка WSP Content-Type)

Якщо BroadcastReceiver зіткнувся з помилкою під час обробки цього наміру, він повинен відповідним чином встановити код результату. Додатковим значенням contentTypeParameters є карта параметрів вмісту, введених їх іменами. Якщо зустрічаються будь-які непризначені загальновідомі параметри, ключ карти буде "непризначений / 0x ...", де "..." - шістнадцяткове значення непризначеного параметра. Якщо параметр не має значення, значення на карті буде нульовим.

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

Оновлення №2

Я зрозумів, як передати додаткові послуги в PendingIntentбути приймаються BroadcastReceiver: Android PendingIntent масовка, не отримала від BroadcastReceiver

Однак додаткові надходження передаються SendBroadcastReceiver, а не SMSReceiver . Як я можу передати додатково до SMS-приймача ?

Оновлення №3

Отримання MMS

Отож, зробивши додаткові дослідження, я побачив деякі пропозиції щодо реєстрації ContentObserver. Таким чином ви зможете виявити, коли є якісь зміни у content://mms-sms/conversationsпостачальнику вмісту, отже, ви зможете виявити вхідні MMS. Ось найближчий приклад змусити цю роботу, яку я знайшов: Отримання MMS

Однак є змінною mainActivityтипу ServiceController. Де ServiceControllerреалізований клас? Чи є якісь інші зареєстровані реалізації ContentObserver?

Надсилання MMS

Що стосується надсилання MMS, я натрапив на такий приклад: Надіслати MMS

Проблема полягає в тому, що я спробував запустити цей код на своєму Nexus 4, який знаходиться на Android v4.2.2, і я отримую цю помилку:

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

Помилка Carriersвидається після запиту ContentProvider у getMMSApns()методі APNHelperкласу.

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

Мабуть, ви не можете читати APN в Android 4.2

Яка альтернатива всім тим програмам, які використовують мобільні дані для виконання операцій (наприклад, надсилання MMS) і не знають налаштувань APN за замовчуванням, наявних у пристрої?

Оновлення №4

Надсилання MMS

Я спробував наслідувати цей приклад: Надіслати MMS

Як @Sam запропонував у своїй відповіді:

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.

Тому зараз я більше не отримую помилок SecurityException. Зараз я тестую Nexus 5 на Android KitKat. Після запуску зразкового коду він надає мені код відповіді 200 після дзвінка на

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

Однак я поспілкувався з людиною, якій я намагався надіслати MMS. І вони сказали, що ніколи не отримували MMS.


Ви раніше переглядали цей підручник? maximbogatov.wordpress.com/2011/08/13/mms-in-android
HaemEternal

3
Так, я маю. Я спробував визначити відповідь Максима разом, але не можу змусити її працювати. Там багато класів, які імпортують android.provider.telephony, який, здається, застарів.
toobsco42

І по- видимому, після прочитання @ відповідь Сахил, ви також пробував це: stackoverflow.com/questions/2972845 / ...
HaemEternal

Я не впевнений, як скласти цю відповідь разом, хоча це дуже схоже на відповідь @ Сахіла.
toobsco42

Привіт @ toobsco42, чи зможете ви знайти рішення для всіх запитів, про які ви згадували вище ..?
kamal_tech_view

Відповіді:


15

У мене була та сама проблема, яку ви описали вище (Galaxy Nexus в t-mobile США), тому що мобільні дані вимкнено.

У Jelly Bean це: Налаштування> Використання даних> мобільні дані

Зауважте, що для надсилання MMS АБО прийому, у мене повинен бути включений мобільний телефон PRIOR. Якщо я отримаю MMS з вимкненою мобільною інформацією, я отримаю сповіщення про нове повідомлення, і отримаю повідомлення з кнопкою завантаження. Але якщо я не маю мобільних даних раніше, вхідний MMS-додаток не буде отриманий. Навіть якщо я ввімкну його після отримання повідомлення.

З певних причин, коли ваш телефонний оператор дає вам можливість надсилати та приймати MMS, у вас повинен бути включений Мобільний дані, навіть якщо ви користуєтесь Wi-Fi, якщо мобільні дані включені, ви зможете отримувати та надсилати MMS, навіть якщо На вашому пристрої Wi-Fi відображається як ваш Інтернет.

Це справжній біль, так як якщо у вас його немає, повідомлення може сильно зависнути, навіть при включенні мобільних даних і може зажадати перезавантаження пристрою.


Також ви повинні знати, що надсилання SMS та MMS - це 2 абсолютно різні речі на задньому плані. MMS - це більше мережева послуга в Інтернеті, оскільки вимагає надсилання додаткових елементів (ЗМІ) з текстом. Даний код добре працює на кількох пристроях, на яких я тестувався. ps: ви можете ігнорувати частину NOKIA.
Manan Sharma

Коли я запускаю цей приклад, у LogCat він друкує: 02-24 13: 32: 40.872: V / SendMMSActivity (5686): TYPE_MOBILE_MMS не підключено, поруч 02-24 13: 32: 40.882: V / SendMMSActivity (5686): тип є не TYPE_MOBILE_MMS, поруч Тут також написано: java.lang.SecurityException: Немає дозволу писати налаштування APN: Ні користувач 10099, ні поточний процес не мають android.permission.WRITE_APN_SETTINGS. Схоже, він не може виконати цей запит: final Cursor apnCursor = this.context.getContentResolver (). Query (Uri.withAppendedPath (Carriers.CONTENT_URI, "current"), null, null, null, null); Я тестую Nexus 4.
toobsco42

Також це той самий приклад, який надав @Sahil.
toobsco42

7

Не існує офіційної підтримки api, що означає, що вона не документально підтверджена для громадськості, і бібліотеки можуть змінюватися в будь-який час. Я усвідомлюю, що ви не хочете залишати програму, але ось, як ви робите це з наміром для всіх, хто цікавиться.

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

}

Я не зовсім зрозумів, як зробити такі речі, як відстеження доставки повідомлення, але це повинно надіслати його.

Ви можете попередити про отримання mms так само, як sms. Фільтр намірів на приймачі повинен виглядати приблизно так.

<intent-filter>
    <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
    <data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>

Це не просто запускає вбудовану програму Повідомлення?
toobsco42

1
так вибачте з цього приводу. Я щойно зрозумів, що ви вже знали, як це зробити. Я додав, як отримувати mms, хоча.
користувач1959417

Дякую, я нещодавно впроваджував частину MMS BroadcastReceiverі використовував те, Intent Filterщо ви розмістили. Я скоро оновлю це питання.
toobsco42

4

Щоб надіслати mms для Android 4.0 api 14 або новішої версії без дозволу писати налаштування apn, ви можете використовувати цю бібліотеку : Отримайте коди mnc та mcc з android, а потім зателефонуйте

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

Щоб використати це, додайте Jsoup і дроїд- призмову jar до шляху збирання та імпортуйте com.droidprism. *;


Привіт @Sam, я додав файл .jar до свого проекту, але отримую цю помилку в рядку, який створює об'єкт Carrier: java.lang.NoClassDefFoundError: com.droidprism.Carrier це з вами відбувається?
toobsco42

немає. Ви повинні додати jsoup до шляху збирання, jar до шляху збирання та імпортувати com.droidprism. *; Я відредагую відповідь. Для цього в android додайте спочатку банки в каталог libs, потім налаштуйте шлях збирання проекту для використання банок, які вже знаходяться в каталозі libs, потім на конфігурації контуру конвеєра натисніть порядок і експортуйте та встановіть прапорці в банках і перемістіть jsoup і droidprism jar до початку порядку складання.
Сем Адамш

Додавання Jsoup .jar вирішило NoClassDefFoundError. Тепер я можу отримати налаштування APN. Наступний крок - з'ясувати, як надсилати MMS.
toobsco42

3

Я не думаю, що існує будь-яка підтримка sdk для надсилання mms в android. Подивіться тут Принаймні я ще не знайшов. Але хлопець стверджував, що це є. Погляньте на цю публікацію.

Надсилайте MMS з програми "Мій додаток" на android


Я переглянув коментарі до androidbridge.blogspot.com повідомлення про реалізацію Nokia, і, схоже, у багатьох людей виникають проблеми з тим, щоб це працювало на своїх пристроях.
toobsco42

@ toobsco42 Отже, підтримка для цього ще може бути.
Sahil Mahajan Mj

-2

Я не розумію розчарувань. Чому б не просто зробити приймач мовлення, який фільтрує для цього намір:

android.provider.Telephony.MMS_RECEIVED

Я перевірив трохи далі, і вам може знадобитися доступ на системному рівні, щоб отримати це (вкорінений телефон).


3
Привіт @ j2emanue. Проблема полягає в тому, як ви отримаєте цей намір, як ви насправді отримуєте вміст MMS? Якщо MMS містить і зображення, і текст, як витягти ці компоненти.
toobsco42

але я помічаю theres байтовий масив, який ви можете отримати, якщо це зробити так, як я згадав .... byte [] data = intent.getByteArrayExtra ("дані"); я не впевнений, як розібратися, хоча шкода.
j2emanue

я вмію розбирати це. але все, що я можу отримати, - це тематика, звідки прийшла повідомлення, і тематичне місцезнаходження, де зберігається вміст файлів. однак ця URL-адреса недоступна.
toobsco42

-2

SmsListenerClass

public class SmsListener extends BroadcastReceiver {

static final String ACTION =
        "android.provider.Telephony.SMS_RECEIVED";

@Override
public void onReceive(Context context, Intent intent) {

    Log.e("RECEIVED", ":-:-" + "SMS_ARRIVED");

    // TODO Auto-generated method stub
    if (intent.getAction().equals(ACTION)) {

        Log.e("RECEIVED", ":-" + "SMS_ARRIVED");

        StringBuilder buf = new StringBuilder();
        Bundle bundle = intent.getExtras();
        if (bundle != null) {

            Object[] pdus = (Object[]) bundle.get("pdus");

            SmsMessage[] messages = new SmsMessage[pdus.length];
            SmsMessage message = null;

            for (int i = 0; i < messages.length; i++) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    String format = bundle.getString("format");
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i], format);
                } else {
                    messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                }

                message = messages[i];
                buf.append("Received SMS from  ");
                buf.append(message.getDisplayOriginatingAddress());
                buf.append(" - ");
                buf.append(message.getDisplayMessageBody());
            }

            MainActivity inst = MainActivity.instance();
            inst.updateList(message.getDisplayOriginatingAddress(),message.getDisplayMessageBody());

        }

        Log.e("RECEIVED:", ":" + buf.toString());

        Toast.makeText(context, "RECEIVED SMS FROM :" + buf.toString(), Toast.LENGTH_LONG).show();

    }
}

Діяльність

@Override
public void onStart() {
    super.onStart();
    inst = this;
}

public static MainActivity instance() {
    return inst;
}

public void updateList(final String msg_from, String msg_body) {

    tvMessage.setText(msg_from + " :- " + msg_body);

    sendSMSMessage(msg_from, msg_body);

}

protected void sendSMSMessage(String phoneNo, String message) {

    try {
        SmsManager smsManager = SmsManager.getDefault();
        smsManager.sendTextMessage(phoneNo, null, message, null, null);
        Toast.makeText(getApplicationContext(), "SMS sent.", Toast.LENGTH_LONG).show();
    } catch (Exception e) {
        Toast.makeText(getApplicationContext(), "SMS faild, please try again.", Toast.LENGTH_LONG).show();
        e.printStackTrace();
    }
}

Маніфест

<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS"/>

<receiver android:name=".SmsListener">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.