收发短信应该是每个手机最基本的功能之一了,即使是许多年前的老手机也都会具备这项功能,而Android 作为出色的智能手机操作系统,自然也少不了在这方面的支持。每个Android 手机都会内置一个短信应用程序,使用它就可以轻松地完成收发短信的操作。
不过作为一名开发者,仅仅满足于此显然是不够的。你要知道,Android 还提供了一系列的API,使得我们甚至可以在自己的应用程序里接收和发送短信。也就是说,只要你有足够的信心,完全可以自己实现一个短信应用来替换掉Android 系统自带的短信应用。那么下面我们就来看一看,如何才能在自己的应用程序里接收和发送短信。
接收短信
其实接收短信主要是利用了我们学习过的广播机制。当手机接收到一条短信的时候,系统会发出一条值为android.provider.Telephony.SMS_RECEIVED 的广播,这条广播里携带着与短信相关的所有数据。每个应用程序都可以在广播接收器里对它进行监听,收到广播时再从中解析出短信的内容即可。
让我们通过一个具体的例子来实践一下吧,新建Module,首先修改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_tv_main"
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_tv_maiin"
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 的实例,如下:
private TextView sender_tv_main;
private TextView content_tv_maiin;
```
sender_tv_main = (TextView) findViewById(R.id.sender_tv_main);
content_tv_maiin = (TextView) findViewById(R.id.content_tv_maiin);
然后我们需要创建一个广播接收器来接收系统发出的短信广播。在MainActivity 中新建MessageReceiver 内部类继承自BroadcastReceiver,并在onReceive()方法中编写获取短信数据的逻辑,代码如下所示:
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_tv_main.setText(address);
content_tv_maiin.setText(fullMessage);
//abortBroadcast();
}
}
可以看到,首先我们从Intent 参数中取出了一个Bundle 对象,然后使用pdu 密钥来提取一个SMS pdus 数组,其中每一个pdu 都表示一条短信消息。接着使用SmsMessage 的createFromPdu()方法将每一个pdu 字节数组转换为SmsMessage 对象,调用这个对象的getOriginatingAddress()方法就可以获取到短信的发送方号码,调用getMessageBody()方法就可以获取到短信的内容,然后将每一个SmsMessage 对象中的短信内容拼接起来,就组成了一条完整的短信。最后将获取到的发送方号码和短信内容显示在TextView 上。完成了MessageReceiver 之后,我们还需要对它进行注册才能让它接收到短信广播,代码如下所示:
private IntentFilter receiveFilter;
private MessageReceiver messageReceiver;
```
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
```
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(messageReceiver);
}
<uses-permission android:name="android.permission.RECEIVE_SMS" />
完整源代码如下:
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView sender_tv_main;
private TextView content_tv_maiin;
private IntentFilter receiveFilter;
private MessageReceiver messageReceiver;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sender_tv_main = (TextView) findViewById(R.id.sender_tv_main);
content_tv_maiin = (TextView) findViewById(R.id.content_tv_maiin);
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
//1555 521 5554
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(messageReceiver);
}
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_tv_main.setText(address);
content_tv_maiin.setText(fullMessage);
//abortBroadcast();
}
}
}
还有个坑就是AS中怎么发短信?
Android studio中用了Genymotion模拟器,已经识别到了Device但是DDMS-Emulator Control是灰色的,模拟拨打电话和发送短信不可用(关键词检索)
碰到了这个坑,还以为是端口被占用的情况,但是已经发现设备了啊,已经启动了啊,检查端口没有发现任何问题:
这里附一个检测adb端口的方法:
1:netstat -aon|findstr "5037" 查看占用端口PID情况,5037是adb默认端口
2:tasklist|findstr "2720" 假如占用的PID是2020,那么此条查看的就是此PID对应的应用程序
如果不是adb,那么就到任务管理器中找到这个PID对应的程序,关闭,重启adb即可。
问题情况:
验证:本机AVD manager生成的Android模拟器就可以使用,so,原理就是别人的东西,你来我这里来不一定好使。
别费时间去纠结为啥不能用,他就是不能用。
另外用这个Genymotion生成的模拟器在制作的过程中不知道电话号码是哪个,所以在类似做拨号器应用的时候,无法验证此功能,可以这样:
在模拟器中查看:
设置-关于手机-状态消息-本机号码:我这里看到的是:15555215554,5554就是这个模拟器的号码,前边一大堆数字不用管,取后四位。