隐式 BroadcastReceiver 的替代方案?

Alternatives to implicit BroadcastReceiver?

我目前正在研究一种架构,以在应用程序之间传递交通消息(“A9 上 Como-Monte Olimpino 和 Brogeda 之间的固定交通”)。

这些消息的来源是专用应用程序:一个通过 TMC 获取消息,其他人可能从互联网上的各种服务中提取它们。

消费者是典型用例中的导航应用程序,但其他用例也是可能的。

多个源和消费者可以同时处于活动状态。

当一个源收到一条新消息时,它会发送一个带有消息的广播 Intent 作为额外的。消费者注册一个 BroadcastReceiver 来获取这些消息。 (消息的有效负载通常为几百个字节。)

当消费者启动时,我需要为其提供一种方法来轮询每个来源以获取来源可能在其缓存中的消息(同时请记住,消费者无法知道哪些来源可用).

我最初的想法也是通过广播来做到这一点:在启动时,消费者将发送一个隐式广播,每个源将使用其当前活动消息的广播提要进行响应。

某些源在消费者启动时可能不 运行,但它们的缓存中可能仍有消息需要传送给消费者。如果应用程序不是 运行,上下文注册的 BroadcastReceiver 将无法捕获轮询广播,因此在清单中声明接收者似乎是合乎逻辑的。

然而,从 Android 8.0 开始,manifest-declared receivers can no longer be used to receive implicit broadcasts. Furthermore, this comment 建议即使在早期版本和 Android 的某些风格上,通过隐式广播唤醒应用程序也不起作用预期(以及我正在开发 sems 的设备也有该限制)。

什么是让消费者从所有来源检索所有当前活动消息的好机制,即使它们不是 运行?实施内容提供程序看起来有点矫枉过正,那么还有哪些其他选项可用?

您的消费者应用需要知道:

  • 安装了哪些源

  • 用户希望消费者应用程序使用这些来源的哪些子集(因为用户可能不想要所有这些来源)

了解安装了哪些源的可能方法包括:

  • 遍历已知可能的源应用程序 ID 列表并使用 PackageManager 查看安装了哪些
  • 使用一些应用程序 ID 命名约定(如果您将成为所有源应用程序的开发者)并使用 PackageManager 查看哪些已安装的应用程序遵守该约定
  • 使用 PackageManagerqueryBroadcastReceivers() 查看哪些应用程序为某些已知的操作字符串实施接收器
  • 使用 PackageManager 遍历所有已安装的应用程序并查看哪些应用程序具有特定的 <meta-data> 条目

您可以使用 SharedPreferenceMultiSelectListPreference,或一些类似的 UI,以允许用户取消选中他们不希望消费者应用程序使用的特定来源。

鉴于您正计划让源向消费者发送广播,您还需要在源应用中使用相同的基本流程,请参阅:

  • 安装了哪些消费者
  • 用户希望源应用与这些消费者的哪个子集一起工作

鉴于消息来源了解符合条件的消费者,反之亦然,您有多种 IPC 选项。

感觉大部分的交流都是source -> consumer。在这种情况下,让源使用广播是合理的。请记住,这些将需要是显式广播:

  • 使用所需的操作字符串创建 Intent
  • 迭代符合条件的消费者的应用程序 ID
    • Intent 的副本上使用 setPackage() 将其与特定消费者相关联
    • 发送该副本的"broadcast"

如果我认为大部分通信是源 -> 消费者是正确的,那么使用从消费者 -> 源到 "wake up" 源的广播并获取缓存数据是合理的,如果这将简化实施的来源。可能定期更新广播与 "send the cached events" 广播非常相似。

如果这两个广播之间存在实质性差异,以至于不会在源或消费者上共享很多代码,您可以消除该方法的异步性质并使用 ContentProvider,其中源有一个消费者可以查询的提供者。


恕我直言,所有这一切的第一个问题是隐私和安全。像这样的 N 方通信变得棘手,以确保它不是意外的 N+1 方通信,其中 +1 是一个间谍软件。