UNPKG

capacitor-notification-reader

Version:

Capacitor plugin to read and persist Android notifications with RoomDB storage

557 lines (556 loc) 16.1 kB
import type { Plugin, PluginListenerHandle } from '@capacitor/core'; /** * Android notification categories */ export declare enum NotificationCategory { ALARM = "alarm", CALL = "call", EMAIL = "email", ERROR = "err", EVENT = "event", LOCATION_SHARING = "location_sharing", MESSAGE = "msg", MISSED_CALL = "missed_call", NAVIGATION = "navigation", PROGRESS = "progress", PROMO = "promo", RECOMMENDATION = "recommendation", REMINDER = "reminder", SERVICE = "service", SOCIAL = "social", STATUS = "status", STOPWATCH = "stopwatch", SYSTEM = "sys", TRANSPORT = "transport", VOICEMAIL = "voicemail", WORKOUT = "workout", UNKNOWN = "unknown" } /** * Android notification styles */ export declare enum NotificationStyle { BIG_TEXT = "BigTextStyle", BIG_PICTURE = "BigPictureStyle", INBOX = "InboxStyle", MESSAGING = "MessagingStyle", MEDIA = "MediaStyle", CALL = "CallStyle", DECORATED_CUSTOM = "DecoratedCustomViewStyle", DECORATED_MEDIA = "DecoratedMediaCustomViewStyle", DEFAULT = "default" } /** * Notification action button */ export interface NotificationAction { /** * Action title/label */ title: string; /** * Base64-encoded icon for the action (if available) */ icon?: string; /** * Whether this action allows remote input (for inline replies) */ allowsRemoteInput: boolean; } /** * Progress information for notifications with progress bars */ export interface NotificationProgress { /** * Current progress value */ current: number; /** * Maximum progress value */ max: number; /** * Whether the progress is indeterminate */ indeterminate: boolean; } /** * Message in a messaging-style notification */ export interface NotificationMessage { /** * Message text */ text: string; /** * Timestamp of the message */ timestamp: number; /** * Sender name */ sender?: string; } /** * Base notification properties common to all notifications */ export interface BaseNotification { /** * The unique database ID of the notification (UUID). */ id: string; /** * The human-readable name of the app that posted the notification. */ appName: string; /** * The package name of the app that posted the notification. */ packageName: string; /** * The title of the notification. */ title?: string; /** * The text content of the notification. */ text?: string; /** * The timestamp when the notification was posted (in milliseconds). */ timestamp: number; /** * Base64-encoded PNG of the notification's small icon (status bar icon). */ smallIcon?: string; /** * Base64-encoded PNG of the notification's large icon. */ largeIcon?: string; /** * Base64-encoded PNG of the app's launcher icon. */ appIcon?: string; /** * Notification category (call, message, email, etc.) */ category?: string; /** * Notification style template used */ style: NotificationStyle; /** * Sub-text shown below the main text */ subText?: string; /** * Additional info text */ infoText?: string; /** * Summary text for expanded notifications */ summaryText?: string; /** * Group key for grouped notifications */ group?: string; /** * Whether this is a group summary notification */ isGroupSummary: boolean; /** * Notification channel ID (Android 8+) */ channelId?: string; /** * Action buttons available on the notification (always an array, may be empty) */ actions: NotificationAction[]; /** * Whether the notification is ongoing (can't be dismissed) */ isOngoing: boolean; /** * Whether the notification auto-cancels when clicked */ autoCancel: boolean; /** * Whether the notification is local only (doesn't bridge to other devices) */ isLocalOnly: boolean; /** * Priority level (-2 to 2, where 0 is default) */ priority: number; /** * Number badge (e.g., unread count) */ number: number; } /** * Big text style notification with expanded text content */ export interface BigTextNotification extends BaseNotification { style: NotificationStyle.BIG_TEXT; /** * The full expanded text content */ bigText?: string; } /** * Big picture style notification with an image */ export interface BigPictureNotification extends BaseNotification { style: NotificationStyle.BIG_PICTURE; /** * Base64-encoded picture shown in expanded view */ bigPicture?: string; /** * Content description for the picture */ pictureContentDescription?: string; } /** * Inbox style notification with multiple lines */ export interface InboxNotification extends BaseNotification { style: NotificationStyle.INBOX; /** * Array of text lines in the inbox */ inboxLines: string[]; } /** * Messaging style notification for chat/messaging apps */ export interface MessagingNotification extends BaseNotification { style: NotificationStyle.MESSAGING; category: NotificationCategory.MESSAGE; /** * Conversation title for group chats */ conversationTitle?: string; /** * Whether this is a group conversation */ isGroupConversation: boolean; /** * Array of messages in the conversation */ messages: NotificationMessage[]; } /** * Progress style notification for downloads, uploads, etc. */ export interface ProgressNotification extends BaseNotification { style: NotificationStyle.DEFAULT; category: NotificationCategory.PROGRESS; /** * Progress information */ progress: NotificationProgress; } /** * Call notification */ export interface CallNotification extends BaseNotification { style: NotificationStyle.CALL | NotificationStyle.DEFAULT; category: NotificationCategory.CALL | NotificationCategory.MISSED_CALL; /** * Caller name */ callerName?: string; } /** * Media playback notification */ export interface MediaNotification extends BaseNotification { style: NotificationStyle.MEDIA | NotificationStyle.DECORATED_MEDIA; category: NotificationCategory.TRANSPORT; } /** * Generic notification that doesn't fit specific patterns */ export interface GenericNotification extends BaseNotification { style: NotificationStyle.DEFAULT | NotificationStyle.DECORATED_CUSTOM; } /** * Union type of all specific notification types. * Use discriminated union on 'style' and 'category' for type narrowing. * * Type narrowing examples: * - For BigTextNotification: check `notification.style === NotificationStyle.BIG_TEXT` * - For BigPictureNotification: check `notification.style === NotificationStyle.BIG_PICTURE` * - For InboxNotification: check `notification.style === NotificationStyle.INBOX` * - For MessagingNotification: check `notification.style === NotificationStyle.MESSAGING` * - For ProgressNotification: check `notification.category === NotificationCategory.PROGRESS` * - For CallNotification: check category is CALL or MISSED_CALL * - For MediaNotification: check style is MEDIA or DECORATED_MEDIA */ export declare type NotificationItem = BigTextNotification | BigPictureNotification | InboxNotification | MessagingNotification | ProgressNotification | CallNotification | MediaNotification | GenericNotification; /** * Result returned by getActiveNotifications. */ export interface GetActiveNotificationsResult { /** * Array of active notifications with type-specific shapes. */ notifications: NotificationItem[]; } /** * Options for getNotifications. */ export interface GetNotificationsOptions { /** * Return notifications whose timestamp is strictly less than this value (in ms). * Use the `timestamp` from the last item of the previous page when paginating. */ cursor?: number; /** * Maximum number of notifications to retrieve. * @default 10 */ limit?: number; /** * Optional filter criteria applied on the stored notifications. */ filter?: NotificationFilter; } /** * Result returned by getNotifications. */ export interface GetNotificationsResult { /** * Array of notifications from the database. */ notifications: NotificationItem[]; } /** * Advanced filters for querying stored notifications. * Each filter is optional and multiple filters are combined with AND logic. */ export interface NotificationFilter { /** * Match notifications whose text contains the provided value (case-sensitive). */ textContains?: string; /** * Match notifications whose title contains the provided value (case-sensitive). */ titleContains?: string; /** * Match notifications whose text contains the provided value (case-insensitive). */ textContainsInsensitive?: string; /** * Match notifications whose title contains the provided value (case-insensitive). */ titleContainsInsensitive?: string; /** * Only return notifications whose `appName` exactly matches one of the supplied names. */ appNames?: string[]; /** * Filter by package name of the posting application. */ packageName?: string; /** * Filter by notification category. */ category?: NotificationCategory | string; /** * Filter by notification style template. */ style?: NotificationStyle | string; /** * Filter for ongoing (non-dismissible) notifications only. */ isOngoing?: boolean; /** * Filter for group summary notifications only. */ isGroupSummary?: boolean; /** * Filter by notification channel ID (Android 8+). */ channelId?: string; /** * Only return notifications posted after this timestamp (in milliseconds). * Creates a lower bound for the time range. */ afterTimestamp?: number; /** * Only return notifications posted before this timestamp (in milliseconds). * Creates an upper bound for the time range. */ beforeTimestamp?: number; } /** * Options for importNotifications. */ export interface ImportNotificationsOptions { /** * Array of notification items to import into the database. * Each notification should conform to the NotificationItem type structure. */ notifications: NotificationItem[]; } /** * Information about an installed application. */ export interface InstalledApp { /** * The package name of the app. */ packageName: string; /** * The human-readable name of the app. */ appName: string; /** * Base64-encoded PNG of the app's launcher icon. */ appIcon?: string; /** * Whether the app is a system app. */ isSystemApp: boolean; } /** * Result returned by getInstalledApps. */ export interface GetInstalledAppsResult { /** * Array of installed applications with their metadata. */ apps: InstalledApp[]; } export interface NotificationReaderPlugin extends Plugin { /** * Gets all active notifications from the notification listener service. * * @returns Promise resolving with the list of active notifications * @throws Error if notification listener service is not connected or permission is not granted * @since 1.0.0 * @platform Android */ getActiveNotifications(): Promise<GetActiveNotificationsResult>; /** * Opens the system settings page to allow the user to grant notification access * to the app. The promise resolves when the user returns from settings with * the current permission status. * * @returns Promise resolving with an object indicating if permission was granted * @throws Error if unable to open settings * @since 1.0.0 * @platform Android */ openAccessSettings(): Promise<{ enabled: boolean; }>; /** * Checks if the app has notification access enabled. * * @returns Promise resolving with an object indicating if access is enabled * @since 1.0.0 * @platform Android */ isAccessEnabled(): Promise<{ enabled: boolean; }>; /** * Retrieves notifications from the persistent Room database with optional * filtering and cursor-based pagination. Notifications are cached when they are posted and can be * queried later even after dismissal from the notification drawer. * * @param options - Cursor, limit, and filtering options * @returns Promise resolving with the list of notifications from the database * @since 1.0.0 * @platform Android */ getNotifications(options?: GetNotificationsOptions): Promise<GetNotificationsResult>; /** * Deletes all notifications from the database. * This does not affect notifications in the system notification drawer. * * @returns Promise resolving when all notifications have been deleted * @since 1.0.0 * @platform Android */ deleteAllNotifications(): Promise<void>; /** * Gets the total count of notifications stored in the database. * This count includes all notifications regardless of their status or type. * * @returns Promise resolving with an object containing the total count * @since 1.0.0 * @platform Android */ getTotalCount(): Promise<{ count: number; }>; /** * Imports an array of notifications into the database. * This method is useful for restoring previously exported notifications, * migrating data from another source, or bulk-importing notification data. * * Each notification will be inserted using REPLACE strategy, meaning if a * notification with the same ID already exists, it will be updated. * * @param options - Object containing the array of notifications to import * @returns Promise resolving when all notifications have been imported * @throws Error if the notifications array is missing or if an error occurs during import * @since 1.0.0 * @platform Android * * @example * ```typescript * const notificationsToImport = [ * { * id: 'notification-1', * appName: 'Example App', * packageName: 'com.example.app', * title: 'Test Notification', * text: 'This is a test', * timestamp: Date.now(), * style: NotificationStyle.DEFAULT, * actions: [], * isGroupSummary: false, * isOngoing: false, * autoCancel: true, * isLocalOnly: false, * priority: 0, * number: 0 * } * ]; * * await NotificationReader.importNotifications({ * notifications: notificationsToImport * }); * ``` */ importNotifications(options: ImportNotificationsOptions): Promise<void>; /** * Retrieves a list of all installed applications on the device. * Returns app name, package name, app icon, and whether it's a system app. * * @returns Promise resolving with the list of installed apps * @since 1.0.0 * @platform Android * * @example * ```typescript * const { apps } = await NotificationReader.getInstalledApps(); * const userApps = apps.filter(app => !app.isSystemApp); * console.log('User apps:', userApps.map(app => app.appName)); * ``` */ getInstalledApps(): Promise<GetInstalledAppsResult>; /** * Listen for notifications that are posted while the listener service is running. * Fires with the freshly-captured notification payload. */ addListener(eventName: 'notificationPosted', listenerFunc: (notification: NotificationItem) => void): Promise<PluginListenerHandle>; }