· 2 min read

Apple rejected my privacy manifest. The problem was a CocoaPod I never added.

Apple Review rejected one of my apps last month for the same reason it had rejected three others before it: a missing NSPrivacyAccessedAPI declaration in PrivacyInfo.xcprivacy. The reviewer copy was the standard wall of guideline text, ending with “the following API was used without a declared reason: file timestamp APIs.”

I didn’t use file timestamp APIs.

$ grep -rn "creationDate\|modificationDate\|attributesOfItem" \
    --include="*.swift" --include="*.m" --include="*.mm" .
# (no results)

I went looking in Pods/. Specifically: Pods/<every-pod-name>/**.

$ grep -rn "attributesOfItem\|file.*Date" Pods/ --include="*.m" --include="*.swift"
Pods/SomeAnalyticsSDK/Sources/Diagnostic/FileMetricsCollector.m: ... attributesOfItemAtPath:

There it was. An analytics SDK I’d added two minor versions ago — for crash-free-session metrics, never to actually use the file APIs. But the SDK quietly initialized a FileMetricsCollector on launch, and that file was calling attributesOfItemAtPath: to collect “diagnostic” data.

That call is tracked under NSPrivacyAccessedAPICategoryFileTimestamp. Apple’s static scanner doesn’t care that I didn’t write the code. The binary contains the symbol, my privacy manifest needs to declare it.

The fix

Add the entry to my own PrivacyInfo.xcprivacy:

<key>NSPrivacyAccessedAPITypes</key>
<array>
  <dict>
    <key>NSPrivacyAccessedAPIType</key>
    <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
    <key>NSPrivacyAccessedAPITypeReasons</key>
    <array>
      <string>C617.1</string> <!-- Inside app or group container -->
    </array>
  </dict>
</array>

Resubmit. Approved on round two. 36 hours total cycle time.

What I’d tell past me

Three checks I now run before every submission:

  1. Grep your own code for the API list Apple publishes for each category. If you don’t use it, move to step 2.
  2. Grep the entire Pods/ directory for the same calls. Find the offending SDK by file path, look up which NSPrivacyAccessedAPICategory* it maps to.
  3. Cross-reference with the SDK’s own privacy manifest if it ships one (most do not). If the SDK declares the API in its own PrivacyInfo.xcprivacy, you don’t need to in yours. If it doesn’t, you do.

This is mechanical. There’s no judgment call. So I automated it as apple-presubmit-audit — 70+ App Store Review checks before you hit Submit, and the privacy-manifest crawler walks both your sources and your Pods/ tree.

If you’ve shipped more than ten iOS apps you’ve probably been bitten by this specific class of bug at least twice. It’s the cleanest example of “Apple’s review is a static analyzer, and your CocoaPod tree is in scope.”

If you have a worse one, tell me on Bluesky. I’m collecting these.