Android 6.0 监听系统通知(Notification)

------------------
    因为近期商显项目需求,须要在侧边栏菜单中增长通知列表,就相似systemui中的通知同样。先上效果图

因而就去百度上查找如何监听通知消息的方法,大概是须要这么几个步骤
    1 写一个服务MyNotificationListenService 继承 NotificationListenerService 而且重写三个方法 代码以下android

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>

启动服务 app

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

到这里其实尚未结束,由于应用须要监听通知消息,须要去设置,安全,通知里面设置容许通知消息,可是因为我是商显项目,并无这一项设置,因此须要手动设置去设置打开监听通知消息的权限
 ide

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上挪过来的代码,怎么判断是否设置成功呢?
 post

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

经过这个方法能够判断是否开启通知权限,以上步骤都作完了以后经过命令串口命令 dumpsys notification查看结果
 

很明显已经设置成功,可是很奇怪的是接收通知的回调方法并无触发,前先后后花了大概一天的时间也没有找到缘由,无奈之下只好去SystemUI查看它是怎么作的。ui

首先建立一个NotificationListenerService 对象,重写NotificationListenerService 几个方法this

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 注册成系统服务
 code

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 方法,而且注册成系统服务,
 xml

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");
                }
            };

代码很简单,看一下打印
对象

注册成功

以上就是监听系统通知的方法,目前仍是不清楚第一个方法为何没有做用,有兴趣的小伙伴能够研究一下,评论回复。感谢你们的支持。看完别忘了点赞哟。