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+ 对静态注册隐式广播限制很大,跨应用通信优先用 显式广播
  • 动态注册灵活,但依赖进程常驻
  • 静态注册 + 显式广播是唤醒未启动应用的唯一通用方式
  • 系统广播可以作为触发器,把消息中转给目标应用
相关推荐
世界美景6 小时前
一种基于 ART 内存特征的 LSPosed/Xposed/分身环境 完美检测方案
android·安全·安卓·xposed
2501_946230987 小时前
Cordova&OpenHarmony外观主题设置
android·javascript
小韩博7 小时前
小迪之盲注第44课
android·网络安全·adb
夏沫琅琊8 小时前
Android TestDPC 工程详解
android
键来大师9 小时前
Android16 AP热点修改默认密码为12345678
android·framework·rk3576·android16
李坤林9 小时前
Android KGI (Generic Kernel Image)
android
十二测试录9 小时前
Android和iOS测试区别
android·经验分享·ios·职场发展·ab测试
柒许宁安9 小时前
在 Cursor 中运行 Android 项目指南
android·java·个人开发
技术小甜甜9 小时前
【Godot】【入门】GDScript 快速上手(只讲游戏里最常用的 20% 语法)
android·游戏·编辑器·游戏引擎·godot
aqi0010 小时前
FFmpeg开发笔记(九十五)国产的开源视频美颜工具VideoEditorForAndroid
android·ffmpeg·音视频·直播·流媒体