ITMS-90683: sửa lỗi Missing purpose string với Expo
Bởi Mehdi Azizi
Đăng ngày , 6 phút
ITMS-90683: thêm khóa mô tả mà Apple nêu trong email vào ios.infoPlist của app.json, rồi build lại. Kiểm tra thư viện trước khi gửi để tránh lỗi.
ITMS-90683 là lỗi từ chối tự động của Apple: nó đến qua email ngay sau khi bạn gửi build, trước mọi khâu duyệt của con người. Nó có nghĩa là file Info.plist của bạn thiếu câu giải thích vì sao app truy cập một dữ liệu nhạy cảm. Cách sửa gói gọn trong hai bước: thêm khóa được nêu trong thông báo vào ios.infoPlist, rồi build lại.
Mình đã dính lỗi này với Solys, app báo thức kèm mini-game của mình, vì một dữ liệu mà app thậm chí không dùng tới. Dưới đây là ý nghĩa của thông báo, vì sao nó xuất hiện và cách tránh nó.
Lỗi ITMS-90683 nghĩa là gì?
Thông báo đầy đủ có tiêu đề "ITMS-90683: Missing purpose string in Info.plist". Nó cho biết code của app bạn tham chiếu tới một API đụng đến dữ liệu nhạy cảm (ảnh, camera, micro, vị trí, danh bạ), trong khi Info.plist không có khóa mô tả tương ứng. Thông báo sẽ nêu tên khóa đó, ví dụ NSPhotoLibraryUsageDescription.
Câu mô tả này gọi là "purpose string". Đó là đoạn văn bản iOS hiển thị trong hộp thoại xin quyền. Apple ghi rõ trong tài liệu về truy cập tài nguyên được bảo vệ: App Review từ chối các app có code truy cập những tài nguyên này mà không có purpose string.
Đây không phải lời từ chối của reviewer. Việc kiểm tra là tự động và diễn ra lúc build được giao, trước khi vào hàng duyệt, giống như ITMS-91053 với privacy manifest. Build bị loại và bạn phải gửi build khác.
Vì sao Apple từ chối dù app không dùng dữ liệu đó
Đây là điểm gây bất ngờ. Apple phân tích code nằm trong build của bạn, chứ không phải những gì app thực sự làm. Nếu một thư viện bạn đóng gói có tham chiếu tới thư viện ảnh, khóa đó vẫn bắt buộc, kể cả khi không màn hình nào xin quyền truy cập ảnh. Chính thông báo của Apple cũng nói rõ: một thư viện hoặc SDK bên ngoài có thể tham chiếu tới các API này, và purpose string vẫn bắt buộc.
Trường hợp của mình, ngày 26/9/2026. Khi dọn cấu hình của Solys, mình đã xóa khóa NSPhotoLibraryUsageDescription, vì app không đụng tới ảnh nào. Build tiếp theo bị từ chối với ITMS-90683. Nguyên nhân: hai thư viện Expo mà app dùng, expo-image và expo-file-system, có code tham chiếu tới thư viện ảnh. Build trước đó lọt qua vì khóa vẫn còn.
Bài học: đừng xóa một khóa mô tả chỉ vì "mình không dùng". Chỉ xóa khi không còn thư viện nào trong build tham chiếu tới API đó.
Các khóa thường gặp nhất
NSPhotoLibraryUsageDescription: đọc hoặc ghi ảnh.NSPhotoLibraryAddUsageDescription: thêm ảnh, không đọc.NSCameraUsageDescription: camera.NSMicrophoneUsageDescription: micro.NSLocationWhenInUseUsageDescription: vị trí khi đang dùng app.NSContactsUsageDescription: danh bạ.NSUserTrackingUsageDescription: theo dõi quảng cáo (App Tracking Transparency).
Apple mô tả từng khóa trong tài liệu, ví dụ trang về NSPhotoLibraryUsageDescription: khóa này bắt buộc ngay khi app dùng một API đọc hoặc ghi vào thư viện ảnh.
Sửa ITMS-90683 trong app Expo
- Ghi lại khóa được nêu trong email của Apple. Thông báo cho bạn tên chính xác.
- Thêm nó vào cấu hình, dưới
ios.infoPlist, như hướng dẫn trong tài liệu của Expo về quyền truy cập:
{
"expo": {
"ios": {
"infoPlist": {
"NSPhotoLibraryUsageDescription": "Solys không truy cập ảnh của bạn. Quyền này không bao giờ được yêu cầu."
}
}
}
}
- Build lại. Expo nói rõ: thay đổi Info.plist không thể đi qua bản cập nhật từ xa, nó cần một binary mới.
- Gửi lại build cho Apple, rồi chọn build đó trong phiên bản của bạn.
Một cái bẫy nếu app của bạn có bản dịch: các file ngôn ngữ chỉ dịch một khóa, chúng không khai báo khóa. Khóa phải tồn tại trước trong ios.infoPlist (hoặc trong cấu hình của plugin liên quan). Nếu không, app có thể crash ở lần gọi đầu tiên.
Viết câu gì nếu app không dùng dữ liệu đó?
Apple yêu cầu mô tả chính xác, hữu ích và cụ thể. Nếu app thật sự dùng dữ liệu, hãy nói nó dùng để làm gì, trong một câu: "App dùng camera để quét mã vạch trên vé của bạn."
Nếu khóa chỉ có mặt vì một thư viện, Apple đưa ra hai cách: viết câu mô tả, hoặc gỡ phần code truy cập dữ liệu. Khi code đó nằm trong thư viện, bạn không gỡ đơn giản được. Vì vậy với Solys, mình viết đúng sự thật: "Solys không truy cập ảnh của bạn. Quyền này không bao giờ được yêu cầu." Đây là lựa chọn thực dụng: build tiếp theo đã qua khâu giao nhận, nhưng mình không dám nói Apple sẽ luôn chấp nhận câu này.
Phát hiện khóa còn thiếu trước khi gửi
Từ thư mục gốc của project, lệnh này liệt kê các file thư viện có code iOS tham chiếu tới những API bị giám sát nhiều nhất:
grep -rlE "PHPhotoLibrary|AVCaptureDevice|CLLocationManager|CNContactStore|EKEventStore|ATTrackingManager" \
node_modules/*/ios node_modules/@*/*/ios
Mỗi tên ứng với một loại dữ liệu: PHPhotoLibrary cho ảnh, AVCaptureDevice cho camera và micro, CLLocationManager cho vị trí, CNContactStore cho danh bạ, EKEventStore cho lịch, ATTrackingManager cho theo dõi. Với mỗi kết quả, hãy kiểm tra khóa mô tả tương ứng đã có trong cấu hình chưa.
Tấm lưới này bắt được những trường hợp mình từng gặp. Nó không thay thế việc đọc email của Apple, vốn là danh sách duy nhất chắc chắn, giống như với các API không công khai của ITMS-90338. Từ lần bị từ chối đó, mình chạy bước kiểm tra này trước mỗi build: mất vài giây, trong khi một lần dính ITMS-90683 tốn một build và thời gian làm lại.
Gửi build mà không gặp bất ngờ
ITMS-90683 sửa nhanh khi bạn biết cách đọc nó, cũng như ITMS-90725, lỗi liên quan tới phiên bản Xcode. Những lần từ chối sau đó, từ reviewer, cần bình tĩnh hơn: cách xử lý có trong trang ứng dụng bị Apple từ chối, và các lý do phổ biến nhất nằm trong bài vì sao Apple từ chối app.
Để kiểm tra hồ sơ trước khi gửi, Apple Review Kit gom checklist của mình và các skill Claude Code đọc lại project của bạn. Nếu việc gửi bị kẹt và bạn muốn có người xem giúp, đặt một buổi một giờ với mình: mình cùng xem lại project qua video call, ngay trên màn hình của bạn. Còn nếu bạn đang chuẩn bị ra mắt app đầu tiên, làm bài chẩn đoán miễn phí: nó sắp xếp lại các bước theo đúng thứ tự và gửi bạn checklist chống bị Apple từ chối của mình.
Câu hỏi thường gặp
ITMS-90683 có phải là từ chối của App Review không?
Không theo nghĩa một reviewer là người. Đây là kiểm tra tự động trên build lúc giao, trước khi vào hàng duyệt, giống như ITMS-90717 với icon. Không ai mở app của bạn cả. Build bị loại: bạn cần sửa Info.plist và gửi build mới.
Vì sao Apple đòi khóa cho dữ liệu mà app của mình không dùng?
Vì Apple phân tích code có trong build, không phải hành vi của app. Nếu một thư viện được đóng gói tham chiếu tới thư viện ảnh hoặc camera, khóa mô tả là bắt buộc, kể cả khi không màn hình nào xin quyền đó.
Có sửa ITMS-90683 bằng bản cập nhật từ xa được không?
Không. Khóa bị thiếu nằm trong Info.plist, vốn là một phần của binary. Một bản cập nhật từ xa không thay đổi file này: bạn phải build lại và gửi lại cho Apple.
Thêm NSPhotoLibraryUsageDescription ở đâu trong project Expo?
Trong cấu hình app, dưới ios.infoPlist, kèm một câu mô tả mục đích sử dụng. Một số thư viện cũng có tùy chọn riêng trong plugin, có thể thêm các khóa khác, như một chế độ chạy nền. Dù cách nào, khóa phải tồn tại trong cấu hình gốc, không chỉ trong các file bản dịch.
Có nên xóa các khóa mô tả không dùng tới?
Chỉ khi không còn thư viện nào trong build tham chiếu tới API liên quan. Nếu không, lần gửi tiếp theo sẽ bị từ chối với ITMS-90683. Trước khi xóa một khóa, hãy tìm tên API trong code iOS của các dependency.