乐于分享
好东西不私藏

Android APP 接收系统消息

Android APP 接收系统消息

1. 目标

因为要实现无 UI、开机运行、可以弹通知框的 APP,我问了 Gemini,需要实现为 BroadcastReceiver + Service。我先摸一摸 BroadcastReceiver。

2. BroadcastReceiver 是什么

https://developer.android.com/develop/background-work/background-tasks/broadcasts?hl=zh-cn

BroadcastReceiver(广播接收器)是 Android 四大组件之一。它用来接收系统或应用发出的广播消息,实现跨组件或跨应用的数据通信。使用时需继承 BroadcastReceiver 并重写 onReceive() 方法。Android 支持两种 BroadcastReceiver 注册方法——静态注册和动态注册。

动态注册就是在代码中调用 registerReceiver,注册成功后就可以接收广播消息。

静态注册就是在 AndroidManifest.xml 实现开启接收广播的功能。系统会在广播发出后启动应用。如果应用没有运行,系统会启动该应用。这种方式简单,而且符合我的需求。就是它了!

3. 实验环境

IDE:Android Studio Panda 3 | 2025.3.3 

设备:Android Studio 模拟器——Pixel 6

4. 新建工程

因为不需要 UI,所以新建工程时选择 No Activity。

5. 实现静态 BroadcastReceiver

修改 AndroidManifest.xml,包含 2 部分:

  1. 设置为不显示 UI——android:theme="@android:style/Theme.NoDisplay"

  2. 注册开机广播接收器——<receiver> …… </receiver>

完整的 AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?><manifestxmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools">    <application        android:allowBackup="true"        android:dataExtractionRules="@xml/data_extraction_rules"        android:fullBackupContent="@xml/backup_rules"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@android:style/Theme.NoDisplay"<!-- 1. 关键:全局无界面主题 -->        <!-- 2. 注册开机广播接收器(无需配置任何 Activity) -->        <receiver            android:name = ".BootReceiver"            android:enabled = "true"            android:exported = "true" >            <intent-filter>                <actionandroid:name="android.intent.action.BOOT_COMPLETED" />            </intent-filter>        </receiver>    </application></manifest>

6. 重写 BroadcastReceiver:onReceive

BootReceiver.kt:

package com.packt.noui_broadcastimport android.content.BroadcastReceiverimport android.content.Contextimport android.content.Intentimport android.util.Logclass BootReceiver : BroadcastReceiver() {    private val TAG = "boot-broadcast-test"    override funonReceive(context: Context, intent: Intent) {        if(intent.action == Intent.ACTION_BOOT_COMPLETED) {            Log.d(TAG, "receive boot broadcast")        }    }}

定义的 Class 名必须class BootReceiver,因为这个名字要和 AndroidManifest.xml 中 receiver 的 android:name 相对应。

7. 测试

Android Studio 中点击绿色小三角以后,APP 就可以运行在虚拟设备中了。我注册的是接收系统启动完成(BOOT_COMPLETED) 消息,当 APP 收到该消息后会输出一条日志信息。

虽然是系统启动完成消息,但是,并不是只有系统重启才能发送这个消息。也可以在系统启动后手动发送这个消息:

#通过 -n 指定 APP 名称和 receiver 名称adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n com.packt.noui_broadcast/.BootReceiver

8. 我遇到的问题

8.1 Android SDK 版本太低

解决方法

修改 build.gradle.kts(Module:app) 文件,将其中的 version = release(36) 改为 version = release(37)。(别忘记点 Sync

8.2 Error running 'app'

解决方法

修改运行时的配置: