安卓开发之广播接收器

恶意软件检测中常常会看到应用的广播接收器在接收到屏幕锁定的广播后再进行一些恶意操作,这里广播(Broadcast)就指的是一种应用程序之间传输信息的机制,广播接收器(BroadcastReceiver)则是对前者的响应。广播也类似于计算机网络中的广播地址,同一局域网下的所有主机都会收到广播数据包。
安卓的BroadcastReceiver主要分为两种标准广播和有序广播。

标准广播

普通广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之、间没有先后顺序。这种广播效率较高,且无法被截断。

在这里插入图片描述
首先看怎么注册系统广播,有两种方式:动态注册与静态注册。两种方式的主要区别在于动态注册的广播接收器必须在程序启动之后才能接收到广播,而静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机发出的广播只能用静态注册。另一个区别就是动态注册在代码中完成,而静态注册在AndroidManifest.xml文件里注册。

先看动态注册,动态注册是在代码中注册:

  • 1)首先自定义广播接收器类继承BroadcastReceiver,然后重写onReceive()方法,作为接收到广播之后的操作。在讲Service的时候也提到:BroadcastReceiver生命周期只有十秒左右,因此在onReceive()也不能做一些耗时操作防止ARN,所以通用的做法应该是发送给service,由service开启子线程来完成。onReceive中也不能开启子线程来做耗时操作。
  • 2)通过registerReceiver动态注册广播接收器,接收两个参数,分别是(BroadcastReceiver实例,IntentFilter实例)。
    IntentFilter实例的addAction方法用来表明广播接收器监听的时什么广播。C

在这里插入图片描述
然后声明访问系统的网络状态权限:
在这里插入图片描述
这样当系统网络状态发生改变之时,OnReceive方法就会被执行,效果如下:
关闭网络后:
在这里插入图片描述
开启网络后:
在这里插入图片描述
Kotlin:

class MainActivity : AppCompatActivity() {
    lateinit var timeChangeReceiver:TimeworkChangeReceiver
    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeChangeReceiver)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val intentFilter = IntentFilter()
        intentFilter.addAction("android.intent.action.TIME_TICK")
        timeChangeReceiver = TimeworkChangeReceiver()
        registerReceiver(timeChangeReceiver,intentFilter)
    }
    inner class TimeworkChangeReceiver:BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
          Toast.makeText(context,"Time is changed",Toast.LENGTH_SHORT).show()
        }
    }
}

在这里插入图片描述
静态注册在AndroidManifest.xml中注册:
新建MyReceiver类继承自BroadcastReceiver,onReceive方法表示接收到广播之后会进行的操作:
在这里插入图片描述
与动态注册不同,不再需要通过registerReceiver注册,也不需要通过addAction方法用来表明广播接收器监听的时什么广播,而是直接在AndroidManifest.xml文件中声明:
在这里插入图片描述
这样当网络状态发生改变时,onReceive方法就会被执行,效果如下:
关闭网络
在这里插入图片描述
开启网络
在这里插入图片描述
由于大量的恶意软件利用静态注册的机制可以在程序未启动的状态下监听系统广播,从而使任何应用都可以频繁的从后台被唤醒,严重影响了用户手机的电量和性能,因此8.0之后几乎每个版本都在削减静态注册的功能,这里就不基于Q进行演示了。

上述的广播都是来自系统的广播,如果我们想要接收应用程序自己发出的广播,该怎么办呢?
修改MyReceiver类中的代码:在这里插入图片描述
修改AndroidManifest.xml中的代码:
在这里插入图片描述
可以看到这里的action已经不是系统的广播了而是我们自定义的广播,接着在MainActivity中放入一个按钮,设置点击事件如下:
首先构造一个Intent对象,并把要发送的广播的值传入,注意AndroidManifest.xml文件中的值要和这个相同。然后调用Context的sendBroadcast方法将广播发送出去,这样所有监听这条广播的广播接收器就会收到消息,onReceive方法就会被执行:
在这里插入图片描述
点击按钮效果如下,这种广播也是属于标准广播:

在这里插入图片描述

有序广播

有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播接收器是有先后顺序的,且优先级(priority)高的广播接收器会先收到广播消息。有序广播可以被接收器截断使得后面的接收器无法收到它。有序广播的工作流程如图所示:
在这里插入图片描述
新建一个项目Broadtest也接收这个自定义广播,点击按钮后发现Toast了两次,这里其实还是标准广播,那么怎么才能有序呢?
在这里插入图片描述
在这里插入图片描述
修改按钮点击事件,将发送广播事件的方法改为sendOrderedBroadcast:
在这里插入图片描述
并修改Broadtest的广播优先等级:
在这里插入图片描述
再次点击按钮发现Toast的顺序已经发生改比变:
在这里插入图片描述
在这里插入图片描述
如果想要截断广播,调用abortBroadcast方法即可:
在这里插入图片描述
再次点击按钮:发现只有一次Toast了
在这里插入图片描述

本地广播

前面提到的广播都是系统级别的,也就是别的应用程序也可以接收到广播消息,这样很可能导致一些安全问题,比如别的应用恶意向本应用发送大量垃圾广播消息。因此Android引入本地广播机制,使用本地应用广播只能接受来自本应用的广播,别的应用也不会接收到本应用发送的广播消息。
首先修改两个应用的AndroidManifest.xml文件,将静态注册去掉:
在这里插入图片描述
接着修改broadcast项目中的MyReceiver:
在这里插入图片描述
修改MainActivity代码,通过LocalBroadcastManager来对广播进行管理,包括注册、发送等。用法和动态注册相似:
在这里插入图片描述
再次点击按钮,发现只有本应用的onReceive方法执行,说明Broadtest项目没有接收到来自本应用的广播消息。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42011443/article/details/106870601