简介

当下不少第三方安全APP都有消息管理功能或者叫消息盒子功能,它们能管理过滤系统中的一些无用消息,使得消息栏更清爽干净。其实此功能的实现便是使用了Android中提供的通知使用权权限。Android4.3后加入了通知使用权NotificationListenerService,就是说当你开发的APP拥有此权限后便可以监听当前系统的通知的变化,在Android4.4后还扩展了可以获取通知详情信息。下面我们来看看NotificationListenerService的具体使用。

使用

新建一服务类,使它继承NotificationListenerService,并实现两个重要的方法:

kotlin 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification

class NotificationListener : NotificationListenerService() {

// sbn.getId(); 返回通知对应的id
// sbn.getNotification(); 返回通知对象
// sbn.getPackageName(); 返回通知对应的包名
// sbn.getPostTime(); 返回通知发起的时间
// sbn.getTag(); 返回通知的Tag,如果没有设置返回null
// sbn.isClearable(); 返回该通知是否可被清楚,是否为FLAG_ONGOING_EVENT、FLAG_NO_CLEAR
// sbn.isOngoing(); 返回该通知是否在正在运行的,是否为FLAG_ONGOING_EVENT

// 通知被移除时回调
override fun onNotificationRemoved(sbn: StatusBarNotification?) {
super.onNotificationRemoved(sbn)

}

// 增加一条通知时回调
override fun onNotificationPosted(sbn: StatusBarNotification?) {
super.onNotificationPosted(sbn)
}
}

java 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class NotificationListener extends NotificationListenerService {
privatestatic final String TAG = "NotificationListener";

@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
Log.i(TAG,"Notification removed");
}

@Override
public void onNotificationPosted(StatusBarNotification sbn) {
Log.i(TAG, "Notification posted");
}
}

注册权限

AndroidManifest.xml中声明此服务类,并必须声明BIND_NOTIFICATION_LISTENER_SERVICE许可和意图过滤器android.service.notification.NotificationListenerService,还有我们在系统设置中通知使用权列表中看到的label标签:

1
2
3
4
5
6
7
8
9
<!--通知栏使用权限-->
<service
android:name=".listener.NotificationListener"
android:label="通知使用权测试程序"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService"/>
</intent-filter>
</service>

判断是否拥有通知使用权

kotlin版本

1
2
3
4
5
6
7
8
9
10
11
/**
* 判断是否拥有通知使用权
* 使用NotificationListenerService的应用如果开启了Notification access,系统会将包名等相关信息写入SettingsProver数据库中,因此可以从数据库中获取相关信息并过滤,从而判断应用是否开启了Notification access,代码如下:
*/
fun isNotificationEnable(context: Context?): Boolean {
val flat = Settings.Secure.getString(context?.contentResolver, "enabled_notification_listeners")
if (flat != null) {
return flat.contains(context!!.packageName)
}
return false
}

java 版本

1
2
3
4
5
6
7
8
9
private boolean notificationListenerEnable() {
boolean enable = false;
String packageName = getPackageName();
String flat= Settings.Secure.getString(getContentResolver(),"enabled_notification_listeners");
if (flat != null) {
enable= flat.contains(packageName);
}
return enable;
}

跳转系统设置里的通知使用权页面

kotlin 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 跳转系统通知使用权页面
*/
fun gotoNotificationAccessSettingUI(context: Context?): Boolean {
return if (null == context) {
false
} else try {
val intent = Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS")
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
true
} catch (e: ActivityNotFoundException) {
try {
val intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val cn = ComponentName(
"com.android.settings",
"com.android.settings.Settings\$NotificationAccessSettingsActivity"
)
intent.component = cn
intent.putExtra(":settings:show_fragment", "NotificationAccessSettings")
context.startActivity(intent)
return true
} catch (ex: Exception) {
ex.printStackTrace()
}
false
}
}

java 版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private boolean gotoNotificationAccessSetting(Contextcontext) {
try {
Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return true;
} catch(ActivityNotFoundException e) {
try {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ComponentName cn = new ComponentName("com.android.settings","com.android.settings.Settings$NotificationAccessSettingsActivity");
intent.setComponent(cn);
intent.putExtra(":settings:show_fragment", "NotificationAccessSettings");
context.startActivity(intent);
return true;
} catch(Exception ex) {
ex.printStackTrace();
}
return false;
}
}

参考文章

https://blog.csdn.net/lyz_zyx/article/details/65440927/
https://blog.csdn.net/sunjie3030/article/details/100521191