我正在尝试向 Kotlin android compose 项目添加通知侦听器:
我的
AndroidManigest.xml
:
<application>
<!-- ... -->
<service
android:name=".MyNotificationListenerService"
android:exported="false"
android:foregroundServiceType="specialUse"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="explanation_for_special_use" />
</service>
</application>
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
我的
MainActivity.kt
:
class MainActivity : ComponentActivity() {
private lateinit var serviceIntent: Intent
private fun isServiceRunningInForeground(): Boolean {
val manager = this.getSystemService(ACTIVITY_SERVICE) as ActivityManager
@Suppress("DEPRECATION")
for (service in manager.getRunningServices(Int.MAX_VALUE)) {
if (MyNotificationListenerService::class.java.name == service.service.className) {
if (service.foreground) {
return true
}
}
}
return false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
serviceIntent = Intent(this, MyNotificationListenerService::class.java)
Log.d("NB", "MainActivity.onCreate")
setContent {
MyNotificationListenerTheme {
var isServiceRunning by remember { mutableStateOf(isServiceRunningInForeground()) }
Scaffold(
floatingActionButton = {
FloatingActionButton(
onClick = {
if (isServiceRunning) {
stopService(serviceIntent)
} else {
if (!NotificationManagerCompat.getEnabledListenerPackages(this)
.contains(
packageName
)
) {
startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))
}
startForegroundService(
serviceIntent
)
}
isServiceRunning = !isServiceRunning
}
) {
Icon(
imageVector = if (isServiceRunning) Icons.Default.Close else Icons.Default.PlayArrow,
contentDescription = if (isServiceRunning) "Pause" else "Play"
)
}
}
) { innerPadding ->
Surface(
modifier = Modifier.padding(innerPadding),
color = MaterialTheme.colorScheme.background
) {
// Your UI content
}
}
}
}
}
}
我的
MyNotificationListenerService.kt
:
class MyNotificationListenerService : NotificationListenerService() {
private val channelId = "MyNotificationListenerService"
override fun onCreate() {
super.onCreate()
createNotificationChannel()
startForeground(1, getNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE)
Log.d("NB", "MyNotificationListenerService.onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("NB", "MyNotificationListenerService.onStartCommand")
return START_STICKY
}
private fun createNotificationChannel() {
val serviceChannel = NotificationChannel(
channelId,
"My Notification Listener Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(serviceChannel)
}
private fun getNotification(): Notification {
return Notification.Builder(this, channelId)
.setContentTitle("Running...")
.build()
}
override fun onBind(intent: Intent?): IBinder? {
Log.d("NB", "MyNotificationListenerService.onBind")
return super.onBind(intent)
}
override fun onDestroy() {
Log.d("NB", "MyNotificationListenerService.onDestroy")
return super.onDestroy()
}
override fun onNotificationPosted(sbn: StatusBarNotification) {
val text = sbn.notification?.extras?.getString("android.text");
Log.d("NB", "MyNotificationListenerService.onNotificationPosted - text: $text")
super.onNotificationPosted(sbn)
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
// Optionally handle notification removal
}
override fun onListenerConnected() {
Log.d("NB", "MyNotificationListenerService.onListenerConnected")
}
}
当我按“播放”时,我确实收到了日志:
MainActivity.onCreate
MyNotificationListenerService.onCreate
MyNotificationListenerService.onStartCommand
但是当我的手机收到通知时,
MyNotificationListenerService.onNotificationPosted
没有被呼叫。
我错过了什么?
正如评论中Mike M.所建议的,这不是你自己开始的。
用户必须手动将您的应用程序启用为监听器,然后您的Service将由系统自动启动。
可以将用户引导到屏幕,以便他们使用
startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))
启用它。
删除启动服务的逻辑和所有前台相关代码使其工作:
AndroidManifest.xml
:
<application>
<!-- ... -->
<service
android:name=".MyNotificationListenerService"
android:exported="false"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
MainActivity.kt
:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyNotificationListenerTheme {
var isServiceRunning by remember { mutableStateOf(isServiceRunningInForeground()) }
Scaffold { innerPadding ->
Surface(
modifier = Modifier.padding(innerPadding),
color = MaterialTheme.colorScheme.background
) {
// Your UI content
}
}
}
}
}
}
MyNotificationListenerService.kt
:
class MyNotificationListenerService : NotificationListenerService() {
override fun onCreate() {
super.onCreate()
Log.d("NB", "MyNotificationListenerService.onCreate")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("NB", "MyNotificationListenerService.onStartCommand")
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
Log.d("NB", "MyNotificationListenerService.onBind")
return super.onBind(intent)
}
override fun onDestroy() {
Log.d("NB", "MyNotificationListenerService.onDestroy")
return super.onDestroy()
}
override fun onNotificationPosted(sbn: StatusBarNotification) {
val text = sbn.notification?.extras?.getString("android.text");
Log.d("NB", "MyNotificationListenerService.onNotificationPosted - text: $text")
super.onNotificationPosted(sbn)
}
override fun onNotificationRemoved(sbn: StatusBarNotification) {
// Optionally handle notification removal
}
override fun onListenerConnected() {
Log.d("NB", "MyNotificationListenerService.onListenerConnected")
}
}