Android 跨应用广播通信全攻略

在 Android 开发中,广播(Broadcast) 是一种非常常用的组件间通信机制,既可以在应用内部解耦模块,也可以在多个应用之间传递消息。

但是随着 Android 版本的演进,特别是 8.0+(API 26) 之后,广播的使用方式有了很多限制和坑。

今天我们结合一个实际场景,来系统梳理一下 跨应用广播 的正确用法。


1. 广播的分类

Android 中的广播按发送/接收方式主要有两类:

分类 注册方式 特点
静态注册 Manifest 配置 进程未启动时也能接收(部分系统广播受限),App 会被系统唤醒
动态注册 代码中注册 只能在进程运行时接收,生命周期跟随注册者,灵活但需手动管理

2. Android 8.0+ 的限制

Android 8.0(API 26) 开始,大部分隐式广播(未指定包名/组件的广播)禁止静态注册。

比如:

java 复制代码
sendBroadcast(new Intent("custom.start.schoolfinance.MODE_CHANGE"));

在 8.0+ 中,Manifest 静态注册的自定义接收器将收不到此广播。

但以下情况不受限制:

  1. 显式广播(指定包名或组件名)
  2. 系统允许的部分广播(如 BOOT_COMPLETEDPACKAGE_ADDED 等)
  3. 应用内部广播(LocalBroadcast)

3. 显式广播的正确用法

显式广播就是明确指定接收方,例如指定包名:

java 复制代码
Intent intent = new Intent("custom.start.schoolfinance.MODE_CHANGE");
intent.setPackage("com.appB.package"); // 只发给 B 应用
sendBroadcast(intent);

优点:

  • 不受 Android 8.0+ 静态注册限制
  • 安全性高,不会被第三方应用接收
  • 投递效率高,只发给目标应用

缺点:

  • 只能发给指定的应用,广播范围受限

4. Application 中动态注册

如果只要求在应用运行时接收广播,可以在 Application 中动态注册:

java 复制代码
public class MyApplication extends Application {
    private final BroadcastReceiver modeChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int mode = intent.getIntExtra("mode", -1);
            Log.d("桌面APP", "收到模式变更广播: mode=" + mode);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver(modeChangeReceiver, new IntentFilter("custom.start.schoolfinance.MODE_CHANGE"));
    }
}

优点

  • 不受 Android 8.0 隐式广播限制
  • 灵活,可在运行时按需注册

缺点

  • 应用进程未启动时无法接收

5. 跨应用发送广播示例(A → B)

A 应用发送:

java 复制代码
Intent intent = new Intent("custom.start.schoolfinance.MODE_CHANGE");
intent.putExtra("mode", 1);
intent.setPackage("com.appB.package"); // 显式指定
sendBroadcast(intent);

B 应用接收(Application 中动态注册):

java 复制代码
@Override
public void onCreate() {
    super.onCreate();
    registerReceiver(modeChangeReceiver, new IntentFilter("custom.start.schoolfinance.MODE_CHANGE"));
}

📌 适用:B 已启动或后台常驻时实时接收


6. 让未启动的应用也能接收

如果希望 B 即使没启动也能收到广播,必须:

  • Manifest 中静态注册接收器
  • 广播必须是显式广播

B 应用:

xml 复制代码
<receiver android:name=".ModeChangeReceiver" android:exported="true">
    <intent-filter>
        <action android:name="custom.start.schoolfinance.MODE_CHANGE"/>
    </intent-filter>
</receiver>

7. 系统广播中转给其他应用

有时 A 需要在收到系统广播(如 BOOT_COMPLETED)后,把信息转发给 B:

java 复制代码
public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            Intent sendToB = new Intent("custom.start.schoolfinance.MODE_CHANGE");
            sendToB.putExtra("mode", 1);
            sendToB.setPackage("com.appB.package");
            context.sendBroadcast(sendToB);
        }
    }
}

8. 选择方案的参考表

需求 推荐方案
进程未启动也能接收 静态注册 + 显式广播
应用已运行,实时接收 Application 中动态注册
只发给一个应用 显式广播(setPackage/setComponent)
多个应用都要接收 隐式广播(注意 8.0+ 限制)

9.为什么 setIntent() 必须调用

singleTask + FLAG_ACTIVITY_CLEAR_TOP 场景下的 Intent 参数传递流程图 ,为什么 setIntent() 必须调用?

css 复制代码
┌─────────────────────────┐
│ 启动 Activity A (首次)   │
│ onCreate(Intent old)     │
│ mIntent = oldIntent      │
└────────────┬────────────┘
             │
             ▼
        用户停留在 A
             │
             ▼
┌─────────────────────────┐
│ 再次启动 A               │
│  Intent: machineMode=1  │
│  FLAG_ACTIVITY_CLEAR_TOP │
└────────────┬────────────┘
             │
  A 已经存在 → 不走 onCreate()
             │
             ▼
┌─────────────────────────────┐
│ 调用 onNewIntent(newIntent) │
│  (machineMode=1)            │
└─────────────────────────────┘
             │
             │ (系统并不会更新 mIntent)
             ▼
  mIntent 还是旧的 → getIntent() 读不到新参数 ❌
             │
             ▼
   调用 setIntent(newIntent) ✔
             │
             ▼
  mIntent 更新 → getIntent() 拿到最新参数

总结

  • 不调用 setIntent()getIntent() 永远是第一次启动时的旧数据。
  • 调用 setIntent()getIntent() 会返回最新一次启动传进来的参数。

所以

java 复制代码
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent); // 必须,保证 getIntent() 是最新
    handleIntent(intent);
}

总结

  • Android 8.0+ 对静态注册隐式广播限制很大,跨应用通信优先用 显式广播
  • 动态注册灵活,但依赖进程常驻
  • 静态注册 + 显式广播是唤醒未启动应用的唯一通用方式
  • 系统广播可以作为触发器,把消息中转给目标应用
相关推荐
OperateCode1 小时前
Android Studio 格式规范
android
张风捷特烈1 小时前
鸿蒙纪·Flutter卷#02 | 已有 Flutter 项目鸿蒙化 · 3.27.4 版
android·flutter·harmonyos
QING6184 小时前
Media3 ExoPlayer 快速实现背景视频播放(干货)
android·前端·kotlin
用户2018792831674 小时前
PengdingIntent之“我想要的很简单时光还在你还在”
android
weiwuxian4 小时前
js与原生通讯版本演进
android·前端
叽哥4 小时前
flutter学习第 12 节:网络请求与 JSON 解析
android·flutter·ios
y东施效颦5 小时前
uni-app app端安卓和ios如何申请麦克风权限,唤起提醒弹框
android·ios·uni-app
亲爱的非洲野猪6 小时前
从 0 到 1:用 MyCat 打造可水平扩展的 MySQL 分库分表架构
android·mysql·架构
安卓开发者6 小时前
深入理解Android Kotlin Flow:响应式编程的现代实践
android·kotlin·echarts