133

我已经弄清楚如何发送和接收 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 的一部分,但我想有人可能已经能够实现这一点。任何帮助是极大的赞赏。

更新

BroadcastReceiverAndroidManifest.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 接收BroadcastReceiverAndroid PendingIntent extras, not received by BroadcastReceiver

但是,额外的被传递给SendBroadcastReceiver而不是SMSReceiver。我怎样才能将额外的传递给SMSReceiver

更新#3

接收彩信

所以在做了更多研究之后,我看到了一些注册ContentObserver. 这样您就可以检测到content://mms-sms/conversationsContent 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.

在类的方法中查询CarriersContentProvider后抛出错误。getMMSApns()APNHelper

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

显然您无法在 Android 4.2 中读取 APN

对于使用移动数据执行操作(如发送彩信)并且不知道设备中存在的默认 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);

但是,我咨询了我尝试向其发送彩信的人。他们说他们从未收到过彩信。

4

6 回答 6

15

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

在 Jelly Bean 中是:设置 > 数据使用 > 移动数据

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

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

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

于 2013-02-14T13:23:38.310 回答
7

没有官方的 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>
于 2013-01-23T18:17:42.903 回答
4

要在未经允许写入 apn 设置的情况下为 Android 4.0 api 14 或更高版本发送 mms,您可以使用此库:Retrieve mnc and mcc codes from android, then call

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.*;

于 2013-07-19T20:01:26.970 回答
3

我认为在 android 中发送彩信没有任何 sdk 支持。看这里至少我还没有找到。但是一个人声称拥有它。看看这个帖子。

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

于 2013-01-22T06:46:15.103 回答
-2

我不理解挫折。为什么不制作一个过滤此意图的广播接收器:

android.provider.Telephony.MMS_RECEIVED

我进一步检查了一下,您可能需要系统级别的访问权限才能获得这个(有根电话)。

于 2014-02-27T21:56:23.073 回答
-2

短信监听类

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>
于 2016-03-28T08:39:32.607 回答