我已经学会了如何发送和接收短信。发送短信需要调用SmsManager
类的sendTextMessage()
和sendMultipartTextMessage()
方法。接收短信需要在AndroidMainfest.xml
文件中注册接收器,并覆盖BroadcastReceiver
的onReceive()
方法。以下是示例。
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的一部分,但我认为可能有人能够实现这个。非常感谢任何帮助。
更新
我已经将一个
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 的文档:
Broadcast Action: A new text based SMS message has been received by the device. The intent will have the following extra values:
pdus
- AnObject[]
ofbyte[]
s containing the PDUs that make up the message.The extra values can be extracted using
getMessagesFromIntent(android.content.Intent)
If a BroadcastReceiver encounters an error while processing this intent it should set the result code appropriately.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
Broadcast Action: A new data based SMS message has been received by the device. The intent will have the following extra values:
pdus
- AnObject[]
ofbyte[]
s containing the PDUs that make up the message.The extra values can be extracted using getMessagesFromIntent(android.content.Intent). If a BroadcastReceiver encounters an error while processing this intent it should set the result code appropriately.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
Broadcast Action: A new WAP PUSH message has been received by the device. The intent will have the following extra values:
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)If a BroadcastReceiver encounters an error while processing this intent it should set the result code appropriately. The contentTypeParameters extra value is map of content parameters keyed by their names. If any unassigned well-known parameters are encountered, the key of the map will be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If a parameter has No-Value the value in the map will be null.
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
更新 #2
我已经找到如何通过PendingIntent
传递额外参数给BroadcastReceiver
并接收:
然而,额外参数被传递给了SendBroadcastReceiver而不是SMSReceiver。我该如何将额外参数传递给SMSReceiver?
更新 #3
接收MMS
经过更多的研究,我看到一些建议注册一个ContentObserver
来检测content://mms-sms/conversations
内容提供程序中的任何更改,从而可以检测到传入的MMS。这是我找到的最接近能够起作用的例子:接收MMS
发送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.
在
APNHelper
类的getMMSApns()
方法中查询Carriers
ContentProvider后,会抛出错误。final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
显然,在Android 4.2中无法读取APNs。
所有使用移动数据执行操作(如发送MMS)且不知道设备上存在的默认APN设置的应用程序的替代方案是什么?
更新#4
发送MMS
我尝试了以下示例:发送MMS
如@Sam在他的回答中建议的那样:
您必须将jsoup添加到构建路径中,将jar文件添加到构建路径并导入com.droidprism。要在Android中执行此操作,请首先将jars添加到libs目录中,然后配置项目构建路径以使用已经在libs目录中的jars,然后在构建路径配置上单击“顺序和导出”并选中框中的jars,并将jsoup和droidprism jar移到构建顺序的顶部。
现在我不再遇到SecurityException错误。我正在Nexus 5上测试Android KitKat。运行示例代码后,调用结束后返回200响应代码。
MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);
然而,我和我尝试发送MMS的人进行了核实。他们表示从未收到过MMS。