Skip to content

Camera Plugin: iOS View Corruption 1st time run #2425

@metalaureate

Description

@metalaureate

Bug Description

After returning from the iOS camera picker (PHPickerViewController), the entire app view remains in a corrupted visual state - appearing darkened/dimmed and "pushed back" as if behind an invisible modal, even though the app remains functionally operational.

Environment

  • Capacitor: 7.0.0
  • @capacitor/camera: 7.0.2
  • Ionic Framework: 8.6.2 (Vue)
  • Platform: iOS (tested on physical device)
  • iOS Version: 18.7
  • Device: iPhone 15
Image

Steps to Reproduce

  1. Call Camera.getPhoto() with any source (Camera or Photos)
  2. iOS native camera picker (PHPickerViewController) opens
  3. Cancel the picker by tapping "Cancel" button
  4. Observe that app view is now visually corrupted (darkened/pushed back appearance)

Minimal Reproduction Code

import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';

const testCamera = async () => {
  try {
    const photo = await Camera.getPhoto({
      quality: 90,
      allowEditing: false,
      resultType: CameraResultType.Uri,
      source: CameraSource.Camera,
    });
    // Success - works fine
  } catch (error: any) {
    // Error thrown correctly: "User cancelled photos app"
    // BUT: View is now visually corrupted
  }
};

Expected Behavior

After canceling the camera picker, the app should return to its normal visual state.

Actual Behavior

After canceling, the app view appears:

  • Darkened/dimmed
  • "Pushed back" as if behind an invisible modal
  • But remains functionally operational (can click buttons, navigate, etc.)

Investigation Results

1. Console Error After Cancel

PHPickerViewControllerDelegate_Private doesn't respond to _pickerDidPerformCancelAction:
ERROR: User cancelled photos app
ERROR: <ion-modal> must be used inside ion-content.

KEY ERROR: PHPickerViewControllerDelegate_Private doesn't respond to _pickerDidPerformCancelAction:

This is the smoking gun - the Capacitor Camera plugin's delegate is missing the private cancel action handler, causing iOS to fail proper cleanup of the PHPickerViewController dismissal.

2. First-Time Only Behavior

!!!: This bug only occurs on the first camera/gallery use. Subsequent uses work fine.

This suggests:

  • First use: iOS expects _pickerDidPerformCancelAction: delegate method, doesn't find it, corrupts view state
  • Subsequent uses: iOS has already handled the missing delegate and works around it

3. CSS/DOM State Analysis

Comprehensive diagnostics show CSS is completely clean:

  • ✅ No stuck modal classes (modal-open, ion-modal-open, etc.)
  • ✅ No transform/filter/opacity changes
  • ✅ No stuck ion-backdrop elements
  • ✅ All z-index values normal

This confirms the corruption is at iOS native view controller level, not web/CSS.

4. Workarounds That DO Fix It

  • ✅ Opening and closing ANY Ionic modal in the app
  • ✅ Navigating to a different view/page
  • ❌ CSS manipulation does NOT fix it
  • ❌ DOM cleanup does NOT fix it
  • ❌ Programmatically created modals do NOT fix it

5. Happens With Bare Camera.getPhoto()

Tested with absolute minimal code - direct Camera.getPhoto() call with:

  • ❌ No composables
  • ❌ No utilities
  • ❌ No custom modals
  • ❌ No action sheets

Bug still occurs, confirming it's in the Camera plugin itself.

Root Cause Analysis

The Capacitor Camera plugin's PHPickerViewController delegate is missing the _pickerDidPerformCancelAction: method.

Evidence chain:

  1. Critical Error: PHPickerViewControllerDelegate_Private doesn't respond to _pickerDidPerformCancelAction:

    • This is a private delegate method iOS expects for proper PHPickerViewController cleanup
    • When missing, iOS fails to properly dismiss the picker and corrupts the view hierarchy
  2. First-time only behavior:

    • First use: Missing delegate method causes iOS to corrupt view state
    • Subsequent uses: iOS has cached the missing method and handles it differently
  3. Modal error follows: <ion-modal> must be used inside ion-content

    • Happens AFTER the delegate error
    • Suggests iOS is trying to interact with modal system as part of failed cleanup
  4. Only native operations fix it:

    • Ionic modals trigger iOS view controller refresh
    • CSS manipulation cannot fix native view controller corruption

Impact

This makes this plug-in completely unusable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions