Android学习笔记(二十二)——短信接收与发送
//此系列博文是《第一行Android代码》的学习笔记,如有错漏,欢迎指正!
当手机接收到一条短信的时候, 系统会发出一条值为 android.provider.Telephony.SMS_RECEIVED 的广播, 这条广播里携带着与短信相关的所有数据。每个应用程序都可以在广播接收器里对它进行监听,收到广播时再从中解析出短信的内容即可。下面让我们一起来实践一下吧。
一、新建项目,构建布局文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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上。
三、添加主活动逻辑:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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" />
我们想要程序接收到系统短信是需要取得系统权限的。
最后程序的运行效果如图:
既然已经能够接收短信了,我们顺便天添加发送短信的功能。
五、修改布局文件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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>
我们又新增了两个 LinearLayout,分别用于手机号码和内容。
六、修改主活动代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
我们先获取到了布局文件中新增控件的实例,然后在 Send 按钮的点击事件里面处理了发送短信的具体逻辑。当 Send 按钮被点击时,会先调用 SmsManager 的getDefault()方法获取到 SmsManager的实例,然后再调用它的 sendTextMessage()方法就可以去发送短信了。sendTextMessage()方法接收五个参数,其中第一个参数用于指定接收人的手机号码,第三个参数用于指定短信的内容,其他的几个参数我们暂时用不到,直接传入 null就可以了。
七、修改权限:
<uses-permission android:name="android.permission.SEND_SMS" />
在manifest文件中加入上述发送短信的权限声明就大功告成了。
//End.