我发现在Android 4.4(API level 19) 中标签增加了一个新的没有在文档中记录的 XML 属性,这个属性是用来过滤 intent的。’android:ssp’这个属性旨在比对URI,顾名思义 “ssp” 是 “scheme-specific part”的缩写,也就是指URI中除了scheme以外的所有剩下的内容。
举个例子,如果我们有个一个 URI 内容是 “https://example.com/foo/bar” 那么这个URI的scheme是’https’ ,而它的ssp则是”//example.com/foo/bar”。另外,这个属性并不常常用来匹配例子中所说的常规HTTP URL,因为我们已经有了 ‘android:host’以及 ‘android:path*’这样的方便好用的过滤器去解决这个问题。ssp这个过滤则是让我们更高效的去监控一些特定的intent事件。
实际问题
Android 的 broadcast receiver 机制是保证你的app收到系统各类信息通知的好方法,无论你的应用是否启动,你都可以接收到系统的broadcast。比如,当前网络的状态,电池电量低等等。同时,由于许多不同的App可能会注册同一个高频率的事件,这就导致了系统同时会换起很多进程,这会让你的系统变的很慢。有个常见的例子就是当你安装,升级或卸载应用的时候引起系统的卡顿。显然,许多带统计SDK的应用都试图去监控和报告当前机器中app的安装和卸载情况,一般来说需要接收的 broadcast receiver 就如同下文所示的代码那样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
; html-script: false ] <receiver android:name=".PackageReceiver"> <intent-filter> <action android:name="android.intent.action.PACKAGE_ADDED" /> <data android:scheme="package" /> </intent-filter> </receiver> ``` 可以注意到的一点是,我们往往只是对一部分的事件有兴趣,比如 URI 是类似于"package:com.example.someapp" 。但由于这个URI并不是一个层次结构的URI,它并没有host,port以及path这些信息,我们并没有办法精确的指定需要监控的包,所以每次有 package 想过的操作 app 都会被唤醒! ##巧用 android:ssp 到了Android 4.4 ,我们可以是使用 scheme-specific部分来匹配 URI,只需要利用`android:ssp`, `android:sspPrefix` 以及 `android:sspPattern`这三个属性就可以。还是以上面的 package 事件做例子,我们现在可以指定特定的一个或几个我们有兴趣的包来进行监控。比如说,我的 app 拥有三个不同的 package ID 分别给开发版,beta版以及正式版。那么我们可以通过如下的方式去匹配这三个 app : <pre class="brush: xml; gutter: true; first-line: 1; highlight: []; html-script: false"> <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> |
这样,只有包含特定开头的package URL的intent才会换起我们app并且触发broadcast receiver了。如果是其他的 app 的操作,我们的应用并没有被唤起,太棒了!当然,这个也可以用在其他的无层次结构的 URI 比如mailto
或者tel
这种。比如另外一个稍有不同的例子,我们可以通过这个手法来截获特定的邮件地址的intent,让用户选择我们特定的 Activity,而不是用系统默认的邮件客户端。
1 2 3 4 5 6 7 8 9 |
; html-script: false ] <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="support-.*@example.com" /> </intent-filter> </activity> |
SSP 属性目前并没有在的官方文档中提及,但是在IntentFilter文档中有提到这个属性的 Java 等效实现。
所以,我们也可以在 待命中动态来注册这样的Intent:
1 2 3 4 5 |
; html-script: false ] IntentFilter pkgFilter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); pkgFilter.addDataScheme("package"); pkgFilter.addDataSchemeSpecificPart("com.example.someapp", PatternMatcher.PATTERN_LITERAL); |
这些例子在 Android 4.4 上可以正常使用,但请放心他们在低版本的 Android 上也是安全的,系统会自动忽略掉这个不支持的属性。
最后,如果你有想到其他使用 scheme-specific 来提高匹配的应用点,欢迎来告知我。