在Android中发送和接收短信和彩信(前吉塔Android 4.4)

我已经想出了如何发送和接收短信。 为了发送SMS消息,我必须调用SmsManager类的sendTextMessage()sendMultipartTextMessage()方法。 要接收SMS消息,我必须在AndroidMainfest.xml文件中注册一个接收器。 然后我不得不重写BroadcastReceiveronReceive()方法。 我已经包含了下面的例子。

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文件以接收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中抓取其他重要的东西,如媒体附件的文件path(图像/audio/video),或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的文档 :

广播动作:设备接收到新的基于短信的短信。 意图将有以下额外的价值:

pdus – 包含组成消息的PDU的byte[]Object[]

可以使用getMessagesFromIntent(android.content.Intent)提取额外的值。如果BroadcastReceiver在处理此意图时遇到错误,则应该适当地设置结果代码。

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

广播动作:设备接收到新的基于数据的SMS消息。 意图将有以下额外的价值:

pdus – 包含组成消息的PDU的byte[]Object[]

额外的值可以使用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 PDUtypes

header (byte[]) – 消息头

data (byte[]) – 消息的数据有效载荷

contentTypeParameters (HashMap<String,String>) – 与内容types相关的任何参数(从WSP Content-Type头解码)

如果BroadcastReceiver在处理这个意图时遇到错误,它应该适当地设置结果代码。 contentTypeParameters额外值是由其名称所键入的内容参数的映射。 如果遇到任何未分配的众所周知的参数,映射的键将是'unassigned / 0x …',其中'…'是未赋值参数的hex值。 如果参数具有无值,则映射中的值将为空。

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

更新#2

我已经想出了如何在PendingIntent传递extras来被BroadcastReceiver接收: Android PendingIntent extras,没有被BroadcastReceiver接收

但是,多余的传递给SendBroadcastReceiver而不是SMSReceiver 。 我怎样才能把一个额外的SMSReceiver

更新#3

接收彩信

所以在做了更多的研究之后,我看到了一些关于注册一个ContentObserverbuild议。 这样,你可以检测到什么时候内容有任何改变content://mms-sms/conversations内容提供者,因此允许你检测传入的彩信。 这是最接近的例子,让我工作,我发现: 接收彩信

但是,有一个ServiceControllertypes的variablesmainActivityServiceController类在哪里实现? 是否有任何其他的注册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. 

在查询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

对于所有使用移动数据执行操作的应用程序(如发送彩信),不知道设备中存在的默认APN设置,有什么select?

更新#4

发送彩信

我试过以下例子: 发送彩信

正如@Sam在他的回答中所build议的那样:

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错误。 我正在testingAndroid KitKat上的Nexus 5。 运行示例代码后,它给了我一个200响应后的代码

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

不过,我检查了我尝试发送彩信的人。 他们说,他们从来没有收到彩信。

我有上面描述的完全相同的问题(Galaxy Nexus on t-mobile USA),这是因为移动数据已closures。

在果冻豆它是:设置>数据使用>移动数据

请注意,我必须先启用移动数据才能发送彩信或接收彩信。 如果我收到移动数据已closures的彩信,我将收到一条新消息的通知,我将收到带有下载button的消息。 但是,如果我以前没有移动数据,将不会收到传入的MMS附件。 即使我收到邮件后打开它。

出于某种原因,当您的电话提供商使您能够发送和接收彩信时,即使您使用的是Wifi,也必须启用移动数据,如果启用了移动数据,您将能够接收和发送彩信,即使Wifi显示为您的设备上的互联网。

这是一个真正的痛苦,就好像你没有打开它,即使打开移动数据,信息也会挂起很多,并且可能需要重新启动设备。

没有官方的api支持,这意味着它没有为公众logging,图书馆可能随时改变。 我意识到你不想离开应用程序,但这是你如何做的一个意图任何人想知道。

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

我还没有完全想到如何做跟踪邮件传递的事情,但这应该让它发送。

您可以像短信一样收到彩信的提醒。 接收机上的意图filter应该看起来像这样。

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

要发送Android 4.0 api 14或更高版本的mms,而没有写入apn设置的权限,可以使用此库 :从android中检索mnc和mcc代码,然后调用

 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和droid prism jar添加到构buildpath,并导入com.droidprism。*;

我不认为有任何sdk支持在android中发送彩信。 看这里至less我还没有find。 但一个人声称拥有它。 看看这个post。

从我的应用程序在Android中发送彩信

我不明白的挫折。 为什么不直接制作一个广播接收器来过滤这个意图:

 android.provider.Telephony.MMS_RECEIVED 

我进一步检查了一下,你可能需要系统级访问来获得这个(根植电话)。

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(); } } 

performance

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