Skip to content

feat(@capacitor/local-notifications): Support largeIcon from local file/URI (file://, content://) #2464

@kstruempf

Description

@kstruempf

Feature Request

Plugin

@capacitor/local-notifications

Description

On Android, the largeIcon option currently only supports referencing drawable resource names (e.g. "icon_name"). This makes it hard/impossible to show dynamic images in local notifications when those images are downloaded/user-specific and cached locally on the device (e.g. file://... paths or content://... URIs).

On iOS, similar use cases can be handled via attachments pointing to local file URLs. On Android, there is no equivalent way in the plugin to provide a local file/URI for largeIcon (or an expanded image style), even though the native Android notification API supports setting a bitmap via NotificationCompat.Builder.setLargeIcon(Bitmap).

Related: #430

Platform(s)

Android

Preferred Solution

Add support for providing a local file path / URI for the notification large icon in a backwards-compatible way.

Option A (backwards-compatible, no API change):
Continue accepting largeIcon: string, but interpret it as:

  • If largeIcon is a resource name (current behavior), resolve drawable by name.
  • If largeIcon looks like a local path/URI:
    • file://... or absolute /... path → decode bitmap from file path
    • content://... → open stream via ContentResolver and decode bitmap
    • call NotificationCompat.Builder.setLargeIcon(bitmap)

Option B (explicit API):
Introduce a new field (e.g. largeIconPath / largeIconUrl) for Android to avoid overloading semantics, while keeping existing largeIcon behavior as-is.

Alternatives

  • Pre-bundle images as Android drawables and reference them by name. This only works for static build-time assets and does not work for downloaded/dynamic images.

Additional Context

Native implementation sketch (Android):

val value = largeIconString
val bmp: Bitmap? = when {
  value.startsWith("content://") -> context.contentResolver
    .openInputStream(Uri.parse(value))
    ?.use { BitmapFactory.decodeStream(it) }

  value.startsWith("file://") -> BitmapFactory.decodeFile(Uri.parse(value).path)

  value.startsWith("/") -> BitmapFactory.decodeFile(value)

  else -> null
}

if (bmp != null) {
  builder.setLargeIcon(bmp)
} else {
  // existing behavior: resolve drawable by name
  resolveDrawableByName(value)?.let { builder.setLargeIcon(it) }
}

Notes:

  • Consider downsampling/scaling to avoid large allocations for big images.
  • content:// handling may require appropriate permissions depending on how the URI was obtained.

Related issue:

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions