在Android中发送和接收短信和彩信(pre Kit Kat Android 4.4)

时间:2013-01-22 06:29:08

标签: android sms broadcastreceiver android-manifest mms

我已经弄明白了如何发送和接收短信。要发送短信,我必须调用sendTextMessage()课程的sendMultipartTextMessage()SmsManager方法。要接收SMS消息,我必须在AndroidMainfest.xml文件中注册一个接收器。然后我必须覆盖onReceive()的{​​{1}}方法。我在下面列举了一些例子。

MainActivity.java

BroadcastReceiver

SMSReceiver.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 ...
}

的AndroidManifest.xml

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

但是,我想知道您是否可以以类似的方式发送和接收彩信。在做了一些研究之后,博客上提供的许多示例只是将<?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> 传递给本机Messaging应用程序。我试图在不离开我的申请的情况下发送彩信。似乎并不是发送和接收MMS的标准方式。有没有人得到这个工作?

此外,我知道SMS / MMS ContentProvider不是官方Android SDK的一部分,但我认为有人可能已经能够实现这一点。非常感谢任何帮助。

更新

我在Intent文件中添加了BroadcastReceiver以接收彩信

AndroidManifest.xml

在MMSReceiver类中,<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> 方法只能获取发送邮件的phoneNumber。你如何从MMS中获取其他重要信息,例如媒体附件的文件路径(图像/音频/视频)或MMS中的文本?

MMSReceiver.java

onReceive()

根据Documentation of android.provider.Telephony

  

广播操作:设备已收到新的基于文本的SMS消息。意图将具有以下额外值:

     

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... } } - pdusObject[]个,其中包含构成邮件的PDU。

     

可以使用byte[]提取额外值   如果BroadcastReceiver在处理此意图时遇到错误,则应该适当地设置结果代码。

getMessagesFromIntent(android.content.Intent)
     
     

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

     

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED"; - pdusObject[]个,其中包含构成邮件的PDU。

     

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

byte[]
     
     

广播操作:设备已收到新的WAP PUSH消息。意图将具有以下额外值:

     

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED"; - WAP交易ID

     

transactionId (Integer) - WAP PDU类型`

     

pduType (Integer) - 邮件标题

     

header (byte[]) - 消息的数据有效负载

     

data (byte[]) - 与内容类型相关的任何参数(从WSP Content-Type标头解码)

     

如果BroadcastReceiver在处理此意图时遇到错误,则应该适当地设置结果代码。   contentTypeParameters额外值是按名称键入的内容参数的映射。   如果遇到任何未分配的众所周知的参数,地图的键将被取消分配/ 0x ...&#39;,其中&#39; ...&#39;是未分配参数的十六进制值。如果参数具有No-Value,则映射中的值将为null。

contentTypeParameters (HashMap<String,String>)

更新#2

我已经想出如何通过@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED"; 传递PendingIntent中的额外内容:BroadcastReceiverAndroid PendingIntent extras, not received by BroadcastReceiver

但是,额外的内容会传递给 SendBroadcastReceiver 而不是 SMSReceiver 。如何将额外内容传递给 SMSReceiver

更新#3

接收彩信

因此,在做了更多研究之后,我看到了一些注册ContentObserver的建议。这样,您可以检测到content://mms-sms/conversations内容提供商何时发生任何更改,从而允许您检测传入的MMS。以下是我发现的最接近的示例:Receiving MMS

但是,mainActivity类型的变量ServiceControllerServiceController类在哪里实现?注册ContentObserver还有其他任何实现吗?

发送彩信

至于发送彩信,我遇到过这个例子:Send 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类的getMMSApns()方法中查询APNHelper ContentProvider后,会抛出错误。

final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);

显然你不能read APNs in Android 4.2

使用移动数据执行操作(如发送彩信)并且不知道设备中存在的默认APN设置的所有应用程序有哪些替代方案?

更新#4

发送彩信

我尝试过以下示例:Send 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错误。我正在测试Android KitKat上的Nexus 5。运行示例代码后,在调用

后,它会给出200响应代码
MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);

但是,我与我尝试发送彩信的人进行了核实。他们说他们从未收到彩信。

5 个答案:

答案 0 :(得分:15)

我遇到了你上面描述的完全相同的问题(T-mobile USA上的Galaxy Nexus),这是因为关闭了移动数据。

在Jelly Bean中它是: 设置&gt;数据使用&gt;移动数据

请注意,我必须在发送彩信或接收彩信之前启用移动数据。如果我收到关闭移动数据的彩信,我将收到新消息的通知,我将收到带有下载按钮的消息。但如果我之前没有移动数据,则不会收到传入的MMS附件。即使我在收到消息后打开它。

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

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

答案 1 :(得分:4)

要在没有写入apn设置权限的情况下发送Android 4.0 api 14或更高版本的mms,您可以使用this library: 从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添加到构建路径,然后导入com.droidprism。*;

答案 2 :(得分:3)

我不认为在android中发送mms有任何sdk支持。 Look here至少我还没找到。但一个人声称拥有它。看看这篇文章。

Send MMS from My application in android

答案 3 :(得分:-1)

我不明白挫折感。为什么不让一个广播接收者过滤这个意图:

android.provider.Telephony.MMS_RECEIVED

我进一步检查了一下你可能需要系统级别的访问来获取这个(root电话)。

答案 4 :(得分:-2)

  

SmsListenerClass

 <asp:Image ID="Id" ImageUrl="~/Uploads/new/sum.jpg" runat="server" />
  

活动

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