我已经弄清楚了如何发送和接收短信。要发送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的标准方法。有没有人得到这个工作?
另外,我知道SMS / MMS ContentProvider并不是官方Android SDK的一部分,但我认为有人可能已经能够实现此功能。任何帮助是极大的赞赏。
更新资料
我已BroadcastReceiver
在AndroidManifest.xml
文件中添加,以接收彩信
<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()
方法只能获取从其发送消息的phoneNumber。您如何从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[]
,byte[]
其中包含构成消息的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[]
,byte[]
其中包含构成消息的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交易ID
pduType (Integer)
-WAP PDU类型`
header (byte[])
-邮件标题
data (byte[])
-消息的数据有效载荷
contentTypeParameters (HashMap<String,String>)
-与内容类型关联的任何参数(从WSP Content-Type标头解码)如果BroadcastReceiver在处理此意图时遇到错误,则应适当设置结果代码。contentTypeParameters额外值是由内容参数的名称作为键的内容映射。如果遇到任何未分配的已知参数,则映射的键将为“未分配/ 0x ...”,其中“ ...”是未分配参数的十六进制值。如果参数没有值,则映射中的值将为null。
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
更新#2
我已经弄清楚了如何通过a PendingIntent
接收附加内容BroadcastReceiver
:
Android PendingIntent附加内容,而不是BroadcastReceiver接收的附加内容
但是,多余的钱将传递给SendBroadcastReceiver而不是SMSReceiver。如何将多余的钱传递给SMSReceiver?
更新#3
接收彩信
因此,在进行了更多研究之后,我发现了一些注册域名的建议ContentObserver
。这样,您可以检测到content://mms-sms/conversations
内容提供程序何时有任何更改,从而使您可以检测传入的MMS。这是我发现的最有效的示例:接收彩信
但是,有一个mainActivity
type 变量ServiceController
。ServiceController
该类在哪里实现?注册后还有其他实现ContentObserver
吗?
发送彩信
关于发送彩信,我遇到了以下示例:发送彩信
问题是我尝试在Android v4.2.2上的Nexus 4上运行以下代码,但收到此错误:
java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has android.permission.WRITE_APN_SETTINGS.
在类Carriers
的getMMSApns()
方法中查询ContentProvider 后,将引发错误APNHelper
。
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
显然您无法在Android 4.2中阅读APN
对于所有使用移动数据执行操作(例如发送MMS)并且不知道设备中存在默认APN设置的应用程序,有什么选择?
更新#4
发送彩信
我试过以下示例: 发送彩信
正如@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错误。我现在正在Android KitKat的Nexus 5上进行测试。运行示例代码后,在调用之后,我会收到200响应代码
MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);
但是,我与尝试发送MMS的人进行了核对。他们说他们从未收到过彩信。