Skip to content

[iOS/Mac] Fix MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on iOS#34695

Closed
devanathan-vaithiyanathan wants to merge 1 commit intodotnet:mainfrom
devanathan-vaithiyanathan:fix-34661
Closed

[iOS/Mac] Fix MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on iOS#34695
devanathan-vaithiyanathan wants to merge 1 commit intodotnet:mainfrom
devanathan-vaithiyanathan:fix-34661

Conversation

@devanathan-vaithiyanathan
Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Issue Details

In the latest .NET MAUI, calling CapturePhotoAsync() throws an UnauthorizedAccessException.

Root Cause

In the CapturePhotoAsync method, EnsureGrantedAsync is called for the PhotosAddOnly permission.
PhotosAddOnly is used to write images to the photo library, which is not required for CapturePhotoAsync.

Description of Change

Removed the PhotosAddOnly permission check from the CapturePhotoAsync method.

Regarding test case

Capturing an image is not possible in a test.

Issues Fixed

Fixes #34661

Tested the behavior in the following platforms.

  • Android
  • Windows
  • iOS
  • Mac
Before After
iOS
Before.mov
iOS
After.mov

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34695

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34695"

@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 28, 2026

🚦 Gate — Test Verification

📊 Expand Full Gateb2f1f4e · fix added

Gate Result: ❌ FAILED

Platform: ios


@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 28, 2026

🤖 AI Summary

📊 Expand Full Reviewb2f1f4e · fix added
🔍 Pre-Flight — Context & Validation

Issue: #34661 - MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on iOS despite successfully being Granted Access
PR: #34695 - [iOS/Mac] Fix MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on iOS
Platforms Affected: iOS, macCatalyst
Files Changed: 1 implementation (MediaPicker.ios.cs), 0 test

Key Findings

  • Root cause: PhotoAsync() in MediaPicker.ios.cs calls EnsureGrantedAsync<Permissions.PhotosAddOnly>() when !pickExisting (capture path) on iOS < 14. PhotosAddOnly requires NSPhotoLibraryAddUsageDescription in Info.plist, which users may not include (it's for saving to library, not for capturing).
  • Regression introduced: Since .NET 10, users who don't include NSPhotoLibraryAddUsageDescription in Info.plist get UnauthorizedAccessException when calling CapturePhotoAsync(), despite having granted camera permission.
  • Fix: Remove the 5-line PhotosAddOnly permission check from the else-branch of PhotoAsync() (the UIImagePickerController path used for iOS < 14 or camera capture).
  • Competing PR: PR Removed PhotosAddOnly permission request within MediaPicker.ios #34287 (also fixing PhotosAddOnly) was merged to inflight/current branch on 2026-03-22. It is NOT yet in main. PR [iOS/Mac] Fix MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on iOS #34695 targets main and is an independent community fix for the same root cause.
  • Gate failed: Gate ❌ FAILED — PR author noted "Capturing an image is not possible in a test." No test files were added.
  • PhotosAsync not affected: The PhotosAsync (multi-photo) method does not have the same PhotosAddOnly check.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34695 Remove EnsureGrantedAsync<Permissions.PhotosAddOnly>() from capture path in PhotoAsync() ❌ Gate FAILED (no tests) MediaPicker.ios.cs (5 line deletion) Original PR; 1 file, minimal change

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (opus-4.6) Wrap check in try- swallows PermissionException PASS (283/283 unit tests) MediaPicker.ios.cs (+10/-1) Swallowing exceptions is a code smell; test limitation: unit tests target netstandard
2 try-fix (sonnet-4.6) Move into video-capture-only path PASS (283/283 unit tests) MediaPicker.ios.cs (+4/-5) Still video capture via UIImagePickerController also doesn't save to gallery
3 try-fix (gpt-5.3-codex) Status-gated: CheckStatusAsync first, only enforce if Granted/Limited PASS (283/283 unit tests) MediaPicker.ios.cs (+2/-1) Still requires permission if status happens to be Granted; doesn't fix root cause
4 try-fix (gpt-5.4) Centralize into helper PASS (283/283 unit tests) MediaPicker.ios.cs (+29/-28) Larger refactor; still removes PhotosAddOnly for photo capture; both PhotoAsync/PhotosAsync benefit
5 try-fix cross-poll (opus) Info.plist guard: before check PASS (283/283 unit tests) MediaPicker.ios.cs (+1/-1) Preserves opt-in behavior but preserves a semantically wrong check
6 try-fix cross-poll (sonnet) Fix at return when key absent layer PASS (283/283 unit tests) MediaPicker.ios.cs (+2), Permissions.ios.tvos.macos.cs (+12/-3) Most principled; benefits all callers; but too broad for targeted bug fix
PR PR #34695 Remove EnsureGrantedAsync<PhotosAddOnly> entirely (5-line Gate FAILED (no tests added) MediaPicker.ios.cs (5 deletion) Original PR; identical approach to already-merged PR #34287 on inflight/current deletion)

Cross-Pollination

Model Round New Ideas? Details
became Attempt 5
became Attempt 6
gpt-5.3-codex 2 Yes Post-capture optional save (N/ CapturePhotoAsync doesn't save to gallery)
gpt-5.4 2 No NO NEW IDEAS
claude-opus-4.6 3 No NO NEW confirmed simple removal is the correct fix
claude-sonnet-4.6 3 Yes SaveToPhotoAlbum feature addition (out of scope; similar SaveToGallery already in development)
gpt-5.3-codex 3 Yes Narrow try-catch (duplicates Attempt 5 logic without improvement)
gpt-5.4 3 Yes Change camera permission handling (unrelated to PhotosAddOnly bug)

Exhausted: no substantively new approaches remainYes
Selected Fix: PR's fix (simple CapturePhotoAsync never writes to the photo library (returns temp file via GetFileResult); PhotosAddOnly is semantically wrong for this code path. Any alternative that preserves the check adds complexity around an incorrect permission. Confirmed by: (a) claude-opus Round 3 analysis, (b) identical fix already merged to inflight/current via PR #34287.removal)


📋 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE 1 implementation file; no test files; competing PR #34287 identified
Gate ❌ FAILED ios — no tests added; camera capture not automatable
Try-Fix ✅ COMPLETE 6 attempts, all ✅ PASS (unit tests); PR's removal selected as best fix
Report ✅ COMPLETE

Summary

PR #34695 correctly removes an incorrect EnsureGrantedAsync<Permissions.PhotosAddOnly>() call from MediaPicker.CapturePhotoAsync() on iOS. The fix is a clean 5-line deletion targeting MediaPicker.ios.cs. The same fix was independently authored and already merged to the inflight/current branch as PR #34287. The gate failed because no automated tests were added — the PR author notes this is inherent to the scenario (camera capture cannot be automated in tests). Despite the gate failure, the fix quality is correct.

Root Cause

In PhotoAsync() (the implementation backing CapturePhotoAsync), the UIImagePickerController path (else branch, iOS < 14 or camera capture) contained:

if (!pickExisting)
{
    await Permissions.EnsureGrantedAsync<Permissions.PhotosAddOnly>();
}

PhotosAddOnly requires NSPhotoLibraryAddUsageDescription in the app's Info.plist. This key is only needed when an app explicitly saves captured media to the photo library — which CapturePhotoAsync never does (it writes to a temp file and returns a FileResult). Apps that omit NSPhotoLibraryAddUsageDescription (reasonably, since they only want to capture) receive UnauthorizedAccessException from iOS when the permission check runs, even though they have camera permission granted.

Fix Quality

PR's fix is correct — the 5-line deletion is the minimal, targeted change needed. CapturePhotoAsync does not call PHPhotoLibrary.performChanges() or write to the device library anywhere in the code path; the permission check has no semantic justification. Multi-model try-fix exploration confirmed this conclusion:

Concerns Requiring Changes

  1. No tests added — The gate failed. While the PR author notes camera capture is not automatable, there are options:

    • A unit test could be added to Essentials.UnitTests verifying the permission sequence for CapturePhotoAsync (e.g., via mocking or confirming PhotosAddOnly is never in the required permissions list)
    • At minimum, a code comment explaining why PhotosAddOnly is not required here would help prevent future regression
  2. Duplicate PR — PR Removed PhotosAddOnly permission request within MediaPicker.ios #34287 addresses the same root cause and was already merged to inflight/current. The team should clarify whether PR [iOS/Mac] Fix MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on iOS #34695 should target main (since Removed PhotosAddOnly permission request within MediaPicker.ios #34287 is on inflight/current), or whether one of these PRs should be closed in favor of the other.

  3. CaptureVideoAsync review — Attempt 2 surfaced a related question: CaptureVideoAsync uses the same PhotoAsync() path (photo=false, pickExisting=false). The PhotosAddOnly check was also guarded by !pickExisting in that path. Confirm CaptureVideoAsync via UIImagePickerController also doesn't need PhotosAddOnly (video capture also returns a temp file).


@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Mar 28, 2026
@sheiksyedm
Copy link
Copy Markdown
Contributor

This is duplicate PR of #34287, hence closing this PR.

@sheiksyedm sheiksyedm closed this Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-essentials-mediapicker community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MediaPicker.CapturePhotoAsync() fails with UnauthorisedAccessException on IOS despite successfully being Granted Access

5 participants