ITMS-91053 Missing API declaration: תיקון ב-Expo
מאת Mehdi Azizi
פורסם ב-, 8 דק׳
ITMS-91053: הבילד שלך משתמש ב-API שדורש סיבה בלי להצהיר עליו. הוסף את הקטגוריה והקוד שלו ב-ios.privacyManifests ובנה מחדש.
ITMS-91053 היא בדיקה אוטומטית של Apple, שמגיעה במייל אחרי העלאת הבילד שלך. היא אומרת שהקוד של האפליקציה שלך משתמש ב-API "שדורש סיבה" (העדפות, תאריכי קבצים, זמן מאז האתחול, נפח דיסק או מקלדות) בלי להסביר למה במניפסט הפרטיות שלה. ב-Expo, התיקון נעשה ב-ios.privacyManifests: הקטגוריה ש-Apple ציינה, הקוד שמתאר את השימוש האמיתי שלך, ואז בילד חדש.
ב-Solys, השעון המעורר שלי עם מיני-משחקים, הסיבות האלה מוצהרות בקונפיגורציה של האפליקציה. הנה ההצהרה האמיתית שלה, הפקודה שמפרטת במה התלויות שלך משתמשות, והבדיקה שצריך לעשות על הקובץ הסופי לפני השליחה.
מה המשמעות של השגיאה ITMS-91053?
כותרת ההודעה היא "ITMS-91053: Missing API declaration". היא מציינת שהקוד בקובץ מסוים בבילד שלך מתייחס ל-API אחד או יותר שדורשים סיבה. אחר כך היא מפרטת את הקטגוריות הרלוונטיות, למשל NSPrivacyAccessedAPICategoryUserDefaults.
ה-API האלה לא מבקשים שום הרשאה מהמשתמש. אבל אפשר להשתמש בהם כדי לזהות מכשיר, מה ש-Apple קוראת לו fingerprinting. זה אסור, גם כשהמשתמש מסכים למעקב. Apple מסבירה את זה בעמוד שלה על API שדורשים סיבה: כל אפליקציה וכל SDK חייבים להצהיר למה הם משתמשים בהם.
אותו עמוד קובע את הכלל: מאז 1 במאי 2024, App Store Connect לא מקבל יותר אפליקציה שלא מתארת את השימושים האלה במניפסט שלה. מפתחים דיווחו שקיבלו את המייל הזה כאזהרה בלבד, על בילד שהתקבל. אל תסמוך על זה: תתייחס לזה כחסימה ותתקן לפני השליחה הבאה.
כמו שאר שגיאות ה-ITMS, זו לא דחייה של reviewer. אף אחד לא פתח את האפליקציה שלך: Apple ניתחה את הבינארי.
ה-privacy manifest של iOS: הקובץ PrivacyInfo.xcprivacy
מניפסט הפרטיות הוא קובץ בשם PrivacyInfo.xcprivacy, שנמצא בשורש ה-bundle של האפליקציה. לפי התיעוד של Apple על privacy manifests, הוא מתאר את הנתונים שנאספים, את המעקב ואת ה-API שדורשים סיבה. האחרונים נכנסים למערך NSPrivacyAccessedAPITypes: רשומה אחת לכל קטגוריה, עם הסוג שלה ורשימת הסיבות.
המלכודת: מניפסט מכסה רק את ה-bundle שלו. Apple כותבת את זה: כל קובץ הרצה או ספרייה דינמית שמשתמשים ב-API האלה חייבים מניפסט ב-bundle שלהם. המניפסט של האפליקציה שלך לא מכסה framework מוטמע, ו-SDK לא יכול לסמוך על המניפסט של האפליקציה שלך.
אל תבלבל אותו עם המשפטים ב-Info.plist ש-ITMS-90683 דורשת. אלה מוצגים למשתמש בבקשת הרשאה. את המניפסט, לעומת זאת, רק Apple קוראת.
5 קטגוריות ה-API וקודי הסיבה שלהן
השם המלא של קטגוריה מתחיל ב-NSPrivacyAccessedAPICategory. רשימת ה-API והסיבות נמצאת בעמוד של המפתח 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: העדפות שמשותפות עם widget או extension באותו 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.
הנה הקטע האמיתי מהקונפיגורציה של Solys. המפתח מכיל גם את המעקב ואת הנתונים שנאספים, שהוסרו כאן:
{
"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 עצמה: האפליקציה משתפת הגדרות עם ה-widget שלה דרך 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 ממזגת את המניפסטים של תלויות CocoaPods לקובץ אחד. ב-Podfile ש-Expo מייצר בפרויקטים שלי (SDK 57), המיזוג הזה פעיל, אלא אם אתה מכבה אותו.
למיזוג יש מגבלה: הוא רואה רק תלויות שמספקות מניפסט. ספרייה ישנה בלי מניפסט נשארת בלתי נראית. אז תקרא את הנתיב של הקובץ שמוזכר במייל: הוא אומר איפה לתקן.
| הקובץ שמוזכר | איפה לתקן |
|---|---|
| קובץ ההרצה של האפליקציה | ios.privacyManifests |
.framework | לעדכן את ה-SDK |
extension מסוג .appex | המניפסט של ה-extension |
בדיקה לפני השליחה
Expo מציעים לחכות למייל של Apple אחרי השליחה. זה עובד, אבל כל סיבוב עולה בילד. הנה ארבע הבדיקות שאני עושה לפני.
1. תפרט מה התלויות שלך מצהירות. משורש הפרויקט:
find node_modules -name PrivacyInfo.xcprivacy -not -path '*/example/*' \
-exec grep -ho "NSPrivacyAccessedAPICategory[A-Za-z]*" {} + | sort | uniq -c
ב-Solys, ב-15 באוקטובר 2026, הפקודה מוצאת 13 מניפסטים וארבע קטגוריות: תאריכי קבצים, העדפות, זמן מאז האתחול ונפח דיסק. כל קטגוריה ברשימה צריכה להופיע במניפסט הסופי של האפליקציה, או במניפסט של ה-framework שמשתמש בה.
2. תחפש בקוד ה-native שלך. מודולים שכתבת, plugins, targets כמו widget: על הקוד הזה אף SDK לא יצהיר במקומך.
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 שלך:
unzip -q MyApp.ipa -d ipa
find ipa/Payload -name PrivacyInfo.xcprivacy
plutil -p ipa/Payload/*.app/PrivacyInfo.xcprivacy
השורה השנייה מפרטת את כל המניפסטים המוטמעים, של האפליקציה ושל ה-frameworks. השלישית מציגה את המניפסט של האפליקציה, להשוואה מול הרשימה משלב 1.
מה המניפסט צריך לספר יחד עם דף האפליקציה שלך
המניפסט לא חי לבד. אם הוא מצהיר על מעקב או על נתונים שנאספים, דף האפליקציה שלך ב-App Store ומדיניות הפרטיות שלך צריכים להגיד את אותו הדבר. פער בין השלושה יכול לעלות לך אחר כך בדחייה אנושית, לפי guideline 5.1.1. מה צריך ליישר מפורט במדיניות פרטיות לאפליקציה.
לשלוח את הבילד בלי הפתעות
שגיאות ITMS מתקנים מהר כשיודעים לקרוא אותן. הדחיות שמגיעות אחר כך דורשות יותר פרספקטיבה: הדרך מוסברת בעמוד אפליקציה שנדחתה על ידי Apple, והסיבות הנפוצות ביותר נמצאות בלמה Apple דוחה אפליקציה.
כדי לבדוק את התיק שלך לפני השליחה, ה-Apple Review Kit מרכז את הצ'קליסט שלי ו-skills של Claude Code שעוברים על הפרויקט שלך. אם השליחה שלך תקועה ואתה רוצה עין אנושית, תקבע איתי שעה: נעבור על הפרויקט שלך בווידאו, על המסך שלך. ואם אתה מכין את ההשקה הראשונה שלך, תעשה את האבחון החינמי: הוא מסדר את השלבים לפי הסדר ושולח לך את הצ'קליסט שלי נגד דחיות של Apple.
שאלות נפוצות
האם ITMS-91053 חוסמת את שליחת הבילד שלי?
Apple כותבת שמאז 1 במאי 2024, App Store Connect לא מקבל יותר אפליקציות שלא מתארות את השימוש שלהן ב-API האלה. ובכל זאת, מפתחים קיבלו את המייל על בילד שהתקבל, כאזהרה. בשני המקרים, תתקן את המניפסט לפני הבילד הבא.
איזה קוד סיבה לבחור ל-UserDefaults?
CA92.1 אם האפליקציה רק קוראת וכותבת את ההעדפות שלה. תוסיף 1C8F.1 אם היא משתפת אותן עם widget או extension דרך App Group. C56D.1 שמור ל-SDK של צד שלישי: אל תשים אותו במניפסט של האפליקציה שלך.
צריך להעתיק את המניפסט של כל SDK ל-app.json?
לא בהכרח. אם מיזוג המניפסטים פעיל, המניפסטים של תלויות CocoaPods מאוחדים בזמן התקנת ה-pods. תעתיק קטגוריה רק אם היא חסרה במניפסט הסופי, עם הסיבה שמתארת את השימוש האמיתי.
האם ה-widget או ה-extension שלי צריכים מניפסט משלהם?
לפי Apple, כל bundle שמכיל קובץ הרצה שמשתמש ב-API האלה חייב מניפסט משלו. extension הוא קובץ הרצה נפרד, ב-bundle משלו: המניפסט של האפליקציה לא מכסה אותו.
אפשר לתקן את ITMS-91053 בלי לבנות מחדש?
לא. מניפסט הפרטיות הוא חלק מהבינארי. תתקן את הקונפיגורציה, תבנה מחדש, ואז תבדוק את הבילד ב-TestFlight לפני שאתה שולח אותו לבדיקה.