本文最后更新于 798 天前
一、判断应用是否包含监听权限
private fun isEnabled(): Boolean {
val pkgName = packageName
val flat: String =
Settings.Secure.getString(contentResolver, "enabled_notification_listeners")
if (!TextUtils.isEmpty(flat)) {
val names = flat.split(":".toRegex()).toTypedArray()
for (i in names.indices) {
val cn = ComponentName.unflattenFromString(names[i])
if (cn != null) {
if (TextUtils.equals(pkgName, cn.packageName)) {
return true
}
}
}
}
return false
}
二、开启监听和跳转
if (!isEnabled()) {
startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
} else {
val toast =
Toast.makeText(applicationContext, "监控器开关已打开", Toast.LENGTH_SHORT)
toast.show()
}
if (isEnabled()) {
startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
} else {
val toast =
Toast.makeText(applicationContext, "监控器开关已关闭", Toast.LENGTH_SHORT)
toast.show()
}
三、定义监听服务
@SuppressLint("NewApi")
class NotificationMonitorService : NotificationListenerService() {
// 在收到消息时触发
override fun onNotificationPosted(sbn: StatusBarNotification) {
// 获取标准消息内容
val extras = sbn.notification.extras
// 获取接收消息APP的包名
val notificationPkg = sbn.packageName
// 获取接收消息的抬头
val notificationTitle =
extras.getString(Notification.EXTRA_TITLE)
val tickerText = sbn.notification.tickerText
// 获取接收消息的内容
val notificationText = extras.getString(Notification.EXTRA_TEXT)
Log.i(
"iichen",
"Notification 标准 posted notificationTitle ¬ificationText & tickerText ¬ificationPkg"
)
// 获取非标准通知内容
val view = getContentView(this,sbn.notification)
view?.apply {
val content = getContent(this)
Log.i(
"iichen",
"Notification 非标准 posted notificationTitle &content"
)
}
}
// 在删除消息时触发
override fun onNotificationRemoved(sbn: StatusBarNotification) {
// TODO Auto-generated method stub
val extras = sbn.notification.extras
// 获取接收消息APP的包名
val notificationPkg = sbn.packageName
// 获取接收消息的抬头
val notificationTitle =
extras.getString(Notification.EXTRA_TITLE)
// 获取接收消息的内容
val notificationText = extras.getString(Notification.EXTRA_TEXT)
Log.i(
"iichen",
"Notification removed notificationTitle ¬ificationText"
)
}
//获取notification的view
fun getContentView(context: Context?, notification: Notification): View? {
var contentView: RemoteViews? = null
//获取contentView
if (notification.contentView != null) {
contentView = notification.contentView
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
contentView = Notification.Builder.recoverBuilder(context, notification)
.createContentView()
}
//RemoteViews转成view
var view: View? = null
try {
view = contentView?.apply(context, null)
} catch (e: Throwable) {
}
return view
}
//获取view里面的文本
fun getContent(view: View): String? {
val stringBuilder = StringBuilder()
traversalView(view, stringBuilder)
return stringBuilder.toString()
}
//遍历View,获取TextView里面的文本内容
private fun traversalView(
view: View,
stringBuilder: StringBuilder
) {
if (view is ViewGroup) {
val viewGroup = view as ViewGroup
val count = viewGroup.childCount
for (i in 0 until count) {
val childView: View = viewGroup.getChildAt(i)
traversalView(childView, stringBuilder)
}
} else {
if (view is TextView) {
val tv = view as TextView
val text = tv.text
stringBuilder.append(text)
stringBuilder.append(";")
}
}
}
}
四、清单文件配置