1、第一章 短信安全短信发送和拦截2学习目标v了解在了解在Android中如何实现短信发中如何实现短信发送与接收功能送与接收功能v短信拦截作用及其必要性短信拦截作用及其必要性v通过运行两个通过运行两个Android模拟器,介模拟器,介绍在绍在Android中如何实现短信服务中如何实现短信服务(SMS,short message service)的功能。的功能。v短信 short message service,简称SMS 是用户通过手机或其他电信终端直接发送或接收的文字或数字信息,用户每次能接收和发送短信的字符数,是160个英文或数字字符,或者70个中文字符。android 短信流程分析v系统的短
2、信库存在系统的短信库存在data/data/com.android.providers.telephony/databases/mmssms.db1 SMS发送APIvAndroid 使用SmsManager发送短信vpublic void sendTextMessage(String destinationAddress,String scAddress,String text,PendingIntent sentIntent,PendingIntent deliveryIntent)destinationAddress:收件人地址scAddress:短信中心号码,空为默认中心号码sentI
3、ntent:当消息发出时,成功或者失败的信息报告通过PendingIntent来广播。如果该参数为空,则发信程序会被所有位置程序检查一遍,这样会导致发送时间延长。deliveryIntent:当消息发送到收件人时,该PendingIntent会被广播。pdu数据在状态报告的extended data(“pdu”)中。抛出 IllegalArgumentException 如果收件人或者信息为空。1 SMS发送APIvpublic static PendingIntent getBroadcast(Context context,int requestCode,Intent intent,int
4、 flags)返回一个用于广播的PendingIntent,类似于调用Context.sendBroadcast()函数,requestCode 暂时不用intent 是用于广播的intentflags 有:FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,FLAG_UPDATE_CURRENT 用于设置新建的PendingIntent是使用一次、如无则不创建、取消当前、更新当前等属性。vvoid sendMultipartTextMessage(String destinationAddress,String scAddress,ArrayLi
5、st parts,ArrayList sentIntents,ArrayList deliverIntents)发送一个基于SMS的多部分文本,调用者应用已经通过调用divideMessage(String text)将消息分割成正确的大小。2 SMS发送程序分析v讲解例子SendDemov第一步:设计界面2 SMS发送程序分析第一步:设计界面v编辑布局文件res/layout/main.xmlv在res/values/strings.xm中添加上面定义的视图的text的值2 SMS发送程序分析第二步:编写代码实现简单的短信发送 在java源文件中,获取用户在edtPhoneNo中输入的电话号
6、码,edtContent中输入要发送的内容;然后点击btnSend按钮发送短信,要达到这个目的我们要设置btnSend的OnClickListener以达到当点击它触发发送短信的功能,而且要发送短信就要用到我们前面介绍的SmsManager类提供的方法接口。vbtnSend的OnClickListener的代码v发送短信的功能的代码sendSMS2 SMS发送程序分析第三步:在清单文件AndroidManifest.xml中加入允许发送短信的权限课堂练习1v增强发送短信功能,使其能够发送超长短信以及查看短信是否成功被接收v解决办法:为了跟踪发出的短信的状态,需要修改sendTextMessag
7、e方法中的第4个和第5个参数,即sentIntent和deliveryIntent。第4个参数-sendIntent,当消息成功发送或发送失败都将被触发。广播接收者的结果码,Activity.RESULT_OK表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU之一表示错误。对应RESULT_ERROR_GENERIC_FAILURE,sentIntent可能包括额外的“错误代码”包含一个无线电广播技术特定的值,通常只在修复故障时有用。第5个参数-deliveryIntent,仅当目标接收
8、到你的SMS消息才触发。3 SMS拦截APIv演示一个小例子:通过DDMS给SendDemo虚拟机发送一条短信v广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,这个特性跟JMS中的Topic消息接收者类似。3 SMS拦截APIvBroadcastReceiver是android中用处巨大的异步消息机制。一个BroadcastReceiver对象的生
9、命周期不超过5秒,不能绑定服务和做一些耗时的操作,但是用来接收信息则戳戳有余。vpublic void onReceive(Context context,Intent intent)3 SMS拦截APIv广播接收者的响应 在Android中,每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive()方法,onReceive()方法执行完后,BroadcastReceiver 的实例就会被销毁。当onReceive()方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否则会弹出AN
10、R(Application No Response)的对话框。如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。3 SMS拦截API 这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时BroadcastReceiver的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。3 SMS拦截
11、APIpublic class IncomingSMSReceiver extends BroadcastReceiver Override public void onReceive(Context context,Intent intent)/发送Intent启动服务,由服务来完成比较耗时的操作 Intent service=new Intent(context,XxxService.class);context.startService(service);3 SMS拦截APIv广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered bro
12、adcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播;然而有序广播是按照接收者声明的优先级别,被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C。3 SMS拦截APIv优先级别声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置。有序广播的接收者可以终
13、止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。另外,有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。3 SMS拦截APIvContext.sendBroadcast(),发送的是普通广播,所有订阅者都有机会获得并进行处理。vContext.sendOrderedBroadcast(),发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播vBroadcastReceiver.abortBroadcast()中断广
14、播的继续传递,实现拦截短信的功能。3 SMS拦截APIv如果发出的广播属于有序广播。如果不想让比他优先级低的人收到这个信息,那就在onReceiver()方法的最后加上这个abortBroadcast(),这样就中断了广播的继续传递v如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将数据通过setResultExtras(Bundle)方法存放进结果对象,然后传给下一个接收者,下一个接收者通过代码:Bundle bundle=getResultExtras(true)可以获取上一个接收者存入在结果对象中的数据。4 SMS拦截例子分析例子:使用广播接收
15、者例子:使用广播接收者监听监听短信短信v本程序设计了一个可以接收短信的程序,将捕捉到的短信广播信息,拆解为可阅读的消息正文,而后以Toast的方式输出至手机。v当系统收到短信时,会发出一个广播Intent,Intent的action名称为android.provider.Telephony.SMS_RECEIVED,该Intent存放了系统接收到的短信内容,我们使用名称“pdus”即可从Intent中获取到短信内容。4 SMS拦截例子分析要实现一个广播接收者方法如下:v第一步:继承BroadcastReceiver,并重写onReceive()方法public class IncomingSM
16、SReceiver extends BroadcastReceiver Override public void onReceive(Context context,Intent intent)第二步:订阅感兴趣的广播Intent,订阅方法有两种:第一种动态注册:使用代码进行订阅IntentFilter filter=new IntentFilter(android.provider.Telephony.SMS_RECEIVED);IncomingSMSReceiver receiver=new IncomingSMSReceiver();registerReceiver(receiver,f
17、ilter);第二种静态注册:在AndroidManifest.xml文件中的节点里进行订阅:v代码动态注册的Intent-Filter高于manifest静态注册的Intent-Filter。动态注册中的Intent-Filter在相同优先级下(如整型的最大值),接受顺序是按照动态注册的时间顺序。静态注册中Intent-Filter在相同优先级下,接受顺序是apk的安装顺序。v使用BroadReceiver的弊端查看BroadReceiver sdk reference,可以了解到所有的BroadReceiver对短信的接收是无顺序的状态,即使是使用了Ordered broadcasts对于
18、同等优先级别的BroadReceiver,也会产生无顺序的行为。所以下面介绍另一种接收短信的行为,包括其中可以进行短信的删除。v应用观察者模式,监听短信数据库,操作短信内容应用观察者模式,监听短信数据库,操作短信内容课堂作业2v改成动态注册然后观察是否能监听到短信信息?Android DDMSvDDMS 的全称是Dalvik Debug Monitor Service,它为我们提供例如:为测试设备截屏,针对特定的进程查看正在运行的线程以及堆信息、Logcat、广播状态信息、模拟电话呼叫、接收SMS、虚拟地理坐标等等。综合课堂练习v做一个既能接收又能拦截的例子v(1)发送短信按钮能够发送短信v(2)拦截短信按钮实现短信拦截,即中断了广播的继续传递,低优先级的程序无法接收短信,v(3)取消拦截按钮则取消拦截,使模拟机能够接受到短信息