Я выяснил, как отправлять и получать 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 не является частью официального Android SDK, но я думал, что кто-то, возможно, смог это реализовать. Любая помощь приветствуется.
Update
Я добавил файл 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.Telephony:
Трансляция: новое SMS-сообщение на основе текстовой информации было получено устройством. У намерения будут следующие дополнительные значения:
pdus
-Object[]
ofbyte[]
, содержащий 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
-Object[]
ofbyte[]
, содержащий 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)
- Тип WAP PDU
header (byte[])
- заголовок сообщения
data (byte[])
- Полезная нагрузка данных сообщения
contentTypeParameters (HashMap<String,String>)
- Любые параметры, связанные с типом контента (декодированные из заголовка Content-Type WSP)Если BroadcastReceiver обнаруживает ошибку при обработке этого намерения, он должен соответствующим образом установить код результата. Дополнительное значение contentTypeParameters - это карта параметров контента, подкрепленных их именами. Если обнаружены какие-либо непризнанные хорошо известные параметры, ключ карты будет "неназначен/0x...", где "..." является шестнадцатеричным значением неназначенного параметра. Если параметр имеет значение No-value, значение на карте будет равно null.
@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. Как передать дополнительную информацию в SMSReceiver?
Обновление # 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.