ITMS-91053: „Missing API declaration“ mit Expo beheben
Von Mehdi Azizi
Veröffentlicht am , 8 Min.
ITMS-91053: Dein Build nutzt eine Required Reason API, ohne sie zu deklarieren. Trag Kategorie und Code in ios.privacyManifests ein und baue neu.
ITMS-91053 ist eine automatische Prüfung von Apple, die du per E-Mail bekommst, nachdem du deinen Build hochgeladen hast. Sie besagt, dass der Code deiner App eine API mit Begründungspflicht nutzt (Einstellungen, Dateizeitstempel, Zeit seit dem Systemstart, Speicherplatz oder Tastaturen), ohne in ihrem Privacy Manifest zu erklären, warum. Mit Expo behebst du das in ios.privacyManifests: die von Apple genannte Kategorie, der Code, der deine tatsächliche Nutzung beschreibt, dann ein neuer Build.
Bei Solys, meinem Wecker mit Minispielen, sind diese Gründe in der App-Konfiguration deklariert. Hier findest du die echte Deklaration, den Befehl, der auflistet, was deine Abhängigkeiten nutzen, und die Prüfung der fertigen Datei vor dem Upload.
Was bedeutet der Fehler ITMS-91053?
Die Meldung heißt „ITMS-91053: Missing API declaration“. Sie gibt an, dass der Code einer bestimmten Datei in deinem Build eine oder mehrere APIs referenziert, die eine Begründung erfordern. Dann listet sie die betroffenen Kategorien auf, zum Beispiel NSPrivacyAccessedAPICategoryUserDefaults.
Diese APIs fragen den Nutzer nach keiner Berechtigung. Sie können aber dazu dienen, ein Gerät wiederzuerkennen, was Apple Fingerprinting nennt. Das ist verboten, selbst wenn der Nutzer dem Tracking zustimmt. Apple erklärt das auf seiner Seite zu den Required Reason APIs: Jede App und jedes SDK muss deklarieren, warum es sie nutzt.
Dieselbe Seite legt die Regel fest: Seit dem 1. Mai 2024 akzeptiert App Store Connect keine App mehr, die diese Nutzungen nicht in ihrem Manifest beschreibt. Manche Entwickler haben diese E-Mail als bloße Warnung bei einem akzeptierten Build gemeldet. Verlass dich nicht darauf: Behandle sie als Blockade und korrigiere vor dem nächsten Upload.
Wie die anderen ITMS-Fehler ist das keine Ablehnung durch einen Reviewer. Niemand hat deine App geöffnet: Apple hat das Binary analysiert.
Das iOS Privacy Manifest: die Datei PrivacyInfo.xcprivacy
Das Privacy Manifest ist eine Datei namens PrivacyInfo.xcprivacy, die im Root des App-Bundles liegt. Laut Apples Dokumentation zu Privacy Manifests beschreibt sie die erhobenen Daten, das Tracking und die Required Reason APIs. Letztere kommen in das Array NSPrivacyAccessedAPITypes: ein Eintrag pro Kategorie, mit ihrem Typ und der Liste ihrer Gründe.
Die Falle: Ein Manifest deckt nur sein eigenes Bundle ab. Apple schreibt es so: Jedes Executable oder jede dynamische Bibliothek, die diese APIs nutzt, braucht ein Manifest in ihrem Bundle. Das Manifest deiner App deckt kein eingebettetes Framework ab, und ein SDK kann sich nicht auf das deiner App verlassen.
Verwechsle es nicht mit den Texten in der Info.plist, die ITMS-90683 verlangt. Die werden dem Nutzer in einer Berechtigungsanfrage angezeigt. Das Manifest dagegen liest nur Apple.
Die 5 API-Kategorien und ihre Reason-Codes
Der vollständige Name einer Kategorie beginnt mit NSPrivacyAccessedAPICategory. Die Liste der APIs und Gründe steht auf der Seite des Schlüssels NSPrivacyAccessedAPIType, abgerufen am 15. Oktober 2026.
| Kategorie | Typische API | Häufiger Grund |
|---|---|---|
| UserDefaults | UserDefaults | CA92.1 |
| FileTimestamp | creationDate | C617.1 |
| SystemBootTime | systemUptime | 35F9.1 |
| DiskSpace | volumeAvailableCapacityKey | E174.1 |
| ActiveKeyboards | activeInputModes | 54BD.1 |
Die Codes, denen du am häufigsten begegnest:
- CA92.1: Die App liest und schreibt ihre eigenen Einstellungen, auf die andere Apps keinen Zugriff haben.
- 1C8F.1: Einstellungen, die mit einem Widget oder einer Extension derselben App Group geteilt werden.
- C617.1: Datum oder Größe von Dateien im Container der App.
- 3B52.1: Dateien, die der Nutzer ausgewählt hat, zum Beispiel in einer Dokumentauswahl.
- 35F9.1: die verstrichene Zeit zwischen zwei Ereignissen der App messen oder einen Timer laufen lassen.
- E174.1: freien Speicherplatz prüfen, bevor Dateien geschrieben werden, mit sichtbarer Auswirkung für den Nutzer.
- 85F4.1: dem Nutzer den Speicherplatz anzeigen.
Deklariere den Grund, der deiner tatsächlichen Nutzung entspricht, nicht den, der am breitesten wirkt. Apple stellt klar, dass diese APIs und ihre Daten nur für die deklarierten Gründe genutzt werden dürfen und nie für Tracking. Zwei Codes sind SDKs von Drittanbietern vorbehalten: C56D.1 und 0A2A.1. Sie haben im Manifest deiner App nichts zu suchen.
Das Privacy Manifest in Expo deklarieren
Mit Expo schreibst du die Datei nicht selbst. Du beschreibst sie unter expo.ios.privacyManifests, in app.json oder app.config, und der Prebuild erzeugt PrivacyInfo.xcprivacy. Das ist die Methode aus der Expo-Dokumentation zu Privacy Manifests.
Hier der echte Auszug aus der Konfiguration von Solys. Der Schlüssel enthält auch Tracking und erhobene Daten, die hier entfernt wurden:
{
"expo": {
"ios": {
"privacyManifests": {
"NSPrivacyAccessedAPITypes": [
{
"NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryUserDefaults",
"NSPrivacyAccessedAPITypeReasons": ["CA92.1", "1C8F.1"]
},
{
"NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryFileTimestamp",
"NSPrivacyAccessedAPITypeReasons": ["C617.1"]
},
{
"NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategorySystemBootTime",
"NSPrivacyAccessedAPITypeReasons": ["35F9.1"]
}
]
}
}
}
}
CA92.1, C617.1 und 35F9.1 übernehmen, was React Native und die Expo-Module der App deklarieren. 1C8F.1 kommt von Solys selbst: Die App teilt Einstellungen über eine App Group mit ihrem Widget.
Eine Falle, die du kennen solltest: Wenn dein ios-Ordner generiert und von git ignoriert wird, landet eine von Hand in diesem Ordner geschriebene PrivacyInfo.xcprivacy nie im Build. EAS führt den Prebuild erneut aus und erzeugt den Ordner neu. Ich habe das am 9. September 2026 bei einem meiner Projekte festgestellt: Das von Hand geschriebene Manifest war nach einem Prebuild verschwunden. Die Deklaration gehört in die Konfiguration.
Letzter Punkt: Das Manifest ist Teil des Binarys. Ein Remote-Update ändert es nicht. Du musst neu bauen und den Build erneut hochladen.
SDKs von Drittanbietern mit eigenem Manifest
Die meisten aktuellen Bibliotheken liefern ihr Manifest mit. Die Expo-Pakete, die diese APIs nutzen, haben eine PrivacyInfo.xcprivacy in ihrem ios-Ordner, genau wie React Native. Das Problem liegt darin, wie sie mit deiner App gelinkt werden.
Die Expo-Dokumentation warnt: Apple liest nicht alle Manifeste statisch gelinkter CocoaPods-Abhängigkeiten korrekt, und genau so werden Expo-Pakete gelinkt. Es kann also nötig sein, ihre Gründe in die Konfiguration deiner App zu übernehmen.
Um dir diese Arbeit zu sparen, fasst die Einstellung ios.privacyManifestAggregationEnabled von expo-build-properties die Manifeste der CocoaPods-Abhängigkeiten in einer einzigen Datei zusammen. Im Podfile, das Expo bei meinen Projekten erzeugt (SDK 57), ist diese Zusammenführung aktiv, solange du sie nicht abschaltest.
Die Zusammenführung hat eine Grenze: Sie sieht nur Abhängigkeiten, die ein Manifest mitliefern. Eine alte Bibliothek ohne Manifest bleibt unsichtbar. Lies also den Dateipfad, der in der E-Mail genannt wird: Er sagt dir, wo du korrigieren musst.
| Genannte Datei | Wo korrigieren |
|---|---|
| Das Executable der App | ios.privacyManifests |
Ein .framework | Das SDK aktualisieren |
Eine Extension .appex | Manifest der Extension |
Vor dem Upload prüfen
Expo schlägt vor, nach einem Upload auf die E-Mail von Apple zu warten. Das funktioniert, aber jede Runde kostet einen Build. Hier die vier Prüfungen, die ich vorher mache.
1. Liste auf, was deine Abhängigkeiten deklarieren. Vom Root des Projekts aus:
find node_modules -name PrivacyInfo.xcprivacy -not -path '*/example/*' \
-exec grep -ho "NSPrivacyAccessedAPICategory[A-Za-z]*" {} + | sort | uniq -c
Bei Solys findet der Befehl am 15. Oktober 2026 13 Manifeste und vier Kategorien: Dateizeitstempel, Einstellungen, Zeit seit dem Systemstart und Speicherplatz. Jede aufgelistete Kategorie muss im finalen Manifest der App auftauchen oder in dem des Frameworks, das sie nutzt.
2. Durchsuche deinen eigenen nativen Code. Eigene Module, Plugins, Targets wie ein Widget: Diesen Code deklariert kein SDK für dich.
grep -rlE "UserDefaults|systemUptime|mach_absolute_time|creationDate|modificationDate|volumeAvailableCapacity|activeInputModes" \
--include='*.swift' --include='*.m' --include='*.mm' modules plugins targets
Pass die Ordner an dein Projekt an. Bei Solys bringt genau diese Suche die per App Group geteilten Einstellungen zum Vorschein, daher der Code 1C8F.1.
3. Lies das erzeugte Manifest. Führe npx expo prebuild -p ios aus und öffne dann ios/<NomDeTonApp>/PrivacyInfo.xcprivacy. Achtung: Dieser Befehl kann den ios-Ordner löschen und neu erstellen. Wenn du dort etwas von Hand geändert hast, arbeite an einer Kopie des Projekts.
4. Prüfe den finalen Build. Das ist der einzige Beweis, der zählt. Lade die IPA von der Build-Seite auf expo.dev herunter und führe dann auf deinem Mac aus:
unzip -q MonApp.ipa -d ipa
find ipa/Payload -name PrivacyInfo.xcprivacy
plutil -p ipa/Payload/*.app/PrivacyInfo.xcprivacy
Die zweite Zeile listet alle eingebetteten Manifeste auf, das der App und die der Frameworks. Die dritte zeigt das der App an, das du mit der Liste aus Schritt 1 vergleichst.
Was das Manifest mit deinem Store-Eintrag gemeinsam erzählen muss
Das Manifest steht nicht für sich allein. Wenn es Tracking oder erhobene Daten deklariert, müssen dein App-Store-Eintrag und deine Datenschutzerklärung dasselbe sagen. Eine Abweichung zwischen den dreien kann dich später eine Ablehnung durch einen Menschen kosten, nach Guideline 5.1.1. Was du abgleichen musst, steht ausführlich in Datenschutzerklärung für eine App.
Deinen Build ohne böse Überraschung hochladen
ITMS-Fehler sind schnell behoben, wenn man sie lesen kann. Die Ablehnungen, die danach kommen, brauchen mehr Abstand: Das Vorgehen steht auf der Seite App von Apple abgelehnt, und die häufigsten Gründe findest du unter warum Apple eine App ablehnt.
Um dein Projekt vor dem Upload zu prüfen, vereint das Apple Review Kit meine Checkliste und Claude-Code-Skills, die dein Projekt durchgehen. Wenn dein Upload hängt und du einen menschlichen Blick willst, buch eine Stunde mit mir: Wir gehen dein Projekt per Videocall auf deinem Bildschirm durch. Und wenn du deinen ersten Release vorbereitest, mach deine kostenlose Diagnose: Sie bringt die Schritte in die richtige Reihenfolge und schickt dir meine Checkliste gegen Apple-Ablehnungen.
Häufige Fragen
Blockiert ITMS-91053 den Upload meines Builds?
Apple schreibt, dass App Store Connect seit dem 1. Mai 2024 keine Apps mehr akzeptiert, die ihre Nutzung dieser APIs nicht beschreiben. Trotzdem haben manche Entwickler die E-Mail bei einem akzeptierten Build als Warnung bekommen. In beiden Fällen gilt: Korrigiere das Manifest vor dem nächsten Build.
Welchen Reason-Code wähle ich für UserDefaults?
CA92.1, wenn die App nur ihre eigenen Einstellungen liest und schreibt. Füge 1C8F.1 hinzu, wenn sie sie über eine App Group mit einem Widget oder einer Extension teilt. C56D.1 ist SDKs von Drittanbietern vorbehalten: Setz ihn nicht ins Manifest deiner App.
Muss ich das Manifest jedes SDKs in app.json übernehmen?
Nicht unbedingt. Wenn die Zusammenführung der Manifeste aktiv ist, werden die der CocoaPods-Abhängigkeiten bei der Pod-Installation zusammengefasst. Übernimm eine Kategorie nur, wenn sie im finalen Manifest fehlt, mit dem Grund, der die tatsächliche Nutzung beschreibt.
Braucht mein Widget oder meine Extension ein eigenes Manifest?
Laut Apple muss jedes Bundle, das ein Executable mit diesen APIs enthält, ein eigenes Manifest haben. Eine Extension ist ein eigenes Executable in einem eigenen Bundle: Das Manifest der App deckt sie nicht ab.
Kann man ITMS-91053 ohne neuen Build beheben?
Nein. Das Privacy Manifest ist Teil des Binarys. Korrigiere die Konfiguration, baue neu und teste den Build in TestFlight, bevor du ihn zur Review einreichst.