NotificationListenerService 安卓通知欄管理詳解及分析
一. 方法概述
在api 18前可以通過輔助功能’AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED’或是反射活取通知欄相關信息。
現在我們可以根據NotificationListenerService類非常容易的活取通知回調相關信息。
二. NotificationListenerService詳解
通知的新增和刪除,都會回調你註冊的NLS裏的方法,這些信息可以通過StatusBarNotification類對象來獲取。
另外比較主要的是,系統開啓通知讀取服務後,系統就會對APP有個保活功能,當被系統或是第三方軟件kill後,系統會將你的應用重啓。很多廠商會利用這點做一些壞壞的事情。並且國內各大殺毒,清理軟件都有開啓該功能。
NotificationListenerService主要方法(成員變量):
刪除通知時會回調onNotificationRemoved, 新增通知或是更新時會回調onNotificationPosted
- cancelAllNotifications() :刪除系統中所有 可被清除 的通知;
- cancelNotification(String pkg, String tag, int id) :刪除具體某一個通知;
- getActiveNotifications() :返回當前系統所有通知到StatusBarNotification[]的列表;
- onNotificationPosted(StatusBarNotification sbn) :當系統收到新的通知後出發回調;
- onNotificationRemoved(StatusBarNotification sbn) :當系統通知被刪掉後出發回調;
StatusBarNotification類詳解
StatusBarNotification,多進程傳遞對象,所有通知信息都會在這個類中通過Binder傳遞過來.
內部幾個重要的方法如下:
- getId():返回通知對應的id;
- getNotification():返回通知對象;
- getPackageName():返回通知對應的包名;
- getPostTime():返回通知發起的時間;
- getTag():返回通知的Tag,如果沒有設置返回null;
- isClearable():返回該通知是否可被清楚,FLAG_ONGOING_EVENT、FLAG_NO_CLEAR;
- isOngoing():檢查該通知的flag是否爲FLAG_ONGOING_EVENT;
其中,我們通過getNotification()可以得到Notification對象,Notification是我們比較熟悉的類了,我們可以得到通知具體內容甚至可以還原RemoteViews到我們的本地view上。
三. 使用方法
正確使用NotificationListenerService需要進行三步驟:
1. 新建一個類並繼承自NotificationListenerService,override其中重要的兩個方法;
public class NLService extends NotificationListenerService {
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
}
}
2. 在AndroidManifest.xml中註冊Service並聲明相關權限;
<service android:name=".NLService"
android:label="@string/service_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
3. 開啓NotificationMonitor的監聽功能;
if (!isEnabled()) {
Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivity(intent);
} else {
Toast.makeText(this, "已開啓服務權限", Toast.LENGTH_LONG).show();
}
private boolean isEnabled() {
String pkgName = getPackageName();
final String flat = Settings.Secure.getString(getContentResolver(),
ENABLED_NOTIFICATION_LISTENERS);
if (!TextUtils.isEmpty(flat)) {
final String[] names = flat.split(":");
for (int i = 0; i < names.length; i++) {
final ComponentName cn = ComponentName.unflattenFromString(names[i]);
if (cn != null) {
if (TextUtils.equals(pkgName, cn.getPackageName())) {
return true;
}
}
}
}
return false;
}
四. Demo講解
根據以上步驟,已經可以接收到通知欄變換時的回調,及獲取當前所有通知列表,我們限制寫個小例子,活取所有通知列表並且監聽通知欄的變換,把收到的Notification及相關信息展示到我們的頁面ListView中.
1. 按照以上步驟建立基本例子框架
寫佈局,要有開啓服務的btn, 活取所有通知的btn和清除所有列表的btn, 界面比較簡陋,如圖:
2. 建立BroadcastReceiver和Service交互
當然也可以用binder說是message通信,根據自己程序設計選擇,這裏爲了簡單的演示用了BroadcastReceiver機制
class NotificationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String temp = mInfoList.size() + ":" + intent.getStringExtra(EVENT);
NTBean bean = new NTBean();
bean.info = temp;
Bundle budle = intent.getExtras();
bean.title = budle.getString(Notification.EXTRA_TITLE);
bean.text = budle.getString(Notification.EXTRA_TEXT);
bean.subText = budle.getString(Notification.EXTRA_SUB_TEXT);
bean.largeIcon = budle.getParcelable(Notification.EXTRA_LARGE_ICON);
Icon icon = budle.getParcelable(Notification.EXTRA_SMALL_ICON);
bean.smallIcon = icon;
bean.viewS = budle.getParcelable(VIEW_S);
bean.viewL = budle.getParcelable(View_L);
mInfoList.add(bean);
Log.e("changxing", "receive:" + temp + "\n" + budle);
mAdapter.notifyDataSetChanged();
}
}
3. 活取相關回調展示頁面
將回調的相關參數傳遞到activity中, 展示到listview中,其中可以直接用RemoteViews#apply方法將Notification展示到我們本地ViewGroup中.
程序運行如下:
程序源碼地址
有興趣的同學可以下載源碼繼續學習,也可以對文章的DEMO源碼優化提交Pull Requests!