当手机接收到一条短信的时候, 系统会发出一条值为 android.provider.Telephony.SMS_RECEIVED 的广播, 这条广播里携带着与短信相关的所有数据。每个应用程序都可以在广播接收器里对它进行监听,收到广播时再从中解析出短信的内容即可。下面让我们一起来实践一下吧。
一、新建项目,构建布局文件:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 android:layout_width="match_parent"
3 android:layout_height="match_parent"
4 android:orientation="vertical" >
5 <LinearLayout
6 android:layout_width="match_parent"
7 android:layout_height="50dp" >
8 <TextView
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content"
11 android:layout_gravity="center_vertical"
12 android:padding="10dp"
13 android:text="From:" />
14 <TextView
15 android:id="@+id/sender"
16 android:layout_width="wrap_content"
17 android:layout_height="wrap_content"
18 android:layout_gravity="center_vertical" />
19 </LinearLayout>
20 <LinearLayout
21 android:layout_width="match_parent"
22 android:layout_height="50dp" >
23 <TextView
24 android:layout_width="wrap_content"
25 android:layout_height="wrap_content"
26 android:layout_gravity="center_vertical"
27 android:padding="10dp"
28 android:text="Content:" />
29 <TextView
30 android:id="@+id/content"
31 android:layout_width="wrap_content"
32 android:layout_height="wrap_content"
33 android:layout_gravity="center_vertical" />
34 </LinearLayout>
35 </LinearLayout>
在布局文件中,我们添加了两个 LinearLayout,用于显示两行数据。分别用于显示短信的发送方和短信的内容。
二、构建内部类MessageReceiver:
1 class MessageReceiver extends BroadcastReceiver {
2 @Override
3 public void onReceive(Context context, Intent intent) {
4 Bundle bundle = intent.getExtras();
5 Object[] pdus = (Object[]) bundle.get("pdus"); // 提取短信消息
6 SmsMessage[] messages = new SmsMessage[pdus.length];
7 for (int i = 0; i < messages.length; i++) {
8 messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
9 }
10 String address = messages[0].getOriginatingAddress(); // 获取发送方号码
11 String fullMessage = "";
12 for (SmsMessage message : messages) {
13 fullMessage += message.getMessageBody(); // 获 取短信内容
14 }
15 sender.setText(address);
16 content.setText(fullMessage);
17 }
18 }
在 MainActivity中新建内部类MessageReceiver并使其继承于BroadcastReceiver类,我们从 Intent参数中取出了一个 Bundle 对象, 然后使用 pdu密钥来提取一个 SMS pdus 数组,其中每一个 pdu 都表示一条短信消息。接着使用 SmsMessage 的createFromPdu()方法将每一个 pdu 字节数组转换为 SmsMessage 对象,调用这个对象的getOriginatingAddress()方法就可以获取到短信的发送方号码,调用 getMessageBody()方法就可以获取到短信的内容,然后将每一个 SmsMessage 对象中的短信内容拼接起来,就组成了一条完整的短信。最后将获取到的发送方号码和短信内容显示在TextView上。
三、添加主活动逻辑:
1 public class MainActivity extends AppCompatActivity {
2
3 private TextView sender;
4 private TextView content;
5 private IntentFilter receiveFilter;
6 private MessageReceiver messageReceiver;
7 @Override
8 protected void onCreate(Bundle savedInstanceState) {
9 super.onCreate(savedInstanceState);
10 setContentView(R.layout.activity_main);
11 sender = (TextView) findViewById(R.id.sender);
12 content = (TextView) findViewById(R.id.content);
13 receiveFilter = new IntentFilter();
14 receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
15 messageReceiver = new MessageReceiver();
16 registerReceiver(messageReceiver, receiveFilter);
17 }
18
19
20 @Override
21 protected void onDestroy() {
22 super.onDestroy();
23 unregisterReceiver(messageReceiver);
24 }
25 class MessageReceiver extends BroadcastReceiver {
26 @Override
27 public void onReceive(Context context, Intent intent) {
28 Bundle bundle = intent.getExtras();
29 Object[] pdus = (Object[]) bundle.get("pdus"); // 提取短信消息
30 SmsMessage[] messages = new SmsMessage[pdus.length];
31 for (int i = 0; i < messages.length; i++) {
32 messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
33 }
34 String address = messages[0].getOriginatingAddress(); // 获取发送方号码
35 String fullMessage = "";
36 for (SmsMessage message : messages) {
37 fullMessage += message.getMessageBody(); // 获 取短信内容
38 }
39 sender.setText(address);
40 content.setText(fullMessage);
41 }
42 }
43
44 }
主活动中运用了动态注册广播的技术。在 onCreate()方法中我们先对 MessageReceiver 进行注册,然后在 onDestroy()方法中再对它取消注册。
四、权限的声明:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
我们想要程序接收到系统短信是需要取得系统权限的。
最后程序的运行效果如图:
既然已经能够接收短信了,我们顺便天添加发送短信的功能。
五、修改布局文件:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 android:layout_width="match_parent"
3 android:layout_height="match_parent"
4 android:orientation="vertical" >
5 <LinearLayout
6 android:layout_width="match_parent"
7 android:layout_height="50dp" >
8 <TextView
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content"
11 android:layout_gravity="center_vertical"
12 android:padding="10dp"
13 android:text="From:" />
14 <TextView
15 android:id="@+id/sender"
16 android:layout_width="wrap_content"
17 android:layout_height="wrap_content"
18 android:layout_gravity="center_vertical" />
19 </LinearLayout>
20 <LinearLayout
21 android:layout_width="match_parent"
22 android:layout_height="50dp" >
23 <TextView
24 android:layout_width="wrap_content"
25 android:layout_height="wrap_content"
26 android:layout_gravity="center_vertical"
27 android:padding="10dp"
28 android:text="Content:" />
29 <TextView
30 android:id="@+id/content"
31 android:layout_width="wrap_content"
32 android:layout_height="wrap_content"
33 android:layout_gravity="center_vertical" />
34 </LinearLayout>
35 <LinearLayout
36 android:layout_width="match_parent"
37 android:layout_height="50dp" >
38 <TextView
39 android:layout_width="wrap_content"
40 android:layout_height="wrap_content"
41 android:layout_gravity="center_vertical"
42 android:padding="10dp"
43 android:text="To:" />
44 <EditText
45 android:id="@+id/to"
46 android:layout_width="0dp"
47 android:layout_height="wrap_content"
48 android:layout_gravity="center_vertical"
49 android:layout_weight="1" />
50 </LinearLayout>
51
52 <LinearLayout
53 android:layout_width="match_parent"
54 android:layout_height="50dp" >
55 <EditText
56 android:id="@+id/msg_input"
57 android:layout_width="0dp"
58 android:layout_height="wrap_content"
59 android:layout_gravity="center_vertical"
60 android:layout_weight="1" />
61 <Button
62 android:id="@+id/send"
63 android:layout_width="wrap_content"
64 android:layout_height="wrap_content"
65 android:layout_gravity="center_vertical"
66 android:text="Send" />
67 </LinearLayout>
68 </LinearLayout>
View Code
我们又新增了两个 LinearLayout,分别用于手机号码和内容。
六、修改主活动代码:
1 package com.mycompany.notificationtest;
2
3 import android.app.Notification;
4 import android.app.NotificationManager;
5 import android.app.PendingIntent;
6 import android.content.BroadcastReceiver;
7 import android.content.Context;
8 import android.content.Intent;
9 import android.content.IntentFilter;
10 import android.support.v7.app.AppCompatActivity;
11 import android.os.Bundle;
12 import android.telephony.SmsManager;
13 import android.telephony.SmsMessage;
14 import android.view.View;
15 import android.widget.Button;
16 import android.widget.EditText;
17 import android.widget.TextView;
18 import android.widget.Toast;
19
20 public class MainActivity extends AppCompatActivity {
21
22 private TextView sender;
23 private TextView content;
24 private IntentFilter receiveFilter;
25 private MessageReceiver messageReceiver;
26 private EditText to;
27 private EditText msgInput;
28 private Button send;
29 private IntentFilter sendFilter;
30 private SendStatusReceiver sendStatusReceiver;
31
32 @Override
33 protected void onCreate(Bundle savedInstanceState) {
34 super.onCreate(savedInstanceState);
35 setContentView(R.layout.activity_main);
36 sender = (TextView) findViewById(R.id.sender);
37 content = (TextView) findViewById(R.id.content);
38 receiveFilter = new IntentFilter();
39 receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
40 messageReceiver = new MessageReceiver();
41 registerReceiver(messageReceiver, receiveFilter);
42
43 to = (EditText)findViewById(R.id.to);
44 msgInput = (EditText)findViewById(R.id.msg_input);
45 send = (Button)findViewById(R.id.send);
46 send.setOnClickListener(new View.OnClickListener() {
47 @Override
48 public void onClick(View v) {
49 SmsManager smsManager = SmsManager.getDefault();
50 Intent sentIntent = new Intent("SENT_SMS_ACTION");
51 PendingIntent pi = PendingIntent.getBroadcast
52 (MainActivity.this, 0, sentIntent, 0);
53 smsManager.sendTextMessage(to.getText().toString(), null,
54 msgInput.getText().toString(), pi, null);
55
56 }
57 });
58
59 sendFilter = new IntentFilter();
60 sendFilter.addAction("SENT_SMS_ACTION");
61 sendStatusReceiver = new SendStatusReceiver();
62 registerReceiver(sendStatusReceiver, sendFilter);
63 }
64
65
66 @Override
67 protected void onDestroy() {
68 super.onDestroy();
69 unregisterReceiver(messageReceiver);
70 unregisterReceiver(sendStatusReceiver);
71 }
72 class MessageReceiver extends BroadcastReceiver {
73 @Override
74 public void onReceive(Context context, Intent intent) {
75 Bundle bundle = intent.getExtras();
76 Object[] pdus = (Object[]) bundle.get("pdus"); // 提取短信消息
77 SmsMessage[] messages = new SmsMessage[pdus.length];
78 for (int i = 0; i < messages.length; i++) {
79 messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
80 }
81 String address = messages[0].getOriginatingAddress(); // 获取发送方号码
82 String fullMessage = "";
83 for (SmsMessage message : messages) {
84 fullMessage += message.getMessageBody(); // 获 取短信内容
85 }
86 sender.setText(address);
87 content.setText(fullMessage);
88 }
89 }
90
91
92 class SendStatusReceiver extends BroadcastReceiver {
93 @Override
94 public void onReceive(Context context, Intent intent) {
95 if (getResultCode() == RESULT_OK) {
96 // 短信发送成功
97 Toast.makeText(context, "Send succeeded", Toast.LENGTH_LONG).show();
98 } else {
99 // 短信发送失败
100 Toast.makeText(context, "Send failed", Toast.LENGTH_LONG).show();
101 }
102 }
103
104 }
105 }
View Code
我们先获取到了布局文件中新增控件的实例,然后在 Send 按钮的点击事件里面处理了发送短信的具体逻辑。当 Send 按钮被点击时,会先调用 SmsManager 的getDefault()方法获取到 SmsManager的实例,然后再调用它的 sendTextMessage()方法就可以去发送短信了。sendTextMessage()方法接收五个参数,其中第一个参数用于指定接收人的手机号码,第三个参数用于指定短信的内容,其他的几个参数我们暂时用不到,直接传入 null就可以了。
七、修改权限:
<uses-permission android:name="android.permission.SEND_SMS" />
在manifest文件中加入上述发送短信的权限声明就大功告成了。