我已经弄清楚如何发送和接收 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>
但是,我想知道您是否可以以类似的方式发送和接收彩信。在做一些研究之后,博客上提供的许多示例只是简单地将一个传递Intent
给原生消息传递应用程序。我正在尝试在不离开我的应用程序的情况下发送彩信。似乎没有发送和接收彩信的标准方式。有没有人让这个工作?
另外,我知道 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()
方法只能获取发送消息的电话号码。您如何从 MMS 中获取其他重要信息,例如媒体附件(图像/音频/视频)的文件路径或 MMS 中的文本?
彩信接收器.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
-包含组成消息的 PDU的Object[]
of s。byte[]
getMessagesFromIntent(android.content.Intent)
如果广播接收器在处理此意图时遇到错误,则可以提取额外的值,它应该适当地设置结果代码。@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
广播动作:设备已收到一条新的基于数据的 SMS 消息。意图将具有以下额外值:
pdus
-包含组成消息的 PDU的Object[]
of s。byte[]
可以使用 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...”,其中“...”是未分配参数的十六进制值。如果参数没有值,则映射中的值将为空。
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
更新#2
我已经想出了如何在 a 中传递额外内容以PendingIntent
供 a 接收BroadcastReceiver
:
Android PendingIntent extras, not received by BroadcastReceiver
但是,额外的被传递给SendBroadcastReceiver而不是SMSReceiver。我怎样才能将额外的传递给SMSReceiver?
更新#3
接收彩信
所以在做了更多研究之后,我看到了一些注册ContentObserver
. 这样您就可以检测到content://mms-sms/conversations
Content Provider 何时发生任何更改,从而使您能够检测传入的彩信。这是我发现的最接近的示例:接收彩信
但是,有一个mainActivity
类型为 的变量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
ContentProvider后抛出错误。getMMSApns()
APNHelper
final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
对于使用移动数据执行操作(如发送彩信)并且不知道设备中存在的默认 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);
但是,我咨询了我尝试向其发送彩信的人。他们说他们从未收到过彩信。