Trouble Shooting/iOS

ITMS-91053: Missing API declaration 해결

Gradler 2024. 4. 2. 13:47

언제부턴가 AppStore(앱스토어)나 TestFlight(테스트플라이트)에 앱을 업로드하면 다음과 같은 메일을 받게 됩니다.

 

개인정보 보호 매니페스트 파일에 이유를 설명하지 않고 필수 이유 API를 사용하는 앱을 App Store Connect에 업로드하는 경우, Apple은 앱의 개인정보 매니페스트에 이유를 추가하라고 알리는 이메일을 사용자에게 보냅니다. 2024년 5월 1일부터 개인 정보 매니페스트 파일에 필수 이유 API 사용을 설명하지 않는 앱은 App Store Connect에서 허용되지 않습니다.

 

이슈 안내 원문 메시지
We noticed one or more issues with a recent submission for App Store review for the following app:

Although submission for App Store review was successful, you may want to correct the following issues in your next submission for App Store review. Once you've corrected the issues, upload a new binary to App Store Connect.
https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.ITMS-91053: Missing API declaration - Your app’s code in the “MyApp” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.ITMS-91053: Missing API declaration - Your app’s code in the “MyApp” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryDiskSpace. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.ITMS-91053: Missing API declaration - Your app’s code in the “MyApp” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryUserDefaults. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.ITMS-91053: Missing API declaration - Your app’s code in the “MyApp” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategorySystemBootTime. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

 

메일 내용에 친절하게 우리 앱에서 사용하고 있는 어떤 필수 이유 API 가 있는지 자세히 알려주므로 해당 API를 사용하는 이유만 잘 찾아서 PrivacyInfo.xcprivacy 파일에 명시해 주면 되며, 이유도 개발자가 직접 적는것은 아니고 애플이 사전에 정의해놓은 사유들이 있고 그것에 해당하는 것을 찾아 선택해주면 됩니다. 사전에 정의해놓은 사유들은 메일 본문에 함께 적혀 있는 링크를 통해 확인하시면 됩니다.

 

개발자가 해야할 것

1. 프로젝트에 PrivacyInfo.xcprivacy 파일 생성하기

2. 앱에서 사용중인 필수 이유 API 추가하고 이유 명시하기

3. (필요시) 앱에서 사용중인 개인정보에 해당하는 데이터 식별하고 이유 명시하기

 

순서대로 프로젝트에 Privacy Manifest 파일을 생성하는 방법부터 살펴보겠습니다.

Info.plist를 포함하고 있는 상위 폴더에서 New File을 선택합니다.

 

아래방향으로 스크롤 해서 App Privacy 항목을 선택하고 Next 버튼을 누릅니다.

 

파일을 생성할 위치를 선택하는데 이 때 반드시 Targets을 체크 하셔야 합니다. 

만일 Targets을 체크하지 않고 추가한 경우, Build Phases에서 Copy Bundle Resources에서 수동으로 추가할 수 있습니다.

 

이제 앱에서 사용중인 필수 이유API를 추가하고 이유를 명시해보겠습니다.

 

메일본문에 있던 링크를 클릭해서 들어간 후에 메일 본문에서 API Categories로 명시한 NS~~ 시작하는 API를 검색합니다.

(https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api)
영어로 나오기는 하지만 번역해서 봐도 이해하는데는 무리가 없습니다. 아마도 대다수의 앱들이 필수 이유 API를 사용하는 이유는 비슷비슷 할 것으로 예상하지만 혹시 모르니 본인의 앱에서 사용중인 필수 이유 API들을 해당 링크에서 검색해보시고 맞는 이유를 기입해주시면 될 것 같습니다.

 

우리 앱이 포함하고 있는 필수 이유 API

- NSPrivacyAccessedAPICategoryFileTimestamp

- NSPrivacyAccessedAPICategoryUserDefaults

- NSPrivacyAccessedAPICategoryDiskSpace

- NSPrivacyAccessedAPICategorySystemBootTime

 

NSPrivacyAccessedAPICategoryFileTimestamp로 검색해보니 다음과 같이 사전에 정의해 둔 이유들에 대한 코드가 나와있습니다.

 

우리 앱에서 선택한 각 API 사유는 다음과 같습니다.

 

위와 같이 GUI를 이용해서 선택해서 입력하는 방식도 있지만 우측 상단에 있는 우측 좌측 화살표가 위아래로 배치된 아이콘 모양을 눌러서 xml 형태로 파일을 수정할 수도 있으니 참고해 주세요.

 

API 명시와 이유를 모두 선택했다면 Archive한 파일에서 Generate Privacy Report 를 선택해서 파일이 제대로 생성되고 내용에도 문제가 없는지 확인합니다.

 

필수이유 API 명시만으로는 부족한 경우도 있습니다.

 

파일은 잘 생성되었는데 생성해보니 다음과 같은 내용이 포함되어 있음을 확인할 수 있었습니다.

▲ Errors Encountered
Missing an expected key: 'NSPrivacyCollectedDataTypes'
MyApp.app/PrivacyInfo.xcprivacy

 

이제 앱에서 사용중인 개인정보에 해당하는 데이터 식별하고 이유를 명시해야 합니다.

 

개인정보에 해당 하는 데이터 목록과 사전에 정의해둔 이유는 아래 링크를 통해 확인 할 수 있습니다.

https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests

 

우리 앱의 경우에는 사용자 식별을 위해 사용자의 Email 주소를 수집하고 있고, 앱에 문제가 생겼을 때 빠른 대처를 위해 Crash Data를 수집하고 있었는데 이 부분도 명시를 해줘야 하는 것 같습니다.

 

우리앱에서 수집되는 데이터 목록과 사유는 다음과 같이 명시해 주었습니다.

 

이제 Privacy Manifest가 제대로 생성되는지 다시 한번 Archive > Generate Privacy Report 를 해보니 파일도 정상적으로 생성되고, 내용에도 문제 없음이 확인되었습니다.

 

우리앱의 최종 PrivacyInfo 파일은 다음과 같이 만들었습니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyCollectedDataTypes</key>
<array>
    <dict>
        <key>NSPrivacyCollectedDataType</key>
        <string>NSPrivacyCollectedDataTypeCrashData</string>
        <key>NSPrivacyCollectedDataTypeLinked</key>
        <false/>
        <key>NSPrivacyCollectedDataTypeTracking</key>
        <false/>
        <key>NSPrivacyCollectedDataTypePurposes</key>
        <array>
            <string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
        </array>
    </dict>
    <dict>
        <key>NSPrivacyCollectedDataType</key>
        <string>NSPrivacyCollectedDataTypeEmailAddress</string>
        <key>NSPrivacyCollectedDataTypeLinked</key>
        <true/>
        <key>NSPrivacyCollectedDataTypeTracking</key>
        <false/>
        <key>NSPrivacyCollectedDataTypePurposes</key>
        <array>
            <string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
        </array>
    </dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
    <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
            <string>7D9E.1</string>
        </array>
    </dict>
    <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategorySystemBootTime</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
            <string>E174.1</string>
        </array>
    </dict>
    <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
            <string>DDA9.1</string>
        </array>
    </dict>
    <dict>
        <key>NSPrivacyAccessedAPIType</key>
        <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
        <key>NSPrivacyAccessedAPITypeReasons</key>
        <array>
            <string>CA92.1</string>
        </array>
    </dict>
</array>
</dict>
</plist>

 

최종적으로 App Store Connect에 업로드해서 경고 메일이 오지 않는지도 확인이 필요합니다.

제가 관리하고 있는 앱이 5~6개 정도 되는데, 그 중 한 두개는 파일을 생성할때 Targets에 포함하지 않아서 리포트는 생성되지만 이슈는 해결되지 않고 메일이 계속 오는 경우도 있더라구요. 

 

해당 이슈를 해결하기 위해 여러 자료들을 찾아봤을 때 앱에서 사용하고 있는 SDK도 모두 업데이트를 해야 하는 줄 알고 바짝 긴장했었는데, 꼭 그렇지만은 않은 것 같습니다.

 

실제로 위에 명시한 필수이유 API Category 중 FileTimestamp, DiskSpace, SystemBootTime은 SDK(Alamofire, Firebase 등)에서 사용하고 있는 것들이지 제 프로젝트에서 직접 사용하는 API는 아니었고, 명시한 데이터 중 Crash Data도 마찬가지이기 때문입니다.

 

5월 1일까지 이제 진짜 얼마 남지 않았습니다.
그 이후에 앱 업데이트 계획이 있으신 분들에게 도움 되는 자료가 되길 바라며 이만 줄이겠습니다.