-
Notifications
You must be signed in to change notification settings - Fork 661
Description
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
Steps to Reproduce
- Call
Camera.getPhoto()with any source (Camera or Photos) - iOS native camera picker (PHPickerViewController) opens
- Cancel the picker by tapping "Cancel" button
- 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:
-
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
-
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
-
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
-
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.