The Lineup Is Get the app
← Blog

Xcode 27 silently drops your camera usage string

By Vivek Tanna · Published November 10, 2026

In September I stashed some work and saw a change to Info.plist that I hadn't made. The keys had been re-sorted alphabetically, which I didn't care about. NSCameraUsageDescription was gone, which I cared about a lot.

The Lineup Is uses the camera for one thing: scanning a QR code to pair the app with a physical display. That flow calls AVCaptureDevice.requestAccess(for: .video). Without a camera usage string, iOS terminates the app on that call. App Review rejects the build too. Nothing in the build or the test suite fails when the key goes missing, so the first person to find out is whoever taps Scan.

What happened

Xcode 27 rewrites the source Info.plist for the app target. It re-sorts the keys and drops NSCameraUsageDescription. I first assumed it was a one-off from opening the project in the new Xcode, so I restored the file with git checkout and moved on.

It came back the same day. This time I hadn't opened the project at all. Plain command-line xcodebuild runs had done it. So this isn't something you trip once during an upgrade. Any build can do it, and it doesn't announce itself.

I don't know why Xcode decides that key can go. I only know that it does, and that the deletion is silent.

Why it's easy to miss

  • The build succeeds. A missing usage string isn't a build error.
  • Tests pass. Unless a test actually requests camera access on a device, nothing touches the key.
  • The diff is noisy. When a whole plist gets re-sorted, a single deleted key hides among a lot of moved lines.
  • It only shows up at runtime, on the one screen that needs the camera.

I caught it only because a stash showed a file I hadn't edited. A habit of committing everything that changed would have carried the deletion along with my real work.

Check the built Info.plist, not the source

The source file is what Xcode edits. The built file is what ships. Those are not the same thing, and the built one is the only one that matters to iOS and App Review. After a build, read the key straight out of the app bundle:

/usr/libexec/PlistBuddy -c "Print :NSCameraUsageDescription" \
  "path/to/YourApp.app/Info.plist"

If it prints your string, you're fine. If it prints Print: Entry, ":NSCameraUsageDescription", Does Not Exist, the build you're about to ship will crash the moment it asks for the camera.

You can find the built app under your DerivedData Build/Products folder, or in the archive under Products/Applications. The same check works for any other usage string you depend on: microphone, location, photo library.

The fix: put the key in build settings

Modern Xcode projects can generate the Info.plist from build settings. With GENERATE_INFOPLIST_FILE = YES, any setting named INFOPLIST_KEY_<Key> becomes a key in the built plist, merged with whatever your source Info.plist still contains.

So I moved the camera string out of the file Xcode keeps rewriting and into the target's build settings, for both Debug and Release:

GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Info.plist;
INFOPLIST_KEY_NSCameraUsageDescription = "Scan the QR code shown on your display to pair it.";

In the Xcode UI this is the target's Build Settings tab, under Info.plist Values. Set it at the target level and check both configurations. A key that exists only in Debug will pass every local test and still ship without it.

Then I verified it the hard way. I built from a tree where Xcode had already stripped the key from the source Info.plist, ran the PlistBuddy check on the built app, and it printed the string. The source file can lose the key now and the shipped app still has it.

What I do now

  • Every privacy usage string lives in build settings, not only in the source plist.
  • I don't trust a clean source diff as proof the key is there. I check the built plist.
  • When I see a plist change I didn't make, I read it line by line instead of discarding it as Xcode noise. Re-ordering is harmless. A missing key is not.

The fix is one build setting. The real risk was that nothing would have told me. If your app asks for any permission, run the PlistBuddy check on your next Xcode 27 build before you upload it.

I build The Lineup Is, an iPhone app that tells you which games are worth watching.


Get The Lineup Is on iOS — free — or see tonight's best games ranked right now. More from the blog.

Best games tonight

  • All sports
  • Football
  • Basketball
  • Baseball
  • Hockey
  • Soccer
  • Tennis
  • Golf
  • Motorsports

Top leagues

  • NFL
  • College Football
  • NBA
  • WNBA
  • College Basketball
  • MLB
  • NHL
  • Premier League
  • La Liga
  • MLS
  • Champions League
  • ATP
  • WTA
  • PGA Tour
  • Formula 1
  • NASCAR

How we compare

  • All comparisons
  • vs ESPN
  • vs Apple Sports
  • vs theScore
  • vs Sofascore
  • vs Fixtured
  • vs FotMob
  • vs SportsRec
  • vs Nailbiter
  • vs RateGame
  • Thuuz alternative

Guides

  • Close-game alerts
  • Spoiler-free sports
  • Scores on the lock screen

Learn

  • How the score works
  • About
  • Blog
  • Press
The Lineup Is
Best games tonight · How it works · About · Feed · support@thelineup.is · Privacy · Terms and Conditions