我發現在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 來提高匹配的應用點,歡迎來告知我。