# ITMS-91053: แก้ Missing API declaration ด้วย Expo

> ITMS-91053: บิลด์ของคุณใช้ API ที่ต้องระบุเหตุผลแต่ไม่ได้ประกาศ ให้เพิ่มหมวดหมู่และโค้ดเหตุผลใน ios.privacyManifests แล้วบิลด์ใหม่

หน้าต้นฉบับ: [ITMS-91053: แก้ Missing API declaration ด้วย Expo](https://devoria.fr/th/blog/itms-91053-missing-api-declaration-expo)
ผู้เขียน: [Mehdi Azizi](https://devoria.fr/th/mehdi-azizi)
เผยแพร่: 2026-10-25
แก้ไขเนื้อหาล่าสุด: 2026-10-25


ITMS-91053 คือการตรวจสอบอัตโนมัติของ Apple ซึ่งจะส่งมาทางอีเมลหลัง[การส่งบิลด์ของคุณ](https://devoria.fr/th/blog/eas-submit-ios-publish-expo-app-store) ข้อความนี้บอกว่าโค้ดในแอปของคุณใช้ API แบบ "ต้องระบุเหตุผล" (การตั้งค่า, วันที่ของไฟล์, เวลาตั้งแต่เปิดเครื่อง, พื้นที่ดิสก์ หรือคีย์บอร์ด) โดยไม่ได้อธิบายเหตุผลไว้ในไฟล์ manifest ด้านความเป็นส่วนตัว **ถ้าใช้ Expo ให้แก้ใน `ios.privacyManifests`: ใส่หมวดหมู่ที่ Apple ระบุมา ใส่โค้ดที่ตรงกับการใช้งานจริงของคุณ แล้วบิลด์ใหม่**

ใน Solys แอปนาฬิกาปลุกพร้อมมินิเกมของผม เหตุผลเหล่านี้ประกาศไว้ในคอนฟิกของแอป ในบทความนี้ผมจะให้ดูการประกาศจริงของแอป คำสั่งที่ใช้ดูว่า dependency ของคุณใช้อะไรบ้าง และการตรวจไฟล์สุดท้ายก่อนส่ง

## ข้อผิดพลาด 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 ต้องประกาศว่าใช้ API เหล่านี้เพื่ออะไร

หน้าเดียวกันกำหนดกฎไว้ว่า **ตั้งแต่วันที่ 1 พฤษภาคม 2024 App Store Connect จะไม่รับแอปที่ไม่ได้อธิบายการใช้งานเหล่านี้ไว้ใน manifest** มีนักพัฒนาบางคนบอกว่าได้รับอีเมลนี้เป็นแค่คำเตือนบนบิลด์ที่ผ่านแล้ว แต่อย่าหวังพึ่งตรงนั้น ให้ถือว่าเป็นตัวบล็อกและแก้ให้เสร็จก่อนส่งครั้งต่อไป

เหมือนข้อผิดพลาด ITMS อื่นๆ นี่ไม่ใช่การปฏิเสธจาก reviewer ไม่มีใครเปิดแอปของคุณ Apple แค่วิเคราะห์ไบนารี

## Privacy manifest ของ iOS: ไฟล์ PrivacyInfo.xcprivacy

Privacy manifest คือไฟล์ชื่อ `PrivacyInfo.xcprivacy` ที่วางไว้ที่รากของ bundle ของแอป ตาม[เอกสารของ Apple เรื่อง privacy manifests](https://developer.apple.com/documentation/bundleresources/privacy-manifest-files) ไฟล์นี้อธิบายข้อมูลที่เก็บ การติดตาม และ API ที่ต้องระบุเหตุผล ส่วนหลังสุดนี้อยู่ในอาร์เรย์ `NSPrivacyAccessedAPITypes`: หนึ่งรายการต่อหนึ่งหมวดหมู่ พร้อมประเภทและรายการเหตุผล

จุดที่มักพลาด: **manifest ครอบคลุมเฉพาะ bundle ของตัวเองเท่านั้น** Apple เขียนไว้ชัดว่าทุก executable หรือ dynamic library ที่ใช้ API เหล่านี้ต้องมี manifest ใน bundle ของตัวเอง manifest ของแอปไม่ครอบคลุม framework ที่ฝังมา และ SDK ก็พึ่ง manifest ของแอปคุณไม่ได้

อย่าสับสนกับข้อความใน Info.plist ที่ [ITMS-90683](https://devoria.fr/th/blog/itms-90683-missing-purpose-string-expo) กำหนด ข้อความพวกนั้นแสดงให้ผู้ใช้เห็นตอนขออนุญาต ส่วน manifest นั้นมีแค่ Apple ที่อ่าน

## API 5 หมวดหมู่และโค้ดเหตุผล

ชื่อเต็มของหมวดหมู่ขึ้นต้นด้วย `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**: การตั้งค่าที่แชร์กับวิดเจ็ตหรือ extension ใน App Group เดียวกัน
- **C617.1**: วันที่หรือขนาดของไฟล์ที่เก็บอยู่ใน container ของแอป
- **3B52.1**: ไฟล์ที่ผู้ใช้เลือกเอง เช่น จากตัวเลือกเอกสาร
- **35F9.1**: วัดเวลาที่ผ่านไประหว่างสองเหตุการณ์ในแอป หรือใช้จับเวลา
- **E174.1**: ตรวจพื้นที่ว่างก่อนเขียนไฟล์ โดยมีผลที่ผู้ใช้มองเห็นได้
- **85F4.1**: แสดงพื้นที่ดิสก์ให้ผู้ใช้ดู

**ประกาศเหตุผลที่ตรงกับการใช้งานจริงของคุณ ไม่ใช่เหตุผลที่ดูกว้างที่สุด** Apple ระบุว่า API เหล่านี้และข้อมูลของมันใช้ได้เฉพาะตามเหตุผลที่ประกาศ และห้ามใช้เพื่อการติดตามเด็ดขาด มีสองโค้ดที่สงวนไว้สำหรับ SDK ภายนอก คือ C56D.1 และ 0A2A.1 ซึ่งไม่ควรอยู่ใน manifest ของแอปคุณ

## ประกาศ 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 ignore ไว้ **ไฟล์ `PrivacyInfo.xcprivacy` ที่เขียนเองในโฟลเดอร์นั้นจะไม่มีวันเข้าไปอยู่ในบิลด์** เพราะ EAS จะรัน prebuild ใหม่และสร้างโฟลเดอร์ขึ้นมาใหม่ ผมเจอเองในโปรเจกต์หนึ่งเมื่อวันที่ 9 กันยายน 2026: manifest ที่เขียนเองหายไปหลัง prebuild การประกาศต้องอยู่ในคอนฟิก

อีกเรื่องสุดท้าย: manifest เป็นส่วนหนึ่งของไบนารี การอัปเดตแบบ remote ไม่ได้เปลี่ยนมัน ต้องบิลด์ใหม่แล้วส่งอีกครั้ง

## SDK ภายนอกที่มี manifest ของตัวเอง

ไลบรารีใหม่ๆ ส่วนใหญ่มี manifest มาให้ แพ็กเกจ Expo ที่ใช้ API เหล่านี้มี `PrivacyInfo.xcprivacy` อยู่ในโฟลเดอร์ `ios` ของตัวเอง React Native ก็เช่นกัน ปัญหาอยู่ที่วิธีที่มันถูกลิงก์เข้ากับแอปของคุณ

เอกสารของ Expo เตือนไว้ว่า Apple อ่าน manifest ของ dependency CocoaPods ที่ลิงก์แบบ static ได้ไม่ถูกต้องทั้งหมด ซึ่งแพ็กเกจ Expo เป็นแบบนั้น ดังนั้นคุณอาจต้องคัดลอกเหตุผลของมันมาใส่ในคอนฟิกของแอปเอง

เพื่อลดงานส่วนนี้ การตั้งค่า `ios.privacyManifestAggregationEnabled` ของ [expo-build-properties](https://docs.expo.dev/versions/latest/sdk/build-properties/) จะรวม manifest ของ dependency CocoaPods เข้าเป็นไฟล์เดียว ใน Podfile ที่ Expo สร้างในโปรเจกต์ของผม (SDK 57) การรวมนี้เปิดอยู่ เว้นแต่คุณจะปิดเอง

การรวมนี้มีข้อจำกัด: มันเห็นเฉพาะ dependency ที่มี manifest เท่านั้น ไลบรารีเก่าที่ไม่มี manifest จะมองไม่เห็น **ดังนั้นให้อ่านพาธของไฟล์ที่ระบุในอีเมล** เพราะมันบอกว่าต้องแก้ตรงไหน

| ไฟล์ที่ถูกระบุ     | แก้ที่ไหน              |
| ------------------ | ---------------------- |
| executable ของแอป  | `ios.privacyManifests` |
| `.framework`       | อัปเดต SDK             |
| extension `.appex` | manifest ของ extension |

## ตรวจสอบก่อนส่ง

Expo แนะนำให้รออีเมลจาก Apple หลังส่ง ซึ่งก็ใช้ได้ แต่ทุกรอบที่ไปกลับจะเสียบิลด์หนึ่งครั้ง นี่คือการตรวจสี่อย่างที่ผมทำก่อนส่ง

**1. ดูรายการที่ dependency ของคุณประกาศไว้** รันจากรากของโปรเจกต์:

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

ใน Solys เมื่อวันที่ 15 ตุลาคม 2026 คำสั่งนี้เจอ manifest 13 ไฟล์และสี่หมวดหมู่ ได้แก่ วันที่ของไฟล์ การตั้งค่า เวลาตั้งแต่เปิดเครื่อง และพื้นที่ดิสก์ ทุกหมวดหมู่ที่เจอต้องไปปรากฏใน manifest สุดท้ายของแอป หรือใน manifest ของ framework ที่ใช้มัน

**2. ค้นในโค้ด native ของคุณเอง** โมดูลที่เขียนเอง ปลั๊กอิน target อย่างวิดเจ็ต: โค้ดพวกนี้ไม่มี 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. อ่าน manifest ที่ถูกสร้างขึ้น** รัน `npx expo prebuild -p ios` แล้วเปิด `ios/<YourAppName>/PrivacyInfo.xcprivacy` ระวัง: คำสั่งนี้อาจลบแล้วสร้างโฟลเดอร์ `ios` ใหม่ ถ้าคุณแก้อะไรในนั้นด้วยมือ ให้ทำงานบนสำเนาของโปรเจกต์

**4. ตรวจบิลด์สุดท้าย** นี่คือหลักฐานเดียวที่นับจริง ดาวน์โหลด IPA จากหน้าบิลด์บน expo.dev แล้วรันบน Mac ของคุณ:

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

บรรทัดที่สองแสดง manifest ทั้งหมดที่ฝังอยู่ ทั้งของแอปและของ framework บรรทัดที่สามแสดง manifest ของแอป ให้เทียบกับรายการจากขั้นตอนที่ 1

## สิ่งที่ manifest ต้องสอดคล้องกับหน้าแอปของคุณ

manifest ไม่ได้อยู่ลำพัง ถ้ามันประกาศการติดตามหรือข้อมูลที่เก็บ หน้า App Store และนโยบายความเป็นส่วนตัวของคุณต้องบอกสิ่งเดียวกัน ถ้าสามอย่างนี้ไม่ตรงกัน คุณอาจโดนปฏิเสธจากคนตรวจในภายหลังภายใต้ [guideline 5.1.1](https://devoria.fr/th/blog/guideline-5-1-1-app-store-rejection-fix) รายละเอียดสิ่งที่ต้องทำให้ตรงกันอยู่ในบทความ[นโยบายความเป็นส่วนตัวของแอป](https://devoria.fr/th/blog/ios-app-privacy-policy-guide)

## ส่งบิลด์โดยไม่มีเรื่องเซอร์ไพรส์

ข้อผิดพลาด ITMS แก้ได้เร็วถ้าอ่านเป็น แต่การปฏิเสธที่ตามมาทีหลังต้องคิดมากกว่านั้น วิธีรับมืออยู่ในหน้า[แอปถูก Apple ปฏิเสธ](https://devoria.fr/th/expertise/app-rejected-by-apple) และเหตุผลที่พบบ่อยที่สุดอยู่ใน[ทำไม Apple ถึงปฏิเสธแอป](https://devoria.fr/th/blog/apple-app-rejection-reasons-real-cases)

ถ้าต้องการตรวจโปรเจกต์ก่อนส่ง [Apple Review Kit](https://devoria.fr/th/kits/review-apple) รวมเช็กลิสต์ของผมและ skill ของ Claude Code ที่ช่วยรีวิวโปรเจกต์ของคุณไว้ ถ้าการส่งติดขัดและอยากให้คนช่วยดู [จองเวลาหนึ่งชั่วโมงกับผม](https://devoria.fr/th/coaching) แล้วเราจะไล่ดูโปรเจกต์ของคุณผ่านวิดีโอคอลบนหน้าจอของคุณ และถ้าคุณกำลังเตรียมปล่อยแอปแรก [ทำแบบประเมินฟรี](https://devoria.fr/th/diagnostic) ซึ่งจะเรียงขั้นตอนให้ถูกลำดับและส่งเช็กลิสต์กันโดน Apple ปฏิเสธของผมให้คุณ

## คำถามที่พบบ่อย

### ITMS-91053 บล็อกการส่งบิลด์ของฉันไหม?

Apple เขียนไว้ว่าตั้งแต่วันที่ 1 พฤษภาคม 2024 App Store Connect จะไม่รับแอปที่ไม่ได้อธิบายการใช้ API เหล่านี้ แต่ก็มีนักพัฒนาที่ได้รับอีเมลนี้บนบิลด์ที่ผ่านแล้วในฐานะคำเตือน ไม่ว่าจะเป็นแบบไหน ให้แก้ manifest ก่อนบิลด์ครั้งต่อไป

### ควรเลือกโค้ดเหตุผลอะไรสำหรับ UserDefaults?

ใช้ CA92.1 ถ้าแอปอ่านและเขียนแค่การตั้งค่าของตัวเอง เพิ่ม 1C8F.1 ถ้าแชร์การตั้งค่ากับวิดเจ็ตหรือ extension ผ่าน App Group ส่วน C56D.1 สงวนไว้สำหรับ SDK ภายนอก อย่าใส่ไว้ใน manifest ของแอปคุณ

### ต้องคัดลอก manifest ของทุก SDK ลงใน app.json ไหม?

ไม่จำเป็น ถ้าเปิดการรวม manifest ไว้ manifest ของ dependency CocoaPods จะถูกรวมกันตอนติดตั้ง pods ให้คัดลอกหมวดหมู่มาเฉพาะเมื่อมันขาดไปจาก manifest สุดท้าย พร้อมเหตุผลที่ตรงกับการใช้งานจริง

### วิดเจ็ตหรือ extension ของฉันต้องมี manifest ของตัวเองไหม?

ตามที่ Apple ระบุ ทุก bundle ที่มี executable ซึ่งใช้ API เหล่านี้ต้องมี manifest ของตัวเอง extension เป็น executable แยกที่อยู่ใน bundle ของตัวเอง manifest ของแอปจึงไม่ครอบคลุมมัน

### แก้ ITMS-91053 โดยไม่บิลด์ใหม่ได้ไหม?

ไม่ได้ privacy manifest เป็นส่วนหนึ่งของไบนารี ให้แก้คอนฟิก บิลด์ใหม่ แล้วทดสอบใน [TestFlight](https://devoria.fr/th/blog/testflight-test-iphone-app-before-app-store) ก่อนส่งเข้ารีวิว


## โปรเจกต์ของคุณ

[Apple Review Kit](https://devoria.fr/th/kits/review-apple): เช็กลิสต์รีวิว App Store ที่ผมใช้ การปฏิเสธจาก Apple ที่ผมแก้แล้ว บันทึกถึงผู้ตรวจ และสอง skills ของ Claude Code ที่ตรวจแอปคุณ 29 €

[iOS Kit](https://devoria.fr/th/kits/ios): สร้างแอป iPhone ด้วย Claude Code: Starter Code ของแอปผม skills ที่ตรวจงาน และคิต Apple Review, Screenshots และ ASO 129,99 €
