8.2    接收和发送短信

收发短信应该是每个手机最基本的功能之一了,即使是许多年前的老手机也都会具备这 项功能,而 Android 作为出色的智能手机操作系统,自然也少不了在这方面的支持。每个 Android 手机都会内置一个短信应用程序,使用它就可以轻松地完成收发短信的操作,如 图 8.4 所示。

图   8.4

不过作为一名开发者,仅仅满足于此显然是不够的。你要知道,Android 还提供了一系 列的 API,使得我们甚至可以在自己的应用程序里接收和发送短信。也就是说,只要你有足 够的信心,完全可以自己实现一个短信应用来替换掉 Android 系统自带的短信应用。那么下 面我们就来看一看,如何才能在自己的应用程序里接收和发送短信。

8.2.1    接收短信

其实接收短信主要是利用了我们在第 5 章学习过的广播机制。当手机接收到一条短信的 时候,系统会发出一条值为 android.provider.Telephony.SMS_RECEIVED 的广播,这条广播里 携带着与短信相关的所有数据。每个应用程序都可以在广播接收器里对它进行监听,收到广 播时再从中解析出短信的内容即可。

让我们通过一个具体的例子来实践一下吧,新建一个 SMSTest 项目,首先修改 activity_

main.xml 中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

android:orientation="vertical" >

<LinearLayout android:layout_width="match_parent"

android:layout_height="50dp" >

<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp" android:text="From:" />

<TextView
android:id="@+id/sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp" >

<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp" android:text="Content:" />

<TextView
android:id="@+id/content"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />

</LinearLayout>

</LinearLayout>

这个布局文件里,我们在根元素下面放置了两个 LinearLayout,用于显示两行数据。第 一个 LinearLayout 中有两个 TextView,用于显示短信的发送方。第二个 LinearLayout 中也有 两个 TextView,用于显示短信的内容。

接着修改 MainActivity 中的代码,在 onCreate()方法中获取到两个 TextView 的实例,如下所示:

public class MainActivity extends Activity {

private TextView sender;

private TextView content;

@Override

protected void onCreate(Bundle
savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

sender = (TextView) findViewById(R.id.sender);

content = (TextView) findViewById(R.id.content);

}

}

然后我们需要创建一个广播接收器来接收系统发出的短信广播。在 MainActivity 中新建 MessageReceiver 内部类继承自 BroadcastReceiver,并在 onReceive()方法中编写获取短信数 据的逻辑,代码如下所示:

public class MainActivity extends Activity {

……

class MessageReceiver extends BroadcastReceiver {

@Override

public void
onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras();

Object[] pdus = (Object[]) bundle.get("pdus"); // 提取短信消息

SmsMessage[] messages = new SmsMessage[pdus.length];

for (int i = 0; i < messages.length; i++) {

messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);

送方号码

}

String
address = messages[0].getOriginatingAddress(); //
获取发

String fullMessage = "";

for (SmsMessage message : messages) {

fullMessage
+= message.getMessageBody(); //
获取短信内容

} sender.setText(address);
content.setText(fullMessage);

}

}

}

可以看到,首先我们从 Intent 参数中取出了一个 Bundle 对象,然后使用 pdu 密钥来提取 一个 SMS pdus 数组,其中每一个 pdu 都表示一条短信消息。接着使用 SmsMessage
的 createFromPdu() 方法将每一个 pdu 字节数组转换为 SmsMessage 对象,调用这个对象的 getOriginatingAddress()方法就可以获取到短信的发送方号码,调用 getMessageBody()方法就 可以获取到短信的内容,然后将每一个 SmsMessage 对象中的短信内容拼接起来,就组成了 一条完整的短信。最后将获取到的发送方号码和短信内容显示在 TextView 上。

完成了 MessageReceiver 之后,我们还需要对它进行注册才能让它接收到短信广播,代 码如下所示:

public class MainActivity
extends Activity {

private TextView sender;

private TextView content;

private IntentFilter receiveFilter;

private MessageReceiver messageReceiver;

@Override

protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

sender = (TextView)
findViewById(R.id.sender); content = (TextView) findViewById(R.id.content);
receiveFilter = new IntentFilter();

receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");

messageReceiver = new MessageReceiver();

registerReceiver(messageReceiver, receiveFilter);

}

@Override

protected void onDestroy() {

super.onDestroy();

unregisterReceiver(messageReceiver);

}

……

}

这些代码你应该都已经非常熟悉了,使用的就是动态注册广播的技术。在 onCreate()方 法中对 MessageReceiver 进行注册,在 onDestroy()方法中再对它取消注册。

代码到这里就已经完成得差不多了,不过最后我们还需要给程序声明一个接收短信的权
限才行,修改 AndroidManifest.xml 中的代码,如下所示:

<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.smstest"

android:versionCode="1"
android:versionName="1.0" >

<uses-permission
android:name="android.permission.RECEIVE_SMS" />

……

</manifest>

现在可以来运行一下程序了,界面如图 8.5
所示。

图   8.5

当有短信到来时,短信的发送方和内容就会显示在界面上。不过话说回来,我们使用的是模拟器,模拟器上怎么可能会收得到短信呢?不用担心,DDMS 提供了非常充分的模拟环

境,使得我们不需要支付真正的短信费用也可以模拟收发短信的场景。将 Eclipse 切换到 DDMS 视图下,然后点击 Emulator Control 切换卡,在这里就可以向模拟器发送短信了,如
图 8.6 所示。

图   8.6

可以看到,我们指定发送方的号码是 556677,并填写了一段短信内容,然后点击 Send按钮,这样短信就发送成功了。接着我们立马查看一下 SMSTest 这个程序,结果如图 8.7 所示。

图   8.7

可以看到,短信的发送方号码和短信内容都显示到界面上了,说明接收短信的功能成功
实现了。

8.2.2    拦截短信

仔细观察图 8.7,你会发现在系统状态栏出现了一个通知图标,这个通知图标是由 Android 自带的短信程序产生的。也就是说当短信到来时,不仅我们的程序会接收到这条短信,系统 的短信程序同样也会收到。同样一条短信被重复接收两遍就会造成比较差的用户体验,那么
有没有什么办法可以屏蔽系统短信程序的接收功能呢?

在前面 5.3.2 节学习有序广播的时候我们就已经知道,有序广播的传递是可以截断的, 而系统发出的短信广播正是一条有序广播,因此这里我们的答案是肯定的。修改 MainActivity
中的代码,如下所示:

public class MainActivity extends Activity {

……

@Override

protected void onCreate(Bundle savedInstanceState) {

……

receiveFilter = new IntentFilter(); receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
receiveFilter.setPriority(100);

messageReceiver = new MessageReceiver();

registerReceiver(messageReceiver, receiveFilter);

}

……

class MessageReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

……

abortBroadcast();

}

}

}

可以看到,关键性的步骤只有两步。一是提高 MessageReceiver 的优先级,让它能够先 于系统短信程序接收到短信广播。二是在 onReceive()方法中调用 abortBroadcast()方法,中止掉广播的继续传递。

现在重新运行程序,再向模拟器发送一条短信,这时只有我们自己的程序才能收到这条
短信了。按下 Back 键将程序关闭后,系统的短信程序又会重新拥有接收短信的功能。

注意这个功能一定要慎用,随意拦截短信有可能会造成重要数据的丢失,所以你在拦截
之前一定要先想清楚这种功能是不是你想要的。

8.2.3    发送短信

下面我们继续对 SMSTest 项目进行扩展,给它加上发送短信的功能。那么还是先来编写
一下布局文件吧,修改 activity_main.xml 中的代码,如下所示:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"

android:orientation="vertical" >

……

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp" >

<TextView

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"

android:text="To:" />

<EditText
android:id="@+id/to" android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp" >

<EditText

android:id="@+id/msg_input"
android:layout_width="0dp"

android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />

<Button
android:id="@+id/send" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_gravity="center_vertical"
android:text="Send" />

</LinearLayout>

</LinearLayout>

这里我们又新增了两个 LinearLayout,分别处于第三和第四行的位置。第三行中放置了 一个 EditText,用于输入接收方的手机号码。第四行中放置了一个 EditText 和一个 Button, 分别用于输入短信内容和发送短信。

然后修改 MainActivity 中的代码,在里面加入发送短信的处理逻辑,代码如下所示:

public class MainActivity extends Activity {

……

private EditText to; private EditText
msgInput; private Button send;

@Override

protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

……

to = (EditText) findViewById(R.id.to);

msgInput = (EditText)
findViewById(R.id.msg_input); send = (Button) findViewById(R.id.send);
send.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

SmsManager smsManager = SmsManager.getDefault();

smsManager.sendTextMessage(to.getText().toString(), null,

}

});

}

……

}

msgInput.getText().toString(), null, null);

可以看到,首先我们获取到了布局文件中新增控件的实例,然后在 Send 按钮的点击事 件里面处理了发送短信的具体逻辑。当 Send 按钮被点击时,会先调用 SmsManager 的 getDefault()方法获取到 SmsManager 的实例,然后再调用它的 sendTextMessage()方法就可以 去发送短信了。sendTextMessage()方法接收五个参数,其中第一个参数用于指定接收人的手
机号码,第三个参数用于指定短信的内容,其他的几个参数我们暂时用不到,直接传入 null 就可以了。

接下来也许你已经猜到了,发送短信也是需要声明权限的,因此修改 AndroidManifest.xml中的代码,如下所示:

<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.smstest"

android:versionCode="1"

android:versionName="1.0" >

<uses-permission android:name="android.permission.RECEIVE_SMS"
/>

<uses-permission android:name="android.permission.
SEND_SMS" />

……

</manifest>

现在重新运行程序之后,SMSTest 就拥有了发送短信的能力。不过点击 Send 按钮虽然 可以将短信发送出去,但是我们并不知道到底发送成功了没有,这个时候就可以利用 sendTextMessage()方法的第四个参数来对短信的发送状态进行监控。修改 MainActivity 中的 代码,如下所示:

public class MainActivity extends Activity {

……

private IntentFilter sendFilter;

private SendStatusReceiver sendStatusReceiver;

@Override

protected void
onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

……

sendFilter = new IntentFilter();
sendFilter.addAction("SENT_SMS_ACTION"); sendStatusReceiver = new
SendStatusReceiver(); registerReceiver(sendStatusReceiver, sendFilter);
send.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

SmsManager smsManager =
SmsManager.getDefault(); Intent sentIntent = new
Intent("SENT_SMS_ACTION"); PendingIntent pi =
PendingIntent.getBroadcast

(MainActivity.this, 0, sentIntent, 0);

smsManager.sendTextMessage(to.getText().toString(),
null, msgInput.getText().toString(), pi, null);

}

});

}

@Override

protected void onDestroy()
{ super.onDestroy(); unregisterReceiver(messageReceiver);

unregisterReceiver(sendStatusReceiver);

}

……

class SendStatusReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

if (getResultCode() == RESULT_OK) {

// 短信发送成功

Toast.makeText(context,
"Send succeeded", Toast.LENGTH_LONG).show();

} else {

// 短信发送失败

Toast.makeText(context,
"Send failed", Toast.LENGTH_LONG).show();

}

}

}

}

可以看到,在 Send 按钮的点击事件里面我们调用了 PendingIntent 的 getBroadcast()方法 获取到了一个 PendingIntent 对象,并将它作为第四个参数传递到 sendTextMessage()方法中。 然后又注册了一个新的广播接收器 SendStatusReceiver,这个广播接收器就是专门用于监听 短信发送状态的,当 getResultCode()的值等于 RESULT_OK 就会提示发送成功,否则提示发
送失败。

现在重新运行一下程序,在文本输入框里输入接收方的手机号码以及短信内容,然后点 击 Send 按钮,结果如图 8.8 所示。

图   8.8

注意,这里虽然提示发送成功了,但实际上使用模拟器来发送短信对方是不可能收得到
的,只有把这个项目运行在手机上,才能真正地实现发送短信的功能。

另外,根据国际标准,每条短信的长度不得超过 160 个字符,如果想要发送超出这个长 度的短信,则需要将这条短信分割成多条短信来发送,使用 SmsManager 的 sendMultipart-
TextMessage()方法就可以实现上述功能。它的用法和 sendTextMessage()方法也基本类似,感 兴趣的话你可以自己研究一下,这里就不再展开讲解了。

android: 接收和发送短信的更多相关文章

  1. android 几种发送短信的方法

    android中发送短信很简单, 首先要在Mainfest.xml中加入所需要的权限: ? 1 2 3 <uses-permission android:name="android.p ...

  2. Android开发之发送短信

    本实例通过SmsManager的sendTextMessage方法实现发送短信关于SmsManager的具体解释大家能够參照:Android开发之SmsManager具体解释 实例执行效果图: 程序代 ...

  3. Android 中发送短信

    import android.net.Uri; //调用Android系统API发送短信 Uri uri = Uri.parse("smsto:" + strSmsPhone_va ...

  4. Android之发送短信和接收验证码

      最近项目需求需要发送短信和接收验证码并将验证码显示在输入框中 以下是我的记录    前提---权限     <uses-permission android:name="andro ...

  5. android 发送短信的两种方式,以及接收报告和发送报告

               android发送短信,以及接收报告和发送报告          android中发送短信其实有两种方式,这个和打电话类似,大家可以了解一下:    一.调起系统发短信功能    ...

  6. android 中调用接口发送短信

    android中可以通过两种方式发送短信 第一:调用系统短信接口直接发送短信:主要代码如下: //直接调用短信接口发短信 SmsManager smsManager = SmsManager.getD ...

  7. 无废话Android之activity的生命周期、activity的启动模式、activity横竖屏切换的生命周期、开启新的activity获取他的返回值、利用广播实现ip拨号、短信接收广播、短信监听器(6)

    1.activity的生命周期 这七个方法定义了Activity的完整生命周期.实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环: (1)Activity的完整生命周期 自第一次调用onCrea ...

  8. Android SmsManager 发送短信

    SmsManager可以在后台发送短信,无需用户操作,开发者就用这个SmsManager功能在后台偷偷给SP发短信,导致用户话费被扣.必须添加android.permission.SEND_SMS权限 ...

  9. Android软件开发之发送短信与系统短信库解析

    今天我和同学们讨论一下Android平台下如何调用系统方法发送短信.接收短信.系统的短信库相关的问题.进入正题,我们先使用Eclipse工具模拟给自己的模拟器发送一条短信.在Eclipse下打开DDM ...

随机推荐

  1. [转] Oracle analyze 命令分析

    转自:http://blog.sina.com.cn/s/blog_682841ba0101bncp.html 1.analyze table t1 compute statistics for ta ...

  2. jQuery阻止默认行为和阻止冒泡

    1.阻止默认行为:通常是值一个标签的默认行为,如button的提交表单,a标签的跳转等. 那如何阻止标签的默认行为? 1)return false 2) e.preventDefault(); < ...

  3. 钩子机制(hook)

    钩子是编程惯用的一种手法,用来解决一种或多种特殊情况的处理. 简单来说,钩子就是适配器原理,或者说是表驱动原理,我们预先定义了一些钩子,在正常的代码逻辑中使用钩子去适配一些特殊的属性,样式或事件,这样 ...

  4. .net WebApi中使用swagger

    我在WebApi中使用swagger的时候发现会出现很多问题,搜索很多地方都没找到完全解决问题的方法,后面自己解决了,希望对于遇到同样问题朋友有帮助.我将先一步一步的演示项目中解决swagger遇到问 ...

  5. 近期oepnfire工作总结.

    1.优化订阅好友流程,增加验证消息2.优化好友查询模块,实现对扩展字段的查询.如批量匹配通讯录.3.实现webservice接口方式消息推送功能,供其他系统调用.4.实现花名册版本(XEP-237), ...

  6. GATK-BWA-MEM handle GRCh38 alternate contig mappings

    1. For the Impatient # Download bwakit (or from <http://sourceforge.net/projects/bio-bwa/files/bw ...

  7. C# 读写excel 用于导入数据库 批量导入导出excel

    给大家介绍一款控件,Aspose.Cells.dll,相当强大,几乎就是excel,支持excel2003,excel2007等格式文件.excel2010以上,没有经过测试,估计也是可以. Aspo ...

  8. Git平台使用时的配置分析

    Git仓库的配制文件分为三个部分: 1. .git/config:指定仓库配置(特定于某个仓库),获取或设置时使用--file参数(或者省去). 2. ~/.gitconfig:用户级别仓库配置(适用 ...

  9. 理解RHEL上安装oracle的配置参数

    无论安装什么版本的oracle,在安装之前,都需要配置 /etc/pam.d/login   /etc/profile   /etc/security/limits.conf这三个文件 那这三个文件究 ...

  10. ElasticSearch学习笔记-01 简介、安装、配置与核心概念

    一.简介 ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎.设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便.支持通过HTTP使用JSON进 ...