# ITMS-91053: як виправити Missing API declaration в Expo

> ITMS-91053: твій білд використовує API з обов'язковою причиною і не декларує її. Додай категорію та код в ios.privacyManifests і зроби новий білд.

Оригінальна сторінка: [ITMS-91053: як виправити Missing API declaration в Expo](https://devoria.fr/uk/blog/itms-91053-missing-api-declaration-expo)
Автор: [Mehdi Azizi](https://devoria.fr/uk/mehdi-azizi)
Опубліковано: 2026-10-25
Останнє оновлення змісту: 2026-10-25


ITMS-91053 це автоматична перевірка Apple. Лист про неї приходить після [відправлення твого білда](https://devoria.fr/uk/blog/eas-submit-ios-publish-expo-app-store). У ньому сказано, що код твого застосунку використовує API «з обов'язковою причиною» (налаштування, дати файлів, час від запуску системи, місце на диску або клавіатури), але не пояснює навіщо у своєму маніфесті конфіденційності. **В Expo це виправляється в `ios.privacyManifests`: вказуєш категорію, яку назвала Apple, код, що описує твоє реальне використання, і робиш новий білд.**

У Solys, моєму будильнику з мініграми, ці причини задекларовані в конфігурації застосунку. Нижче його реальна декларація, команда, яка показує, що використовують твої залежності, і перевірка фінального файлу перед відправленням.

## Що означає помилка ITMS-91053?

Лист має заголовок «ITMS-91053: Missing API declaration». У ньому сказано, що код конкретного файлу у твоєму білді звертається до одного чи кількох API, які вимагають причини. Далі йде список категорій, наприклад `NSPrivacyAccessedAPICategoryUserDefaults`.

Ці API не просять у користувача жодного дозволу. Але їх можна використати, щоб розпізнати пристрій. Apple називає це fingerprinting. Він заборонений, навіть якщо користувач погодився на відстеження. Apple пояснює це на своїй сторінці про [API з обов'язковою причиною](https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api): кожен застосунок і кожен SDK мусить задекларувати, навіщо він їх використовує.

Та сама сторінка задає правило: **з 1 травня 2024 року App Store Connect більше не приймає застосунок, який не описує це використання у своєму маніфесті.** Деякі розробники казали, що отримали цей лист як звичайне попередження, а білд прийняли. Не розраховуй на це: вважай його блокером і виправ до наступного відправлення.

Як і інші помилки ITMS, це не відмова від рев'юера. Ніхто твій застосунок не відкривав: Apple проаналізувала бінарник.

## Privacy manifest в iOS: файл PrivacyInfo.xcprivacy

Маніфест конфіденційності це файл `PrivacyInfo.xcprivacy` у корені бандла застосунку. Згідно з [документацією Apple про privacy manifests](https://developer.apple.com/documentation/bundleresources/privacy-manifest-files), він описує зібрані дані, відстеження та API з обов'язковою причиною. Останні йдуть у масив `NSPrivacyAccessedAPITypes`: один запис на категорію, з її типом і списком причин.

Підступний момент: **маніфест покриває лише свій власний бандл.** Apple прямо пише: кожен виконуваний файл чи динамічна бібліотека, що використовує ці API, мусить мати маніфест у своєму бандлі. Маніфест твого застосунку не покриває вбудований фреймворк, а SDK не може покладатися на маніфест твого застосунку.

Не плутай його з рядками в Info.plist, яких вимагає [ITMS-90683](https://devoria.fr/uk/blog/itms-90683-missing-purpose-string-expo). Ті показуються користувачу в запиті дозволу. А маніфест читає лише Apple.

## 5 категорій API та їхні коди причин

Повна назва категорії починається з `NSPrivacyAccessedAPICategory`. Список API і причин є на сторінці ключа [NSPrivacyAccessedAPIType](https://developer.apple.com/documentation/bundleresources/app-privacy-configuration/nsprivacyaccessedapitypes/nsprivacyaccessedapitype), яку я переглянув 15 жовтня 2026 року.

| Категорія       | Типовий API                  | Поширена причина |
| --------------- | ---------------------------- | ---------------- |
| UserDefaults    | `UserDefaults`               | CA92.1           |
| FileTimestamp   | `creationDate`               | C617.1           |
| SystemBootTime  | `systemUptime`               | 35F9.1           |
| DiskSpace       | `volumeAvailableCapacityKey` | E174.1           |
| ActiveKeyboards | `activeInputModes`           | 54BD.1           |

Коди, які трапляються найчастіше:

- **CA92.1**: застосунок читає і записує власні налаштування, недоступні іншим застосункам.
- **1C8F.1**: налаштування, спільні з віджетом або розширенням з тієї ж App Group.
- **C617.1**: дати або розмір файлів, що лежать у контейнері застосунку.
- **3B52.1**: файли, які вибрав користувач, наприклад у вікні вибору документів.
- **35F9.1**: виміряти час між двома подіями в застосунку або запустити таймер.
- **E174.1**: перевірити вільне місце перед записом файлів, з видимим для користувача ефектом.
- **85F4.1**: показати користувачу місце на диску.

**Декларуй причину, яка відповідає твоєму реальному використанню, а не ту, що здається найширшою.** Apple уточнює, що ці API та їхні дані використовуються лише для задекларованих причин і ніколи для відстеження. Два коди зарезервовані для сторонніх SDK: C56D.1 і 0A2A.1. У маніфесті твого застосунку їм не місце.

## Як задекларувати privacy manifest в Expo

В Expo ти не пишеш цей файл сам. Ти описуєш його в `expo.ios.privacyManifests`, в app.json або app.config, а prebuild генерує `PrivacyInfo.xcprivacy`. Це спосіб із [документації Expo про privacy manifests](https://docs.expo.dev/guides/apple-privacy/).

Ось реальний фрагмент конфігурації Solys. Ключ містить ще відстеження і зібрані дані, тут я їх прибрав:

```json
{
  "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 і 35F9.1 повторюють те, що декларують React Native і модулі Expo в застосунку. 1C8F.1 походить від самого Solys: застосунок ділиться налаштуваннями зі своїм віджетом через App Group.

Пастка, про яку варто знати: якщо твоя папка `ios` генерується і ігнорується git, **`PrivacyInfo.xcprivacy`, написаний вручну в цій папці, ніколи не потрапить у білд.** EAS заново запускає prebuild і перегенеровує папку. Я бачив це на одному зі своїх проєктів 9 вересня 2026 року: маніфест, написаний вручну, зник після prebuild. Декларація має жити в конфігурації.

Останнє: маніфест є частиною бінарника. Оновлення по повітрю його не змінює. Треба зробити новий білд і відправити його знову.

## Сторонні SDK зі своїм маніфестом

Більшість свіжих бібліотек мають власний маніфест. Пакети Expo, що використовують ці API, мають `PrivacyInfo.xcprivacy` у своїй папці `ios`, так само як і React Native. Проблема в тому, як вони лінкуються до твого застосунку.

Документація Expo попереджає: Apple не завжди правильно читає маніфести статично злінкованих залежностей CocoaPods, а пакети Expo саме такі. Тому може знадобитися скопіювати їхні причини в конфігурацію свого застосунку.

Щоб зменшити цю роботу, налаштування `ios.privacyManifestAggregationEnabled` з [expo-build-properties](https://docs.expo.dev/versions/latest/sdk/build-properties/) об'єднує маніфести залежностей CocoaPods в один файл. У Podfile, який Expo генерує в моїх проєктах (SDK 57), це об'єднання ввімкнене, якщо ти його не вимкнеш.

В об'єднання є обмеження: воно бачить лише залежності, які мають маніфест. Стара бібліотека без маніфесту лишається невидимою. **Тож читай шлях до файлу, вказаний у листі**: він підказує, де виправляти.

| Вказаний файл               | Де виправляти          |
| --------------------------- | ---------------------- |
| Виконуваний файл застосунку | `ios.privacyManifests` |
| `.framework`                | Оновити SDK            |
| Розширення `.appex`         | Маніфест розширення    |

## Перевірка перед відправленням

Expo пропонує чекати листа від Apple після відправлення. Це працює, але кожна ітерація коштує білд. Ось чотири перевірки, які я роблю заздалегідь.

**1. Подивись, що декларують твої залежності.** З кореня проєкту:

```bash
find node_modules -name PrivacyInfo.xcprivacy -not -path '*/example/*' \
  -exec grep -ho "NSPrivacyAccessedAPICategory[A-Za-z]*" {} + | sort | uniq -c
```

На Solys 15 жовтня 2026 року команда знаходить 13 маніфестів і чотири категорії: дати файлів, налаштування, час від запуску системи і місце на диску. Кожна знайдена категорія має бути у фінальному маніфесті застосунку або в маніфесті фреймворку, який її використовує.

**2. Пошукай у власному нативному коді.** Власні модулі, плагіни, таргети на кшталт віджета: цей код жоден SDK за тебе не задекларує.

```bash
grep -rlE "UserDefaults|systemUptime|mach_absolute_time|creationDate|modificationDate|volumeAvailableCapacity|activeInputModes" \
  --include='*.swift' --include='*.m' --include='*.mm' modules plugins targets
```

Підлаштуй папки під свій проєкт. На Solys саме цей пошук виявляє налаштування, спільні через App Group, звідси й код 1C8F.1.

**3. Прочитай згенерований маніфест.** Запусти `npx expo prebuild -p ios`, потім відкрий `ios/<YourAppName>/PrivacyInfo.xcprivacy`. Обережно: ця команда може видалити і заново створити папку `ios`. Якщо ти вносив туди зміни вручну, працюй на копії проєкту.

**4. Перевір фінальний білд.** Це єдиний доказ, який має значення. Завантаж IPA зі сторінки білда на expo.dev і запусти на своєму Mac:

```bash
unzip -q MyApp.ipa -d ipa
find ipa/Payload -name PrivacyInfo.xcprivacy
plutil -p ipa/Payload/*.app/PrivacyInfo.xcprivacy
```

Другий рядок показує всі вбудовані маніфести: застосунку і фреймворків. Третій виводить маніфест застосунку, який треба порівняти зі списком із кроку 1.

## Маніфест має збігатися з твоєю сторінкою в App Store

Маніфест не існує сам по собі. Якщо він декларує відстеження чи зібрані дані, твоя сторінка в App Store і політика конфіденційності мають казати те саме. Розбіжність між цими трьома може потім коштувати відмови від людини за [guideline 5.1.1](https://devoria.fr/uk/blog/guideline-5-1-1-app-store-rejection-fix). Що саме треба узгодити, детально описано в статті [політика конфіденційності застосунку](https://devoria.fr/uk/blog/privacy-policy-ios-app-guide).

## Відправ білд без неприємних сюрпризів

Помилки ITMS швидко виправляються, коли вмієш їх читати. Відмови, що приходять потім, вимагають більше осмислення: план дій є на сторінці [застосунок відхилила Apple](https://devoria.fr/uk/expertise/app-rejected-by-apple), а найчастіші причини зібрані в статті [чому Apple відхиляє застосунок](https://devoria.fr/uk/blog/vidmova-apple-app-store-prychyny).

Щоб перевірити свій проєкт перед відправленням, [Apple Review Kit](https://devoria.fr/uk/kits/review-apple) містить мій чекліст і skills для Claude Code, які переглядають твій проєкт. Якщо відправлення застрягло і тобі потрібен погляд живої людини, [забронюй годину зі мною](https://devoria.fr/uk/coaching): розберемо твій проєкт по відео, на твоєму екрані. А якщо готуєш свій перший реліз, [пройди безкоштовну діагностику](https://devoria.fr/uk/diagnostic): вона розставить кроки в правильному порядку й надішле тобі мій чекліст проти відмов Apple.

## Поширені запитання

### Чи блокує ITMS-91053 відправлення мого білда?

Apple пише, що з 1 травня 2024 року App Store Connect не приймає застосунки, які не описують використання цих API. Проте деякі розробники отримували лист на прийнятий білд, як попередження. В обох випадках виправ маніфест до наступного білда.

### Який код причини обрати для UserDefaults?

CA92.1, якщо застосунок лише читає і записує власні налаштування. Додай 1C8F.1, якщо він ділиться ними з віджетом чи розширенням через App Group. C56D.1 зарезервований для сторонніх SDK: не додавай його в маніфест свого застосунку.

### Чи треба копіювати маніфест кожного SDK в app.json?

Не обов'язково. Якщо об'єднання маніфестів увімкнене, маніфести залежностей CocoaPods збираються разом під час встановлення pods. Копіюй категорію лише тоді, коли її немає у фінальному маніфесті, з причиною, що описує реальне використання.

### Чи потрібен моєму віджету або розширенню власний маніфест?

За словами Apple, кожен бандл із виконуваним файлом, що використовує ці API, мусить мати власний маніфест. Розширення це окремий виконуваний файл у власному бандлі: маніфест застосунку його не покриває.

### Чи можна виправити ITMS-91053 без нового білда?

Ні. Маніфест конфіденційності є частиною бінарника. Виправ конфігурацію, зроби новий білд і протестуй його в [TestFlight](https://devoria.fr/uk/blog/testflight-testuvannya-zastosunku-iphone), перш ніж відправляти на рев'ю.


## Твій проєкт

[Apple Review Kit](https://devoria.fr/uk/kits/review-apple): Чекліст для review App Store, яким я користуюся, мої виправлені відмови Apple, нотатки для тестувальника і два skills Claude Code, що перевіряють твій застосунок. 29 €.

[iOS Kit](https://devoria.fr/uk/kits/ios): Створи застосунок для iPhone з Claude Code: стартовий код моїх застосунків, skills, що перевіряють його роботу, а також Apple Review Kit, App Store Screenshots Kit і ASO Kit. 129,99 €.
