我已经弄清楚了如何发送和接收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>


但是,我想知道您是否可以以类似的方式发送和接收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的文档:


广播操作:设备已接收到基于文本的新S​​MS消息。该意图将具有以下附加值:

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

可以使用getMessagesFromIntent(android.content.Intent) <提取附加值。 br />如果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额外值是由内容参数的名称作为键的内容参数的映射。
如果有未分配的众所周知的遇到参数时,映射的键将为“ unssigned / 0x ...”,其中“ ...”是未分配参数的十六进制值。如果参数没有值,则映射中的值将为空。

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



更新#2

我有弄清楚了如何将PendingIntent中的附加功能传递给BroadcastReceiver来接收:
Android PendingIntent附加功能,不是BroadcastReceiver接收的。

但是,附加功能会传递给SendBroadcastReceiver而不是SMSReceiver。如何将多余的钱传递给SMSReceiver?

更新#3

接收MMS

因此,在进行了更多研究之后,我发现了一些注册ContentObserver的建议。这样,您可以检测到content://mms-sms/conversations Content Provider何时有任何更改,从而使您可以检测传入的MMS。这是我发现的最有效的示例:接收MMS

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

发送MMS

关于发送MMS,我碰到过以下示例:发送MMS

问题是我尝试在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()方法查询APNHelper 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在其答案中建议的那样:

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响应代码。但是,我与尝试发送MMS的人进行了核对。他们说他们从未收到过彩信。

评论

您之前看过本教程吗? maximbogatov.wordpress.com/2011/08/13/mms-in-android

是的,我有。我尝试将Maxim的答案拼凑在一起,但无法使其正常工作。那里有很多导入android.provider.telephony的类,它们似乎已被弃用。

大概,在阅读@Sahil的答案之后,您还尝试了以下操作:stackoverflow.com/questions/2972845/…

尽管看起来与@Sahil的答案非常相似,但我不确定如何将其拼凑起来。

@ toobsco42您好,您能够找到上面提到的所有查询的解决方案。.

#1 楼

我遇到了与您上述完全相同的问题(美国t-mobile上的Galaxy Nexus),是因为移动数据已关闭。

在Jelly Bean中,它是:移动数据

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

由于某种原因,当您的电话提供商允许您发送和接收彩信时,即使您正在使用,也必须启用移动数据Wifi,如果启用了“移动数据”,即使Wifi在您的设备上显示为Internet,您也将能够收发MMS。

这真是一个痛苦,好像您没有启用此功能后,即使打开“移动数据”,该消息也可能会挂很多,并且可能需要重新启动设备。

评论


另外,您还必须知道,发送SMS和MMS在后台是完全不同的两件事。 MMS更像是基于Internet的网络服务,因为它需要发送带有文本的其他项目(媒体)。给定的代码可以在我测试过的一些设备上正常工作。 ps:您可以忽略诺基亚部分。

– Manan Sharma
13年2月14日在13:28



当我运行此示例时,在LogCat中打印:02-24 13:32:40.872:V / SendMMSActivity(5686):TYPE_MOBILE_MMS未连接,保释02-24 13:32:40.882:V / SendMMSActivity(5686):类型为不是TYPE_MOBILE_MMS,请保释。它还说:java.lang.SecurityException:没有写APN设置的权限:用户10099或当前进程都没有android.permission.WRITE_APN_SETTINGS。似乎无法执行此查询:最终游标apnCursor = this.context.getContentResolver()。query(Uri.withAppendedPath(Carriers.CONTENT_URI,“ current”),null,null,null,null);我正在Nexus 4上进行即时测试。

–toobsco42
13年2月24日在21:40



这也是@Sahil提供的示例。

–toobsco42
13年2月24日在21:47

#2 楼

没有官方的api支持,这意味着它没有公开记录,并且库可能随时更改。我意识到您不想离开该应用程序,但是出于其他任何想知道的目的,这是您要做的事情。

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

}


我还没有完全弄清楚如何可以执行诸如跟踪邮件的传递之类的操作,但这应该可以将其发送出去。

可以像发送短信一样向您通知彩信的接收。接收器上的意图过滤器应如下所示。

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


评论


这不只是启动本机消息传递应用程序吗?

–toobsco42
13年1月23日在18:53

是的,对此感到抱歉。我只是意识到您已经知道该怎么做。我确实添加了如何接收彩信。

–user1959417
2013年1月23日19:16

谢谢,我最近一直在实现MMS BroadcastReceiver的一部分,并使用了您发布的Intent Filter。我将尽快更新这个问题。

–toobsco42
2013年1月23日19:41



#3 楼

要在未经许可的情况下为Android 4.0 api 14或更高版本发送彩信,可以使用此库:
从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棱镜罐添加到构建路径,然后导入com.droidprism。*;

评论


嘿@Sam,我将.jar文件添加到我的项目中,但是在实例化Carrier对象的行上遇到此错误:java.lang.NoClassDefFoundError:com.droidprism.Carrier这是您的事吗?

–toobsco42
13年7月26日在20:54

没有。您必须将jsoup添加到构建路径,将jar添加到构建路径并导入com.droidprism。*;。我将编辑答案。要在android中做到这一点,首先将jars添加到libs目录中,然后配置项目构建路径以使用libs目录中已经存在的jars,然后在构建路径config上单击order并导出并选中jars的框并移动将jsoup和droidprism置于构建顺序的顶部。

–山姆·亚当什(Sam Adamsh)
13年7月27日在17:44



添加Jsoup .jar解决了NoClassDefFoundError。我现在可以获取APN设置。下一步是弄清楚如何发送彩信。

–toobsco42
13年7月30日在17:05

#4 楼

我不认为在Android中发送mms有任何SDK支持。看这里我还没有找到Atleast。但是一个人声称拥有它。看看这篇文章。

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

评论


我查看了诺基亚实现的androidbridge.blogspot.com帖子中的评论,看来很多人在使它在其设备上运行时遇到问题。

–toobsco42
13年1月22日在7:13

@ toobsco42因此,可能尚无支持。

– Sahil Mahajan Mj
13年1月22日在7:20

#5 楼

我不明白挫败感。为什么不制作一个过滤此目的的广播接收器:

android.provider.Telephony.MMS_RECEIVED


我进一步检查了一下,您可能需要系统级访问权限才能获得此电话(有根电话)。 br />

评论


嘿@ j2emanue,问题是您收到此意图后,实际上如何获得MMS的内容?如果彩信包含图像和文本,则如何提取这些组件。

–toobsco42
14年2月27日在22:05

但是我注意到,如果按照.i提到的方式进行操作,则可以获得额外的字节数组。...byte [] data = intent.getByteArrayExtra(“ data”);林不知道如何解析,虽然抱歉。

– j2emanue
14年2月27日在22:15

我能够解析它。但是我所能获得的只是主题,彩信的来源以及存储彩信内容的contentlocation。但是无法访问该URL。

–toobsco42
2014-2-27在22:17



#6 楼


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



清单


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