前面我们介绍都只是如何发送SMS消息,接下来我们介绍如何接收SMS消息,及另一种发短信的方式并增强为可以发生图片等,最后介绍一下emulator工具。本文的主要内容如下:
此系列前面简单地接受过意图(Intent),这里再次简单介绍一下,在短信接收程序和使用Intent发送SMS中我们要用到。android应用程序的三大组件——Activities、Services、Broadcast Receiver,通过消息触发,这个消息就称作意图(Intent)。下面以Acitvity为例,介绍一下Intent。Android用Intent这个特殊的类实现在Activity与Activity之间的切换。Intent类用于描述应用的功能。在Intent的描述结构中,有两个最重要的部分:动作和动作对应的数据。典型的动作类型有MAIN、VIEW、PICK、EDIT等,我们在短信接收程序中就用到从广播意图中提取动作类型并判断是否是"android.provider.Telephony.SMS_RECEIVED",进而作深一步的处理。而动作对应的数据则以URI的形式表示。例如,要查看一个人的联系方式,需要创建一个动作为VIEW的Intent,以及表示这个人的URI。
通过解析各种Intent,从一个屏幕导航到另一个屏幕是很简单的。当向前导航时,Activity将会调用startActivity("指定一个Intent")方法。然后,系统会在所有已安装的应用程序中定义的IntentFilter中查找,找到最匹配的Intent对应的Activity。新的Activity接收到指定的Intent的通知后,开始运行。当startActivity()方法被调用时,将触发解析指定Intent的动作,该机制提供了两个关键的好处:
顾名思义,SmsMessage类是一个表示短信的类,为了更好地了解Android的短信机制及以后更好地编写短信相关程序,这里介绍一下该类的公有方法和常量,及嵌套枚举、类成员。
公有方法:
常量值:
嵌套枚举成员SmsMessage.MessageClass的枚举值:
嵌套枚举成员SmsMessage.MessageClass的公有方法:
嵌套类成员SmsMessage.SubmitPdu的字段:
嵌套类成员SmsMessage.SubmitPdu的公有方法:
当一个SMS消息被接收时,一个新的广播意图由android.provider.Telepony.SMS_RECEIVED动作触发。注意:这个一个字符串字面量(string literal),但是SDK当前并没有包括这个字符串的引用,因此当要在应用程序中使用它时必须自己显示的指定它。现在我们就开始构建一个SMS接收程序:
1)、跟SMS发送程序类似,要在清单文件AndroidManifest.xml中指定权限允许接收SMS:<uses-permission android:name="android.permission.RECEIVER_SMS"/>
为了能够回发短信,还应该加上发送的权限。
2)、应用程序监听SMS意图广播,SMS广播意图包含了到来的SMS细节。我们要从其中提取出SmsMessage对象,这样就要用到pdu键提取一个SMS PDUs数组(protocol description units—封装了一个SMS消息和它的元数据),每个元素表示一个SMS消息。为了将每个PDU byte数组转化为一个SMS消息对象,需要调用SmsMessage.createFromPdu。
每个SmsMessage包含SMS消息的详细信息,包括起始地址(电话号码)、时间戳、消息体。下面编写一个接收短信的类SmsReceiver代码如下:
SmsReceiver类的完整代码package skynet.com.conblogs.www; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.widget.Toast; public class SmsReceiver extends BroadcastReceiver { @Override public void onReceive(Context _context, Intent _intent) { if (_intent.getAction().equals(SMS_RECEIVER)) { SmsManager sms = SmsManager.getDefault(); Bundle bundle = _intent.getExtras(); if (bundle != null) { Object[] pdus = (Object[]) bundle.get("pdus"); SmsMessage[] messages = new SmsMessage[pdus.length]; for (int i = 0; ibyte []) pdus[i]); for (SmsMessage message : messages) { String msg = message.getMessageBody(); String to = message.getOriginatingAddress(); if (msg.toLowerCase().startsWith(queryString)) { String out = msg.substring(queryString.length()); sms.sendTextMessage(to, null, out, null, null); Toast.makeText(_context, "success", Toast.LENGTH_LONG).show(); } } } } } private static final String queryString="@echo"; private static final String SMS_RECEIVER= "android.provider.Telephony.SMS_RECEIVED"; }
上面代码的功能是从接收到的广播意图中提取来电号码、短信内容,然后将短信加上@echo头部回发给来电号码,并在屏幕上显示一个Toast消息提示成功。
上篇我们使用SmsManager类实现了发送SMS的功能,且并没有用到内置的客户端。实际上,我们很少这样做,自己在应用程序中去完全实现一个完整的SMS客户端。相反我们会去利用它,将需要发送的内容和目的手机号传递给内置的SMS客户端,然后发送。
下面我就向大家介绍如何利用Intent实现利用将我们的东西传递给内置SMS客户端发送我们SMS。为了实现这个功能,就要用到startActivity("指定一个Intent")方法,且指定Intent的动作为Intent.ACTION_SENDTO,用sms:指定目标手机号,用sms_body指定信息内容。java源文件如下所示:
java源文件完整代码package skynet.com.cnblogs.www; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class TextMessage extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btnSend = (Button) findViewById(R.id.btnSend); edtPhOneNo= (EditText) findViewById(R.id.edtPhoneNo); edtCOntent= (EditText) findViewById(R.id.edtContent); btnSend.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { String phOneNo= edtPhoneNo.getText().toString(); String message = edtContent.getText().toString(); if (phoneNo.length() > 0 && message.length() > 0) { Intent smsIntent=new Intent(Intent.ACTION_SENDTO, Uri.parse("sms:"+edtPhoneNo.getText().toString())); smsIntent.putExtra("sms_body", edtContent.getText().toString()); TextMessage.this.startActivity(smsIntent); } else Toast.makeText(getBaseContext(), "Please enter both phone number and message.", Toast.LENGTH_SHORT).show(); } }); } private Button btnSend; private EditText edtPhoneNo; private EditText edtContent; }
注意代码中的红色粗体部分,就是实现这个功能的核心代码!布局文件maim.xml和值文件string.xml跟上篇中的一样,这里不再累述。运行结果如下图:
图2、程序主界面
点击send按钮之后,转到内置的SMS客户端并且将我们输入的值传入了,如下图:
图3、内容传至内置SMS客户端
发送之后,5556号android模拟器会收到我们发送的消息,如下图:
图5、发送之后5556号android模拟器收到消息
我们讲了这么多,都还只是实现了简单的发生SMS的功能,如果我们想发送图片、音频怎么办(⊙o⊙)?不急,现在我们就将第9节介绍的SMS发送程序改造为MMS。
我们可以附加一个文件到我们的消息做为附件发送,用Intent.EXTRA_STREAM和附件资源的Uri做为参数调用putExtra()方法,附加到信息。并设置Intent的类型为mime-type。要注意的是:内置的MMS并不包括一个ACTION_SENDTO动作的Intent接收器,我们需要使用的动作类型是ACTION_SEND,并且目标手机号不在是使用sms:而是address。主要代码如下:
// Get the URI of a piece of media to attach.
Uri attached_Uri = Uri.parse("content://media/external/images/media/1");
// Create a new MMS intent
Intent mmsIntent = new Intent(Intent.ACTION_SEND, attached_Uri);
mmsIntent.putExtra("sms_body", edtContent.getText().toString());
mmsIntent.putExtra("address", edtPhoneNo.getText().toString());
mmsIntent.putExtra(Intent.EXTRA_STREAM, attached_Uri);
mmsIntent.setType("image/png");
startActivity(mmsIntent);
将这段代码替换第9节中的红色粗体代码,就完成而来一个MMS的构建。
PS:这篇文章本应该很早就该发出来了,在6月20号就写好了,但由于现在的工作环境完全隔离了Internet,家里又还没有开通网络;还有一个原因是现在工作比较忙!请大家见谅,能够继续支持我,让我有动力写下去。还有一点,这篇文章在我电脑上放久了,对当时的状态有些忘了,不知道文中有什么遗漏和错误,请大家指出!
本系列的其它文章: