ITMS-91064: NSPrivacyTracking and NSPrivacyTrackingDomains must agree in every privacy manifest (true needs domains, domains need true); check, scan and privacy-manifest fail on either mismatch with the exact ITMS text; App Privacy tracking no longer demands the app manifest's true: SDK manifests that declare tracking (Pods, frameworks, SwiftPM, Carthage, plugins, the built IPA) are info, known tracking SDKs info, else a warning; privacy-manifest --propose writes true only with appPrivacy.trackingDomains; apple upload checks every manifest in the IPA (XML or binary) before any network call, apple build after the export. Pitfall 29
This commit is contained in:
parent
b7bfe89151
commit
c8213be2b6
19 changed files with 631 additions and 44 deletions
|
|
@ -7,7 +7,8 @@ description: Add and check Apple privacy manifests (PrivacyInfo.xcprivacy) for a
|
|||
|
||||
`storebound scan` runs the same checks as part of its report (no manifest, undeclared required-reason APIs, SDKs older than their first manifest version) and proposes NSPrivacyTracking and the collected data types from the detected SDKs.
|
||||
|
||||
Scan: `storebound privacy-manifest --ios ios/App` (local, no credentials). Capacitor / Cordova / React Native plugins
|
||||
Scan: `storebound privacy-manifest --ios ios/App` (local, no credentials; `--propose` prints the app manifest
|
||||
storebound proposes). Capacitor / Cordova / React Native plugins
|
||||
live outside the iOS folder; they are found the way Node resolves them: the dependencies of the app's package.json
|
||||
(next to capacitor.config) in the node_modules there and in every folder above it up to the repo root (so a monorepo's
|
||||
`apps/native/node_modules` works), workspace packages (package.json `workspaces`, Bun / npm / yarn), local SwiftPM
|
||||
|
|
@ -15,6 +16,10 @@ packages (Capacitor 8's CapApp-SPM `Package.swift`), Pods and SwiftPM checkouts.
|
|||
cannot find. Exit 1 when something blocks upload.
|
||||
|
||||
## What Apple checks at upload
|
||||
- **ITMS-91064 Invalid tracking information**: "ITMS-91064: Invalid tracking information - A PrivacyInfo.xcprivacy file contains invalid tracking information at the following path: "PrivacyInfo.xcprivacy". NSPrivacyTracking must be true if NSPrivacyTrackingDomains isn't empty. Keys and values in your app's privacy manifests must be valid." Raised for
|
||||
true with an empty list as well as for domains with false, in the app's manifest or any SDK's. `storebound
|
||||
apple upload` checks every manifest in the IPA (app root, Frameworks, bundles; XML or binary) before sending it,
|
||||
`apple build` after the export, `check` / `scan` / `privacy-manifest` in the project.
|
||||
- **ITMS-91053 Missing API declaration**: the binary uses a required-reason API and no manifest in the app or in the
|
||||
SDK that calls it declares the category with a reason.
|
||||
- **ITMS-91061 Missing privacy manifest**: an SDK from Apple's list of commonly used SDKs (Firebase, Google utilities,
|
||||
|
|
@ -31,9 +36,14 @@ cannot find. Exit 1 when something blocks upload.
|
|||
- `NSPrivacyAccessedAPICategorySystemBootTime` + `35F9.1` (elapsed time between events)
|
||||
- `NSPrivacyAccessedAPICategoryDiskSpace` + `E174.1` (check space before writing)
|
||||
Pick the reason that is true; read Apple's reason list ("Describing use of required reason API") if unsure.
|
||||
3. Tracking: `NSPrivacyTracking` true only if the app tracks (ad SDK with IDFA after ATT); then list
|
||||
`NSPrivacyTrackingDomains` the SDK docs name. Keep it consistent with App Privacy "used for tracking" and the ATT
|
||||
prompt (`store-declarations`).
|
||||
3. Tracking (ITMS-91064): in every manifest `NSPrivacyTracking` and `NSPrivacyTrackingDomains` must agree: true
|
||||
needs a non-empty list of the domains the code of THAT bundle sends tracking data to, and a non-empty list needs
|
||||
true. When the tracking comes from an SDK (ad network, mediation such as LevelPlay / AppLovin MAX / AdMob,
|
||||
attribution), the SDK's own manifest declares it and the app's manifest says **false**, while App Privacy in App
|
||||
Store Connect still says "used for tracking" and the ATT prompt stays (`store-declarations`). Never set the app's
|
||||
manifest to true with an empty list: Apple refuses the build as Invalid Binary a minute after the upload. Only
|
||||
when the app's own code tracks, list its domains in `appPrivacy.trackingDomains`;
|
||||
`storebound privacy-manifest --ios ios/App --propose` prints the manifest with true only then.
|
||||
4. `NSPrivacyCollectedDataTypes`: what the app itself collects; SDK manifests cover their own collection. Xcode's
|
||||
Privacy Report (Product > Archive > Generate Privacy Report) merges all manifests; compare it with App Privacy.
|
||||
5. SDKs flagged "ships no PrivacyInfo.xcprivacy": update to a version that has one (ad networks and mediation
|
||||
|
|
@ -44,5 +54,8 @@ cannot find. Exit 1 when something blocks upload.
|
|||
- The scan is a text search: it can miss calls inside binary frameworks (their manifest must cover them) and flag a
|
||||
harmless symbol name; confirm before adding a category you do not use.
|
||||
- A manifest must be in the **app target's** Copy Bundle Resources, not only in the project.
|
||||
- `check` saying "tracking declared by the <SDK> manifest" (info) is the correct setup for SDK tracking; a warning
|
||||
that no manifest declares tracking means: check the SDK version ships its manifest (`pod install`, resolve
|
||||
packages), not "set the app's manifest to true".
|
||||
- Static libraries cannot carry a manifest bundle by themselves; the vendor ships a resource bundle or you merge their
|
||||
declarations into the app's manifest as their docs say.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@ CLI: `storebound` (or `bunx storebound` in a project that has it, or `bun <toolc
|
|||
(Advertising Data, Gameplay Content, Customer Support, Environment Scanning, Hands, Head) are answered only here.
|
||||
`scan --write` proposes `collected` + `purposes` for detected types the block does not answer yet; `linked` and
|
||||
`tracking` are never proposed (ask the owner). `storebound check` compares the block with the iOS project:
|
||||
tracking true <-> `NSUserTrackingUsageDescription` and `NSPrivacyTracking` true; the app's
|
||||
tracking true <-> `NSUserTrackingUsageDescription` and a manifest that declares tracking: the tracking SDK's own
|
||||
manifest (Pods, frameworks, plugins, the built IPA; info) or the app's, which says true only with its own
|
||||
`NSPrivacyTrackingDomains` (true with an empty list is ITMS-91064, see `privacy-manifest`); the app's
|
||||
`NSPrivacyCollectedDataTypes` <-> the types marked collected (mismatches both ways).
|
||||
6. **Export compliance.** `export-compliance` skill (`ITSAppUsesNonExemptEncryption` in Info.plist, `apple encryption`).
|
||||
7. **Privacy manifest (iOS).** `privacy-manifest` skill; keep it consistent with App Privacy.
|
||||
|
|
|
|||
|
|
@ -376,3 +376,19 @@ that fails without the fix (see CONTRIBUTING.md).
|
|||
Responses?" (Cancel / Publish); afterwards "Published … ago by …" shows, which `console verify apple-app-privacy`
|
||||
reads as the published signal.
|
||||
- **Guard:** appstore-first-release and store-iap-setup skills; `tests/console-play-plans.test.ts`.
|
||||
|
||||
## 29. ITMS-91064: NSPrivacyTracking true with an empty NSPrivacyTrackingDomains
|
||||
- **Symptom:** Apple marks the build Invalid Binary a minute after the upload: "ITMS-91064: Invalid tracking information - A PrivacyInfo.xcprivacy file contains invalid tracking information at the following path: "PrivacyInfo.xcprivacy". NSPrivacyTracking must be true if NSPrivacyTrackingDomains isn't empty. Keys and values in your app's privacy manifests must be valid."
|
||||
- **Cause:** the app's own PrivacyInfo.xcprivacy said NSPrivacyTracking true with an empty NSPrivacyTrackingDomains
|
||||
because App Privacy says "used for tracking", but the tracking came from an ad SDK (mediation, attribution) whose own
|
||||
manifest declares it. Apple's text names the other direction (domains listed with false); both are refused.
|
||||
- **Do:** in every manifest, NSPrivacyTracking true needs a non-empty NSPrivacyTrackingDomains (domains the code of
|
||||
THAT bundle sends tracking data to), and a non-empty list needs true. When only an SDK tracks, the app's manifest
|
||||
says false; App Privacy in App Store Connect still says tracking = yes and ATT stays. Set
|
||||
`appPrivacy.trackingDomains` only for the app's own tracking domains. A bad SDK manifest: update the SDK. Rebuild
|
||||
and upload a new build number.
|
||||
- **Guard:** `check`, `scan` and `privacy-manifest` fail on either mismatch with the ITMS text; `check` reports
|
||||
tracking declared by an SDK manifest as info and warns only when no manifest declares it; `privacy-manifest
|
||||
--propose` writes true only with `appPrivacy.trackingDomains`; `apple upload` checks every manifest in the IPA
|
||||
(app root, Frameworks, bundles) before any network call, `apple build` after the export;
|
||||
`tests/privacy-tracking.test.ts`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue