Search code examples
androidpollingandroid-broadcast

Alternatives to implicit BroadcastReceiver?


I am currently working on an architecture to pass traffic messages (“stationary traffic on A9 between Como-Monte Olimpino and Brogeda”) between applications.

Sources of these messages are dedicated apps: one picks up messages via TMC, others might pull them from various services on the Internet.

Consumers are navigation apps in the typical use case, though other use cases are possible as well.

Multiple sources and consumers can be active at the same time.

When a source receives a new message, it sends a broadcast Intent with the message as an extra. Consumers register a BroadcastReceiver to pick up these messages. (Payload for a message typically being a few hundred bytes.)

When a consumer starts up, I need to provide a way for it to poll every source for messages which the source might have in its cache (while bearing in mind that the consumer has no way of knowing which sources are available).

My initial idea was to do that via broadcasts as well: on startup, the consumer would send an implicit broadcast and each source would respond with a broadcast feed of its currently active messages.

Some sources might not be running at the time a consumer starts up, but may still have messages in their cache that need to be delivered to the consumer. As a context-registered BroadcastReceiver would not be able to catch the poll broadcast if the app is not running, it would seem logical to declare te receiver in the manifest.

However, as of Android 8.0, manifest-declared receivers can no longer be used to receive implicit broadcasts. Furthermore, this comment suggests that even on earlier versions and with some flavors of Android, waking up an app via an implicit broadcast does not work as expected (and the device on which I am developing sems to have that restriction as well).

What would be a good mechanism to let a consumer retrieve all currently active messages from all sources, even if they are not running? Implementing a content provider looks a bit like overkill, so what other options are available?


Solution

  • Your consumer app will need to know:

    • What sources are installed

    • What subset of those sources the user wants the consumer app to use (as the user might not want all of them)

    Possible ways to know what sources are installed include:

    • Iterating over a list of known possible source application IDs and using PackageManager to see which are installed
    • Using some application ID naming convention (if you will be the developer of all source apps) and using PackageManager to see which installed apps adhere to that convention
    • Using PackageManager and queryBroadcastReceivers() to see which apps implement a receiver for some known action string
    • Using PackageManager to iterate over all installed apps and see which have a certain <meta-data> entry

    You can use SharedPreference and a MultiSelectListPreference, or some similar UI, to allow the user to uncheck particular sources that they do not want the consumer app to use.

    Given that you are planning on the sources sending broadcasts to consumers, you will also need the same basic flow in the source apps, to see:

    • What consumers are installed
    • What subset of those consumers the user wants the source app to work with

    Given that the sources know the eligible consumers, and vice versa, you have a variety of IPC options.

    It feels like that most of the communications is source -> consumer. In that case, having sources use broadcasts is reasonable. Bear in mind that those will need to be explicit broadcasts:

    • Create an Intent with the desired action string
    • Iterate over the application IDs of the eligible consumers
      • Use setPackage() on a copy of the Intent to associate it with a particular consumer
      • Send the "broadcast" of that copy

    If I am correct that most of the communications is source -> consumer, then using a broadcast from consumer -> source to "wake up" the sources and get cached data is reasonable, if this will simplify the implementation of the sources. It may be that a regular update broadcast is very similar to the "send the cached events" broadcast.

    If there will be substantial differences between those two broadcasts, such that not a lot of code would be shared either on the source or the consumer, you might eliminate the asynchronous nature of that approach and use a ContentProvider, where the source has a provider that the consumer can query.


    IMHO, your #1 problem with all of this is privacy and security. N-party communications like this gets tricky to make sure that it is not accidentally N+1-party communications, where the +1 is a piece of spyware.