Skip to content

bug(android): NullPointerException on ActivityResultLauncher.unregister() in LegacyCameraFlow #75

Description

@MarvinRucinski

Bug Report

Plugin version

@capacitor/camera 8.2.0 – 8.2.3 (still present on main)

Platform

Android (observed on Android 14/15/16)

Current Behavior

Opening the system photo picker via Camera.pickImages() / Camera.getPhoto() can crash the app when returning from the gallery.

Fatal crash:

java.lang.NullPointerException: Attempt to invoke virtual method
'void androidx.activity.result.ActivityResultLauncher.unregister()'
on a null object reference
  at com.capacitorjs.plugins.camera.LegacyCameraFlow.lambda$openPhotos$3 (LegacyCameraFlow.java:349)
  at androidx.activity.result.ActivityResultRegistry.register (ActivityResultRegistry.kt:177)
  at com.capacitorjs.plugins.camera.LegacyCameraFlow.registerActivityResultLauncher (LegacyCameraFlow.java:301)
  at com.capacitorjs.plugins.camera.LegacyCameraFlow.openPhotos (LegacyCameraFlow.java:324)
  at com.capacitorjs.plugins.camera.LegacyCameraFlow.pickImages (LegacyCameraFlow.java:120)
  at com.capacitorjs.plugins.camera.CameraPlugin.pickImages (CameraPlugin.kt:132)

Root cause

In LegacyCameraFlow.openPhotos, the activity-result callback calls pickMultipleMedia.unregister() / pickMedia.unregister() without a null check:

https://github.com/ionic-team/capacitor-camera/blob/main/android/src/main/java/com/capacitorjs/plugins/camera/LegacyCameraFlow.java#L349-L363

ActivityResultRegistry.register() can synchronously invoke the callback when a pending result exists (e.g. after the Activity was destroyed while the Photo Picker was open and later recreated). At that moment the field has not been assigned yet (pickMultipleMedia / pickMedia is still null), so unregister() NPEs.

Note: onDestroy() already null-checks before unregister(), but the callbacks in openPhotos do not.

Expected Behavior

Returning from the gallery after Activity recreation should not crash. Selected images should still be processed when possible.

Reproduction

  1. Capacitor app with @capacitor/camera
  2. Android Developer Options → enable Don't keep activities
  3. Call Camera.pickImages({ quality: 80, limit: 5 }) (or getPhoto / gallery source)
  4. Select photo(s) and return
  5. App crashes with the NPE above

Also reproducible on low-memory devices when the OS kills the Activity while the system Photo Picker is in the foreground.

Proposed Fix

Null-check before unregister in both callbacks (same pattern as onDestroy()):

if (pickMultipleMedia != null) {
    pickMultipleMedia.unregister();
}

if (pickMedia != null) {
    pickMedia.unregister();
}

A slightly more robust approach is to capture the launcher in a local final holder assigned before the callback can run, so unregister always targets the instance created by that register() call.

Related

Previously reported (wrong repo, closed without fix, redirected here):
ionic-team/capacitor-plugins#2537

Additional context

Affects production apps using the deprecated pickImages / getPhoto APIs that still go through LegacyCameraFlow on Android.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions