Android 6.0 監聽系統通知(Notification)

------------------
    由於近期商顯項目需求,需要在側邊欄菜單中增加通知列表,就類似systemui中的通知一樣。先上效果圖

於是就去百度上查找如何監聽通知消息的方法,大概是需要這麼幾個步驟
    1 寫一個服務MyNotificationListenService 繼承 NotificationListenerService 並且重寫三個方法 代碼如下

package com.protruly.floatwindowlib.service;


import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;


public class MyNotificationListenerService extends NotificationListenerService {
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        super.onNotificationPosted(sbn);
        Log.i("gyx","onNotificationPosted");

    }

    @Override
    public void onListenerConnected() {
        Log.i("gyx","onListenerConnected");
        super.onListenerConnected();
    }
    
    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        super.onNotificationRemoved(sbn);
        Log.i("gyx","onNotificationRemoved");
    }
    
    
    
}

Mainfest.xml 註冊服務
 

        <service android:name=".service.MyNotificationListenerService"
            android:label="notification listener"
            android:persistent="true"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action
                android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>

啓動服務 

Intent intent =new Intent(this, MyNotificationListenerService.class);
startService(intent);

到這裏其實還沒有結束,因爲應用需要監聽通知消息,需要去設置,安全,通知裏面設置允許通知消息,但是由於我是商顯項目,並沒有這一項設置,所以需要手動設置去設置打開監聽通知消息的權限
 

private final HashSet<ComponentName> mEnabledServices = new HashSet<ComponentName>();
mConfig = getNotificationListenerConfig();
mEnabledServices.add(new ComponentName(this,  MyNotificationListenerService.class));
saveEnabledServices();

    private void saveEnabledServices() {
        StringBuilder sb = null;
        for (ComponentName cn : mEnabledServices) {
            if (sb == null) {
                sb = new StringBuilder();
            } else {
                sb.append(':');
            }
            sb.append(cn.flattenToString());
        }
        Settings.Secure.putString(getContentResolver(), mConfig.setting,
                sb != null ? sb.toString() : "");
    }

    private static Config getNotificationListenerConfig() {
        final Config c = new Config();
        c.tag = "gyx";
        c.setting = "enabled_notification_listeners";
        c.intentAction = NotificationListenerService.SERVICE_INTERFACE;
        c.permission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
        c.noun = "notification listener";
        return c;
    }
    protected static class Config {
        String tag;
        String setting;
        String intentAction;
        String permission;
        String noun;
    }
        

這部分代碼是去原生的setting上挪過來的代碼,怎麼判斷是否設置成功呢?
 

 private static boolean isNotificationListenerServiceEnabled(Context context) {
        Set<String> packageNames =     
            NotificationManagerCompat.getEnabledListenerPackages(context);
        if (packageNames.contains(context.getPackageName())) {
            return true;
        }
        return false;
    }

通過這個方法可以判斷是否開啓通知權限,以上步驟都做完了之後通過命令串口命令 dumpsys notification查看結果
 

很明顯已經設置成功,但是很奇怪的是接收通知的回調方法並沒有觸發,前前後後花了大概一天的時間也沒有找到原因,無奈之下只好去SystemUI查看它是怎麼做的。

首先創建一個NotificationListenerService 對象,重寫NotificationListenerService 幾個方法

private final NotificationListenerService mNotificationListener =
            new NotificationListenerService() {
        @Override
        public void onListenerConnected() {
            if (DEBUG) Log.d(TAG, "onListenerConnected");
            final StatusBarNotification[] notifications = getActiveNotifications();
            final RankingMap currentRanking = getCurrentRanking();
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    for (StatusBarNotification sbn : notifications) {
                        addNotification(sbn, currentRanking, null /* oldEntry */);
                    }
                }
            });
        }

        @Override
        public void onNotificationPosted(final StatusBarNotification sbn,
                final RankingMap rankingMap) {
            if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
            if (sbn != null) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {

                        String key = sbn.getKey();
                        boolean isUpdate = mNotificationData.get(key) != null;

                        // In case we don't allow child notifications, we ignore children of
                        // notifications that have a summary, since we're not going to show them
                        // anyway. This is true also when the summary is canceled,
                        // because children are automatically canceled by NoMan in that case.
                        if (!ENABLE_CHILD_NOTIFICATIONS
                            && mGroupManager.isChildInGroupWithSummary(sbn)) {
                            if (DEBUG) {
                                Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
                            }

                            // Remove existing notification to avoid stale data.
                            if (isUpdate) {
                                removeNotification(key, rankingMap);
                            } else {
                                mNotificationData.updateRanking(rankingMap);
                            }
                            return;
                        }
                        Bundle extras =sbn.getNotification().extras;
                        if(extras==null){
                           // Log.i("gyx","extras==null");
                        }else{
                            //Log.i("gyx","extras!=null");
                            String notificationText = extras.getString(Notification.EXTRA_TEXT);
                            if(notificationText==null){
                                //Log.i("gyx","notificationText==null");
                                return;
                            }else{
                               // Log.i("gyx","notificationText="+notificationText);
                            }
                        }
                        if (isUpdate) {
                          //  Log.i("gyx","isUpdate");
                            updateNotification(sbn, rankingMap);
                        } else {
                          //  Log.i("gyx","not Update");
                            addNotification(sbn, rankingMap, null /* oldEntry */);
                        }
                    }
                });
            }
        }

        @Override
        public void onNotificationRemoved(StatusBarNotification sbn,
                final RankingMap rankingMap) {
            if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
            if (sbn != null) {
                final String key = sbn.getKey();
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        removeNotification(key, rankingMap);
                    }
                });
            }
        }

        @Override
        public void onNotificationRankingUpdate(final RankingMap rankingMap) {
            if (DEBUG) Log.d(TAG, "onRankingUpdate");
            if (rankingMap != null) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    updateNotificationRanking(rankingMap);
                }
            });
        }                            }

    };

然後把這個實例通過系統API  registerAsSystemService 註冊成系統服務
 

        try {
            mNotificationListener.registerAsSystemService(mContext,
                    new ComponentName(mContext.getPackageName(),         
             getClass().getCanonicalName()),UserHandle.USER_ALL);
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to register notification listener", e);
        }

就這樣實現了監聽系統通知消息的方法,既然SystemUI可以這樣做,那麼我也嘗試這種辦法,創建NotificationListenerService  實例,通過反射拿到registerAsSystemService 方法,並且註冊成系統服務,
 

 try {
        Class clazz = 
           Class.forName("android.service.notification.NotificationListenerService");
        Method registerAsSystemService = clazz.getDeclaredMethod("registerAsSystemService", 
           Context.class, ComponentName.class, int.class);
        registerAsSystemService.invoke(mNotificationListener,this,new 
            ComponentName(getPackageName(), getClass().getCanonicalName()),-1);
 } catch (Exception e) {
        e.printStackTrace();
        Log.i("gyx","e.printStackTrace()="+e.getMessage());
 }


 NotificationListenerService mNotificationListener =
            new NotificationListenerService(){
                @Override
                public void onNotificationPosted(StatusBarNotification sbn) {
                    super.onNotificationPosted(sbn);
                    Log.i("gyx","onNotificationPosted");
                }

                @Override
                public void onNotificationRemoved(StatusBarNotification sbn) {
                    super.onNotificationRemoved(sbn);
                    Log.i("gyx","onNotificationRemoved");
                }
            };

代碼很簡單,看一下打印

註冊成功

以上就是監聽系統通知的方法,目前還是不清楚第一個方法爲什麼沒有作用,有興趣的小夥伴可以研究一下,評論回覆。感謝大家的支持。看完別忘了點贊喲。

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