安卓通知欄管理詳解及分析 NotificationListenerService

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, 界面比較簡陋,如圖:

Demo截圖

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中.

程序運行如下:

程序運行截圖 程序運行截圖

程序源碼地址

Github 源碼地址

有興趣的同學可以下載源碼繼續學習,也可以對文章的DEMO源碼優化提交Pull Requests!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章