Android 跨应用广播通信全攻略

2025-12-04 09:47:14

剧情档案

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

在 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 静态注册的自定义接收器将收不到此广播。

但以下情况不受限制:

显式广播(指定包名或组件名)

系统允许的部分广播(如 BOOT_COMPLETED、PACKAGE_ADDED 等)

应用内部广播(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

复制代码

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+ 对静态注册隐式广播限制很大,跨应用通信优先用 显式广播

动态注册灵活,但依赖进程常驻

静态注册 + 显式广播是唤醒未启动应用的唯一通用方式

系统广播可以作为触发器,把消息中转给目标应用