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