If you're like 99.9999% of other developers, you're using UserDefaults in an app.

And because you do that, you'll see this message when you upload your next build to the App Store.

Here's what to do about it…

First, read the documentation:

https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api

The section for UserDefaults is the last one (saving the best for last, of course!)

Describing use of required reason API | Apple Developer Documentation

Ensure your use of covered API is consistent with policy.

Apple Developer Documentation

You'll need to add a new file to your Xcode project. Make sure the PrivacyInfo.xcprivacy file is included in the target (so that it can be extracted after you upload to the App Store).

The documentation here explains how to create the file:

https://developer.apple.com/documentation/bundleresources/privacy_manifest_files#4284009

Privacy manifest files | Apple Developer Documentation

Describe the data your app or third-party SDK collects and the reasons required APIs it uses.

Apple Developer Documentation

The format of the XML in the file isn't obvious. There's a lot of talk about keys for types and description, but the hierarchy wasn't clear to me.

Here's where I landed on the file: https://gist.github.com/chockenberry/2c1c829dba9c7f34c9a7e8e04335be42

NOTE: This file assumes that you only use UserDefaults in the app. If you're using an app group for an extension or whatever, the “CA92.1" won't fly. Read the docs I mentioned earlier!

PrivacyInfo.xcprivacy sample

PrivacyInfo.xcprivacy sample. GitHub Gist: instantly share code, notes, and snippets.

Gist

Also note that this PrivacyInfo.xcprivacy is only for UserDefaults. You may (and probably!) have other APIs you need to declare.

This is a nice little shell script that helps you find the culprits (before the App Store can complain about them):

https://github.com/Wooder/ios_17_required_reason_api_scanner

GitHub - Wooder/ios_17_required_reason_api_scanner: A simple shell script collection to scan your Xcode Swift project for required reason API usage to ensure privacy compliance and to simplify the creation of privacy manifests.

A simple shell script collection to scan your Xcode Swift project for required reason API usage to ensure privacy compliance and to simplify the creation of privacy manifests. - Wooder/ios_17_requi...

GitHub

It sure would have been nice for Apple to document the most widespread use case for privacy.

The motivation here is excellent: it's an effort to reduce the fingerprinting that shithead developers like to do. I'm all for that.

But making me work to figure it all out? And making every other developer who's used UserDefaults do the same thing?

Come on, that's low hanging fruit!

Apple folks: while you're updating these PrivacyInfo.xcprivacy docs, how about putting in some information about how this affects macOS and your other platforms? There's nothing to indicate that it's iOS-only or not at this point.

Also: thanks to @brentsimmons for pointing me in the right direction for a lot of this stuff.

FIN

Just discovered this as a note at the end of one of the documents:

> You only need to supply NSPrivacyAccessedAPITypes for apps and third-party SDKs on iOS, iPadOS, tvOS, visionOS, and watchOS.

We regret the error, but how about putting it front and center?

@chockenberry Yeah, while I was reading what you sent, I thought it's about the SDKs, not apps 🤔

But definitely not clear enough! Especially in combination with app rejection!

@chockenberry also, how about a built in Xcode warning for every call I’m making that I need to document. I mean, the email I got listing the exact dame same error three times is a nice clue that I have 3 items I need to document, but I wasn’t really in the mood for a scavenger hunt.

@jolson @chockenberry
And Rotten Fruit cares about your mood why?

Any indications over the last couple of years that Apple ever cared for its developer chattel?

(A couple of people have pointed out to me that Apple is not a classical case of #enshitification because, well, they simply never cared for their business partners.)

@chockenberry I do not trust these self assessments (also with the data collection labels). If I would be fingerprinting, I just wouldn't declare it or hide it behind bullshit test.

@ernstb It’s my understanding that these APIs aren’t going to be enabled unless you declare them.

And if you make the declaration and it doesn’t match the privacy label, that will be a problem, too.

@chockenberry woof. That’s how I pass data to my widgets. Will give this a read later. Thanks for the info.
@chockenberry You’ll also need to include the privacy manifest file in all the relevant extensions, as I learned the hard way.
@adam Oh good one! It's becoming pretty clear that this file is as ubiquitous as Info.plist.
@chockenberry I was banging my head today trying to figure out why it wasn't picked up by the App Store. I definitely didn't embed it into the target, will try again doing that. Thanks for the tip!
@chockenberry What happens when you use a package with an .xcprivacy file and your app has one. Are they merged? Evaluated as a group?
@chockenberry Does this popup an alert like photo library or GPS access? I’m all for data usage disclosure but HOLY SH*T!
@GaryAsh I have no idea how it will surface in the system UI.
@chockenberry Thanks, a millions for your write-ups and links!
@chockenberry Thank you for this thread, it was glorious.
@chockenberry thanks for this info. A big time saver
@chockenberry I have the same doubt as when they announced this on the WWDC: or they have a very clever idea about using this in the future for something I cannot foresee or this is the most absurd thing the Apple Privacy team has ever done 🤔
@chockenberry thank you for creating ipulse. It’s one of my all time favorite daily use apps!

@chockenberry Thanks for writing this thread.

It begs the question: if App Store static analyzer can notice that you miss the manifest for any number of APIs — why isn't there an option in Xcode to do the same and generate the file?

@chockenberry Thanks for the thread explaining it and the example code 🤗
@chockenberry thank you for putting this together, I appreciate it.
@chockenberry yes I am like 99.9999% of other developers! Thanks for taking the time to write up what we need to do 🙏