0

I am trying to make a React Native Expo Module to read the notifications on my device. I have tried other StackOverflow answers (this and this) and I haven't been able to get it to work. I setup the NotificationListenerService and am trying to use the getActiveNotifications() method but it is returning an empty array. Here is the relevant source code:

ReadNotificationsModule.kt:

package expo.modules.readnotifications

import android.util.Log
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition

import android.content.Intent
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat

class ReadNotificationsModule : Module() {
  private lateinit var notificationListenerService: ReadNotificationsService

  // Each module class must implement the definition function. The definition consists of components
  // that describes the module's functionality and behavior.
  // See https://docs.expo.dev/modules/module-api for more details about available components.
  override fun definition() = ModuleDefinition {
    // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
    // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
    // The module will be accessible from `requireNativeModule('ReadNotifications')` in JavaScript.
    Name("ReadNotifications")

    OnCreate {
      notificationListenerService = ReadNotificationsService()
    }

    // Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
    Constants(
      "PI" to Math.PI
    )

    // Defines event names that the module can send to JavaScript.
    Events("onChange")

    // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
    Function("hello") {
      "Hello world! "
    }

    Function("getNotifications") {
      notificationListenerService.getActiveNotifications()
    }

    Function("getPermission") {
      // Log.wtf(TAG, "getPermission")

      // val i = Intent();
      // i.setAction(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
      // i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      // i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
      // i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
      // startActivity(i);

      notificationListenerService.getPermission(appContext)
    }

    Function("checkPermissions") {
      notificationListenerService.checkPermissions(appContext)
    }

    // Defines a JavaScript function that always returns a Promise and whose native code
    // is by default dispatched on the different thread than the JavaScript runtime runs on.
    AsyncFunction("setValueAsync") { value: String ->
      // Send an event to JavaScript.
      sendEvent("onChange", mapOf(
        "value" to value
      ))
    }

    // Enables the module to be used as a native view. Definition components that are accepted as part of
    // the view definition: Prop, Events.
    View(ReadNotificationsView::class) {
      // Defines a setter for the `name` prop.
      Prop("name") { view: ReadNotificationsView, prop: String ->
        Log.d("TAG", prop)
      }
    }
  }
}

ReadNotificationsService.kt:

package expo.modules.readnotifications

import android.util.Log

import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.content.Intent
import android.os.IBinder
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import expo.modules.kotlin.AppContext

class ReadNotificationsService : NotificationListenerService() {
  private val TAG = "ReadNotificationsService"
  private var ready = false

  override fun onListenerConnected() {
    Log.wtf(TAG, "onListenerConnected")
    ready = true
  }

  override fun onListenerDisconnected() {
    Log.wtf(TAG, "onListenerDisconnected")
    ready = false
  }

  //check notification access setting is enabled or not  
  fun checkPermissions(context: AppContext): String {
    val packageName = context.reactContext?.getPackageName()
    println("packageName: " + packageName)
    val enabledPackages = NotificationManagerCompat.getEnabledListenerPackages(this)
    if (enabledPackages.contains(packageName)) {
      return "authorized"
    } else {
      return "denied"
    }
  }

  fun getPermission(context: AppContext) {
    Log.wtf(TAG, "getPermission")
    // val intent = Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS")
    // startActivity(intent)
    // startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
    // startActivity(Intent(Settings.ACTION_SETTINGS))

    val i = Intent();
    i.setAction(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
    i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    context.reactContext?.startActivity(i);
  }

  override fun onNotificationPosted(sbn: StatusBarNotification) {
    Log.wtf(TAG, "onNotificationPosted")
    Log.wtf(TAG, sbn.toString())
  }

  override fun onNotificationRemoved(sbn: StatusBarNotification) {
    Log.wtf(TAG, "onNotificationRemoved")
    Log.wtf(TAG, sbn.toString())
  }

  override fun onBind(intent: Intent): IBinder? {
    return super.onBind(intent)
  }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="expo.modules.readnotifications">

  <uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />

  <application>
    <service android:name=".ReadNotificationsService"
      android:enabled="true"
      android:exported="false"
      android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
      <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
      </intent-filter>
      <meta-data
        android:name="android.service.notification.default_filter_types"
        android:value="conversations|alerting|ongoing|silent">
      </meta-data>
    </service>
  </application>

</manifest>
Jwiggiff
  • 95
  • 1
  • 8

0 Answers0