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

too*_*o42 131 sms android mms broadcastreceiver android-manifest

我已经弄明白了如何发送和接收短信.要发送短信,我必须调用该类的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 ...
}
Run Code Online (Sandbox Code Playgroud)

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...
    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

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

此外,我知道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>
Run Code Online (Sandbox Code Playgroud)

在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...
    }
}
Run Code Online (Sandbox Code Playgroud)

根据android.provider.Telephony文档:

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

pdus- 包含组成消息的PDU Object[]byte[]s中的一个.

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

 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
 public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
Run Code Online (Sandbox Code Playgroud)

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

pdus- 包含组成消息的PDU Object[]byte[]s中的一个.

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

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
Run Code Online (Sandbox Code Playgroud)

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

transactionId (Integer) - WAP交易ID

pduType (Integer) - WAP PDU类型`

header (byte[]) - 邮件的标题

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

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

如果BroadcastReceiver在处理此意图时遇到错误,则应该适当地设置结果代码.contentTypeParameters额外值是按名称键入的内容参数的映射.如果遇到任何未分配的已知参数,则映射的键将为"unassigned/0x ...",其中"..."是未分配参数的十六进制值.如果参数具有无值,则映射中的值将为null.

@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
Run Code Online (Sandbox Code Playgroud)

更新#2

我已经想出如何传递一个附加组件PendingIntent来接收一个BroadcastReceiver: Android PendingIntent附加组件,而不是BroadcastReceiver收到的

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

更新#3

接收彩信

所以经过更多的研究,我看到了一些注册的建议ContentObserver.这样,您可以检测content://mms-sms/conversations内容提供程序何时发生更改,从而允许您检测传入的MMS.以下是我发现的最接近的示例:接收彩信

但是,有一个mainActivity类型的变量ServiceController.ServiceController课程在哪里实施?是否有其他注册实现ContentObserver

发送彩信

至于发送彩信,我遇到过这个例子:发送彩信

问题是我尝试在我的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.
Run Code Online (Sandbox Code Playgroud)

在类CarriersgetMMSApns()方法中查询ContentProvider 后抛出错误APNHelper.

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

显然你无法在Android 4.2中阅读APN

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

但是,我检查过我尝试发送彩信的人.他们说他们从未收到彩信.

Man*_*rma 15

我有上面描述的完全相同的问题(T-mobile USA上的Galaxy Nexus),因为移动数据已关闭.

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

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

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

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


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

}
Run Code Online (Sandbox Code Playgroud)

我还没有完全弄清楚如何跟踪邮件的传递,但这应该发送.

您可以通过与短信相同的方式收到mms的提醒.接收器上的intent过滤器应如下所示.

<intent-filter>
    <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
    <data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)


Sah*_* Mj 3

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

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