目录
一、前言
二、前提
三、方案
方案一
方案二
方案三
方案四
方案五
方案六
方案七
四、关于NotificationListenerService类头注释
五、结论
一、前言
NotificationListenerService可以让应用监听所有通知,但是无法获得监听通知的权限,如下六种方案暂时均未实现,最终验证方案七+方案二可行。
二、前提
-
应用:客制化桌面(com.**.launcher);
-
应用内置在 /system/priv-app/ 下;
-
应用没有设置:android:sharedUserId="android.uid.system"。
三、方案
方案一
通过Action跳转《系统设置》应用,手动打开通知监听权限:android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS——结果如图:显示在此设备上不能获得此特性——暂不可行;
if (!AppUtils.isNotificationListenersEnabled(context, context.packageName)) {
AppUtils.gotoNotificationAccessSetting(context)
}
fun isNotificationListenersEnabled(context: Context, packageName: String): Boolean =
NotificationManagerCompat.getEnabledListenerPackages(context).contains(packageName)
fun gotoNotificationAccessSetting(context: Context): Boolean {
return 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 (e1: java.lang.Exception) {
e1.printStackTrace()
}
// Toast.makeText(this, "对不起,您的手机暂不支持", Toast.LENGTH_SHORT).show()
e.printStackTrace()
false
}
}
方案二
在源码frameworks/base/core/res/res/values/config.xml路径下,修改config_defaultListenerAccessPackages属性的值为应用包名com.***.launcher——在之前的Android11、Android12上此种方案可行,但在W517的Android9上暂不可行;
方案三
接着方案一,把设置应用的低内存检查去掉,但在通知访问权限弹窗中,点击Allow后系统同样不生效,甚至申请通知访问权限的应用【Launcher2D】会被杀死后重启——暂不可行;
方案四
在系统初次初始化时就将通知权限加入secure 数据库中,但是依旧未生效——暂不可行;
方案五
在应用启动时,去重新关闭打开一次监听服务,但是它依旧未正常工作——暂不可行;
private fun toggleNotificationListenerService() {
Log.e("TAG", "toggleNotificationListenerService: ")
val pm: PackageManager = context.packageManager
pm.setComponentEnabledSetting(
ComponentName(
context, MNotificationListenerService::class.java
), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP
)
pm.setComponentEnabledSetting(
ComponentName(
context, MNotificationListenerService::class.java
), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP
)
}
方案六
如果是某些厂商没有采用google那一套通知逻辑,修改了系统源码,比如:Binder接口被修改,在通知的时候如果采用google那一套,则极有获取不到通知,但即使无论怎么改,调用修改后源码那一套super(arg0)总是没错的;可以试着在NotificationTask类中onBind方法中返回return super.onBind(arg0)——暂不可行
class MNotificationListenerService : NotificationListenerService() {
private val TAG = MNotificationListenerService::class.java.simpleName
override fun onBind(intent: Intent?): IBinder? {
return super.onBind(intent)
}
}
方案七
接着方案一,修改设备为非低内存设备,即将ActivityManager的isLowRamDeviceStatic方法直接返回false,如下,编译系统后验证OK...【开心】
@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {
public static boolean isLowRamDeviceStatic() {
// return RoSystemProperties.CONFIG_LOW_RAM ||
// (Build.IS_DEBUGGABLE && DEVELOPMENT_FORCE_LOW_RAM);
return false;
}
}
原因如下: 参考第四节NotificationListenerService类头注释,Android10及更低版本的低RAM设备上,NotificationListenerService是无法获取通知访问权限的。
解决方案:关掉低内存设备的判断逻辑,直接返回false。
四、关于NotificationListenerService类头注释
1、 Android 11/12的NotificationListenerService类头注释中有如下内容:
Notification listeners cannot get notification access or be bound by the system on low-RAM devices running Android Q (and below).
翻译过来就是说:在运行 Android Q(及更低版本)的低 RAM 设备上,通知侦听器无法获取通知访问权限或被系统绑定。
2、 Android 9的NotificationListenerService类头注释中有如下内容:
Notification listeners cannot get notification access or be bound by the system on low-RAM devices.
翻译过来就是说:在低 RAM 设备上,通知侦听器无法获取通知访问权限或被系统绑定。
五、结论
使用方案七+方案二即可。