I discovered that Android 4.4 (API level 19) added a set of not-yet-documented XML attributes to its
<data> tag for intent filtering.
android:ssp attribute is intended to match against URIs — the "ssp" stands for "scheme-specific part" and essentially means everything that appears after the scheme.
e.g. The URI
"https://example.com/foo/bar" can be split into the scheme
"https" and scheme-specific part
While this isn't of much use for regular HTTP URLS, as the
android:path* attributes exist to easily build intent filters, it makes monitoring certain types of events much more efficient.
The broadcast receiver mechanism on Android is a great way to ensure that your app — regardless of whether its process is already running — can be informed of system events, like whether there's currently network connectivity, or the battery is low etc.
However, when multiple apps subscribe to the same, oft-occurring events, this causes a lot of processes to started by the system simultaneously, bringing the whole system to a crawl.
The most common case in which this occurs is when installing, updating or removing an Android package.
Apparently a lot of apps with analytics SDKs built in like to monitor and report on app installs or removals, and do so with a broadcast receiver defined like this:
<receiver android:name=".PackageReceiver"> <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <data android:scheme="package" /> </intent-filter> </receiver>
Note that we're only interested in actions whose URI look like "package:com.example.someapp", but because this is not a hierarchical URI — there is no host, no port, no path — we cannot be any more precise about exactly which packages we want to be notified for. So all apps get woken up for every package event!
Android 4.4 allows us to match against the scheme-specific part of the URI with the
In the case of packages, we can now specifically target one or more packages we are interested in. For example, an app I worked on had three different package IDs for development, beta and release builds.
We could match all three apps (and no others) with a filter like this:
<receiver android:name=".DataClearedReceiver"> <intent-filter> <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" /> <data android:scheme="package" android:sspPrefix="com.myswitzerland.hotels" /> </intent-filter> </receiver>
So only intents containing package URIs which start with that exact text would cause the app process to start and the receiver to be triggered. If any other app has its data cleared, our process does not start. Excellent!
Of course, this works for other non-hierachical URI types like
In a slightly-contrived example, we could intercept specific email addresses and let the user choose to use our specific Activity, rather than the default email client:
<activity android:name=".PremiumSupportActivity"> <intent-filter> <action android:name="android.intent.action.SENDTO" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="mailto" android:sspPattern="email@example.com" /> </intent-filter> </activity>
So it is also possible to register such intent filters at runtime if required, e.g.:
IntentFilter pkgFilter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); pkgFilter.addDataScheme("package"); pkgFilter.addDataSchemeSpecificPart("com.example.someapp", PatternMatcher.PATTERN_LITERAL);
These examples work for me on an Android 4.4 device, but the XML attributes should also be safe to use on earlier Android versions, as the system will just ignore the unknown SSP attributes.
Let me know if you can think of other use cases that could be improved by the use of scheme-specific part matching.