iOS 27.2의 EU 추적 프롬프트: 무엇을 출시해야 하는가
iOS 27.2와 iPadOS 27.2부터 유럽연합(EU) 안의 앱은 대체 버전의 App Tracking Transparency 프롬프트를 띄울 수 있고, 프랑스, 독일, 이탈리아, 폴란드, 루마니아에 배포되는 앱은 새 호출에서도 예전 호출에서도 그 버전만 받게 됩니다. 27.2 베타 SDK가 더한 것은 메서드 하나와 Info.plist 키 하나입니다. 메서드는 requestTrackingAuthorization(usingExpandedInterface:additionalInformationAction:completionHandler:)로 iOS 27.2에서 쓸 수 있고 macOS, tvOS, watchOS, visionOS에서는 쓸 수 없습니다. 키는 선택 사항인 NSUserTrackingMarkdownUsageDescription입니다. EU 밖에서는 새 호출도 예전 호출처럼 동작하고, 언제 허락을 구해야 하는지에 대한 규칙도 그대로이며, EU 사용자에게는 마지막 응답으로부터 1년 뒤에 다시 물을 수 있습니다. 출시 절차는 아래에 정리했습니다. 27.2 베타 시뮬레이터에서 지역을 미국, 독일, 네덜란드, 프랑스로 설정하고 재부팅 직후에 반복할 수 있었던 호출은 모두 표준 알림창을 띄웠는데, 이는 EU 안에 있지 않은 기기를 위한 폴백으로 Apple이 문서에 적어 둔 동작입니다. 이 증거만 놓고 보면 시트 확인은 실기기 테스트입니다.12345
{.answer-block}
TL;DR
- Apple의 공지, 9월 16일. “Beginning with iOS 27.2 and iPadOS 27.2, developers will have the option to use an alternative version of the App Tracking Transparency system prompt in the EU. The requirements for when you must seek permission to track users will remain the same. Due to legal requirements, only the alternative version of the system prompt is available for apps distributed in Germany, France, Italy, Poland, and Romania.”(iOS 27.2와 iPadOS 27.2부터 개발자는 EU에서 ATT 시스템 프롬프트의 대체 버전을 쓸 수 있다. 추적 허락을 구해야 하는 조건은 그대로다. 법적 요건 때문에 독일, 프랑스, 이탈리아, 폴란드, 루마니아에 배포되는 앱에는 대체 버전만 제공된다.)1
- 새 메서드는 하나입니다. 27.2 베타 SDK의
ATTrackingManager.h는requestTrackingAuthorizationUsingExpandedInterface:additionalInformationAction:completionHandler:를API_AVAILABLE(ios(27.2)) API_UNAVAILABLE(macos, tvos, watchos, visionos)와 함께 선언합니다. 헤더 주석은 이렇습니다. “This method behaves identically torequestTrackingAuthorizationWithCompletionHandler:in non-EU countries.”(EU 밖의 국가에서는 기존 메서드와 똑같이 동작한다.)3 - 다섯 나라에서는 예전 호출도 시트를 띄웁니다.
requestTrackingAuthorization(completionHandler:)의 Apple 레퍼런스 페이지에는 이렇게 적혀 있습니다. “In France, Germany, Italy, Poland, and Romania, the system presents a full-page sheet; otherwise, the system prompts the person with an alert.” 그리고 그 시트는 “displays theNSUserTrackingMarkdownUsageDescriptionstring with support for rich-text elements if you include it in your app’s target configuration in Xcode.”라고 합니다. 새 호출이 더해 주는 것은 EU의 나머지 나라에서의 시트, “Additional Information” 버튼, 그리고 그것을 요청하는 플래그입니다.4 - 키는 하나 늘었고, 기존 키는 여전히 필수입니다.
NSUserTrackingMarkdownUsageDescription은 선택 사항인 Markdown이며 “bold or italic style,” 글머리 기호 목록, 문단 나누기를 쓸 수 있지만 “but it doesn’t support underline”입니다. 헤더는 새 호출에서도 기존NSUserTrackingUsageDescription이 Info.plist에 “must be in”이라고 말합니다.34 - “Additional Information” 버튼은 예도 아니고 아니오도 아닙니다. Apple의 헤더는 이렇게 말합니다. “If the user taps the ‘Additional Information’ button, the prompt dismisses without recording an authorization decision, your
additionalInformationActionruns so you can surface your own privacy information, and the completion handler receivesnotDetermined.”(사용자가 그 버튼을 누르면 권한 결정이 기록되지 않은 채 프롬프트가 닫히고,additionalInformationAction이 실행되어 직접 만든 개인정보 안내를 보여줄 수 있으며, 완료 핸들러는notDetermined를 받는다.) 그다음에 다시 묻는 일은 여러분의 코드가 해야 합니다.3 - 재요청은 EU에서만. “you can reprompt a user via the App Tracking Transparency system prompt one year after the user’s previous choice in your app’s App Tracking Transparency system prompt, regardless of whether that choice was to accept or reject,”(앱의 ATT 시스템 프롬프트에서 사용자가 이전에 선택한 지 1년이 지났다면, 그 선택이 수락이든 거부든 다시 물을 수 있다.) 다만 사용자가 “Allow Apps to Request to Track”을 꺼 둔 경우는 예외입니다. 이 설정의 이름은 EU에서 “Allow Apps to Request to Link Your Activity Across Companies”로 바뀝니다.2
- 시뮬레이터가 보여준 것. iOS 27.2 베타 런타임의 iPhone 18 Pro 시뮬레이터에서 지역을 미국, 독일, 네덜란드, 프랑스로 설정하고
preferExpandedInterface: true로 새 호출을 했을 때 나온 것은 기존 usage description이 담긴 표준 알림창이었고, “Additional Information” 버튼은 없었습니다.false도, nil 액션도, 예전 호출도 마찬가지였으며, 완료 핸들러는 탭을 기다렸고 상태는notDetermined에 머물렀습니다. 반대로 곧바로notDetermined가 돌아오는 경로가 하나 있는데, 이것은 원할 때마다 재현되며 아래에 적어 두었습니다. 앞선 실행에서 아직 남아 있는 프롬프트입니다. 9월 20일에는 프랑스 실행 두 번도 곧바로 돌아왔지만, 이쪽은 제가 기록할 수 있는 원인이 없었고, 같은 구성이 이후 재부팅 직후의 실행에서는 프롬프트를 띄웠습니다.5
Apple의 표현으로 본 변경점
Apple은 이 변경을 세 군데에서 글로 밝혔고, 첫 번째는 이유까지 적어 둔 9월 16일 공지입니다. “As part of agreements with select European competition authorities, Apple is introducing changes to its App Tracking Transparency framework in the European Union.”(유럽의 일부 경쟁 당국과 맺은 합의의 일환으로, Apple은 EU에서 App Tracking Transparency 프레임워크를 변경한다.) 공지의 나머지는 규칙과 다섯 나라를 밝힙니다.1 App Store 정책 페이지는 프롬프트의 모양을 덧붙입니다. “The alternative version of the App Tracking Transparency system prompt has modified formatting and language and provides you the option to use a text button labeled “Additional Information.” This allows you to surface additional information about your request to link user or device data collected from your app with user or device data collected from other companies’ apps, websites, or offline properties for targeted advertising or advertising measurement purposes, or to share user or device data with a data broker.”(대체 버전은 서식과 문구가 바뀌었고 “Additional Information”이라는 텍스트 버튼을 쓸 수 있는 선택지를 준다. 이를 통해 타깃 광고나 광고 측정을 위해 앱에서 모은 사용자·기기 데이터를 다른 회사의 앱, 웹사이트, 오프라인 자산에서 모은 데이터와 연결하려는 요청, 또는 데이터 브로커에게 데이터를 제공하려는 요청에 대해 추가 정보를 보여줄 수 있다.)2 그리고 iOS 및 iPadOS 27.2 베타 릴리스 노트는 App Tracking Transparency의 New Features 항목에서 한 줄로 정리합니다. AppTrackingTransparency는 “now supports an alternative expanded prompt and re-prompting on a yearly basis for EU users. The alternative prompt is required for users in France, Germany, Italy, Poland, and Romania.”(EU 사용자를 위한 대체 확장 프롬프트와 연 단위 재요청을 지원한다. 대체 프롬프트는 프랑스, 독일, 이탈리아, 폴란드, 루마니아 사용자에게 필수다.)6
정책 페이지는 그대로인 것도 밝힙니다. 추적하기 전에 물어야 한다는 요구 사항, 그리고 버튼 너머에 있는 모든 것에 대한 개발자의 책임입니다. “Any additional information related to your request or more granular consent controls provided via the text button are entirely your responsibility. However, you cannot access the device’s advertising identifier, or otherwise collect and use device or user data from your app as described in the App Tracking Transparency system prompt, until the user has granted your app permission in that prompt.”(텍스트 버튼으로 제공하는 추가 정보나 더 세분화된 동의 설정은 전적으로 개발자의 책임이다. 다만 사용자가 그 프롬프트에서 앱에 권한을 주기 전까지는 기기의 광고 식별자에 접근할 수도, ATT 시스템 프롬프트에 적힌 방식으로 앱에서 기기나 사용자 데이터를 수집해 쓸 수도 없다.)2
27.2 SDK의 API
Xcode 27.2 베타(27B5019j)는 iOS 27.2 SDK를 빌드 24B5084k로 담고 있고, 그 AppTrackingTransparency.framework 헤더에는 이미 쓰고 있는 메서드 옆에 클래스 메서드가 하나 늘었습니다.3
+ (void)requestTrackingAuthorizationUsingExpandedInterface:(BOOL)preferExpandedInterface
additionalInformationAction:(nullable void(^)(void))additionalInformationAction
completionHandler:(void(^)(ATTrackingManagerAuthorizationStatus status))completion API_AVAILABLE(ios(27.2)) API_UNAVAILABLE(macos, tvos, watchos, visionos);
Swift에서는 ATTrackingManager.requestTrackingAuthorization(usingExpandedInterface:additionalInformationAction:completionHandler:)가 되고, Apple 레퍼런스 페이지는 이를 iOS 27.2, iPadOS 27.2, Mac Catalyst 27.2로, 모두 베타로 표시합니다. 헤더 주석은 Apple이 공개한 것 중 두 매개변수에 대한 가장 자세한 설명이며, 그중 네 문장이 호출을 어떻게 쓸지 결정합니다.34
- “Pass
YEStopreferExpandedInterfaceto request the alternative prompt where permitted; passNOto request the original prompt.”(허용되는 곳에서 대체 프롬프트를 원하면YES, 기존 프롬프트를 원하면NO를 넘긴다.) 매개변수에 대해서는 이렇게 덧붙입니다. “Note that in France, Germany, Italy, Poland, and Romania, due to legal requirements, only the expanded interface version of the ATT prompt will be available regardless of what is passed in topreferExpandedInterface.”(다섯 나라에서는 법적 요건 때문에preferExpandedInterface에 무엇을 넘기든 확장 인터페이스 버전만 제공된다.) - “If you pass
niltoadditionalInformationAction, this button will not be shown.”(additionalInformationAction에nil을 넘기면 이 버튼은 표시되지 않는다.) - “If the user taps the ‘Additional Information’ button, the prompt dismisses without recording an authorization decision, your
additionalInformationActionruns so you can surface your own privacy information, and the completion handler receivesnotDetermined.”(버튼을 누르면 권한 결정이 기록되지 않은 채 프롬프트가 닫히고, 액션이 실행되며, 완료 핸들러는notDetermined를 받는다.) - “iOS users may be re-prompted in eligible regions on a periodic basis even after a previous authorization decision. If the user is not eligible to be re-prompted and a previous authorization decision exists, the completion handler is called with that prior decision without showing the prompt.”(해당 지역에서는 이전 결정이 있어도 주기적으로 다시 물을 수 있다. 재요청 대상이 아니면서 이전 결정이 있으면, 프롬프트를 띄우지 않고 그 결정이 완료 핸들러로 전달된다.)
레퍼런스 페이지는 헤더가 암시만 하던 지역별 표를 실제로 그려 줍니다. 프랑스, 독일, 이탈리아, 폴란드, 루마니아에서는 “The system displays markdown text you supply via NSUserTrackingMarkdownUsageDescription in a full-page sheet regardless of what you set for preferExpandedInterface, and includes an Additional Information button if you supply an action.”(preferExpandedInterface 값과 상관없이 전체 화면 시트에 Markdown을 띄우고, 액션을 넘기면 Additional Information 버튼도 넣는다.)입니다. EU의 나머지 나라에서는 “The system displays markdown text in the NSUserTrackingMarkdownUsageDescription, if you supply it. The system displays the full-page sheet if you set preferExpandedInterface to true, and includes an Additional Information button if you supply an action.”(Markdown을 넣어 두었다면 띄우고, preferExpandedInterface가 true면 전체 화면 시트를 띄우며, 액션을 넘기면 버튼도 넣는다.)입니다. 그 밖의 지역에서는 “Outside of the European Union, the system doesn’t use either parameter, and presents a system alert displaying the original NSUserTrackingUsageDescription, which is equivalent to calling requestTrackingAuthorization(completionHandler:).”(EU 밖에서는 두 매개변수를 모두 쓰지 않고 기존 설명 문구를 담은 시스템 알림창을 띄우며, 이는 예전 호출과 같다.)입니다. 페이지는 지역 판정 조건도 덧붙입니다. 기기가 “located in a specific European Union country and signed in with an Apple Account with a specific EU country or region”(특정 EU 국가에 있고, 특정 EU 국가 또는 지역의 Apple Account로 로그인되어 있는) 상태여야 합니다.4
예전 호출인 requestTrackingAuthorization(completionHandler:)의 페이지도 이제 다섯 나라에서는 이 호출로도 시트가 뜬다고 밝힙니다. “In France, Germany, Italy, Poland, and Romania, the system presents a full-page sheet; otherwise, the system prompts the person with an alert.”라고 적혀 있고, 타깃 속성 항목에서는 “In France, Germany, Italy, Poland, and Romania, the full-page sheet displays the NSUserTrackingMarkdownUsageDescription string with support for rich-text elements if you include it in your app’s target configuration in Xcode.”(Xcode의 타깃 설정에 Markdown 키를 넣어 두면 다섯 나라의 전체 화면 시트가 리치 텍스트로 보여 준다.)라고 합니다. 이 페이지는 시트의 버전을 적지 않고 메서드를 iOS 14로 두면서 베타 표시도 달지 않으므로, 시트의 27.2라는 하한은 이 페이지가 아니라 릴리스 노트에서 나옵니다. 함께 읽으면, 새 호출로 얻는 것은 EU의 나머지 나라에서의 시트, 버튼, 그리고 플래그를 직접 정할 권한입니다. 다섯 나라에서는 어느 쪽 호출이든 시트가 뜹니다.46
두 개의 Info.plist 키
NSUserTrackingUsageDescription은 사라지지 않습니다. 새 메서드에 달린 헤더의 “Important” 주석은 기존 요구 사항을 글자 그대로 되풀이합니다. 이 키는 정보 속성 목록에 “must be in”이어야 하고, 새 키의 레퍼런스 페이지도 “if your app’s target properties omit this key”(앱의 타깃 속성에 이 키가 없으면)인 경우 시스템이 기존 키로 되돌아간다고 밝힙니다.34
새로 더해진 것이 NSUserTrackingMarkdownUsageDescription이고, iOS 27.2와 iPadOS 27.2 베타로 표시되어 있습니다. Apple의 페이지는 이렇게 말합니다. “The format of the string is Markdown text; you can apply bold or italic style, but it doesn’t support underline. You can include bullet lists and paragraph breaks.”(문자열 형식은 Markdown이다. 굵게와 기울임은 쓸 수 있지만 밑줄은 지원하지 않는다. 글머리 기호 목록과 문단 나누기는 넣을 수 있다.) 이 키는 프롬프트와 같은 방식으로 지역을 탑니다. 다섯 나라에서는 넣어 두기만 하면 예전 호출에서도 새 호출에서도 쓰이고, EU의 나머지 나라에서는 preferExpandedInterface: true를 넘겼을 때 쓰이며, EU 밖에서는 무시됩니다. Apple의 두 페이지는 이 중간 경우를 다르게 적습니다. 메서드 페이지는 Markdown을 “if you supply it”(넣어 두었다면) 띄운다고만 하고, 키 페이지는 true를 넘겨야 한다는 조건을 덧붙입니다. 더 엄격한 쪽은 키 페이지이고, 위의 그림도 그쪽을 따랐습니다. 이 페이지에 실린 Apple의 조언은 기존 추적 키 페이지에 있는 것과 같습니다. “Keep the text of your description short and specific. The system displays your app name in the prompt so you don’t need to include it in the string.”(설명은 짧고 구체적으로 쓰라. 앱 이름은 시스템이 프롬프트에 표시하므로 문자열에 넣을 필요가 없다.)4
1년 주기 재요청
정책 페이지는 EU에서의 규칙을 이렇게 정합니다. “you can reprompt a user via the App Tracking Transparency system prompt one year after the user’s previous choice in your app’s App Tracking Transparency system prompt, regardless of whether that choice was to accept or reject. A user cannot be re-prompted if they have disabled “Allow Apps to Request to Track” (renamed to “Allow Apps to Request to Link Your Activity Across Companies” in the EU) in their device’s Settings.”(이전 선택으로부터 1년이 지났다면 수락이든 거부든 다시 물을 수 있다. 다만 기기 설정에서 해당 항목을 꺼 둔 사용자에게는 다시 물을 수 없다.)2 헤더는 앱 쪽에서 본 작동 방식을 두 번 설명합니다. 예전 메서드에 대해서는 이렇습니다. “In eligible regions, iOS users may be re-prompted after a year has passed since their last decision; otherwise the system remembers the user’s choice and doesn’t prompt again unless the user uninstalls and then reinstalls the app on the device.”(해당 지역에서는 마지막 결정으로부터 1년이 지나면 다시 물을 수 있고, 그렇지 않으면 시스템이 선택을 기억하여 앱을 지웠다가 다시 설치하지 않는 한 다시 묻지 않는다.) 새 메서드에 대해서는, 재요청 대상이 아니면서 이전 결정이 있는 사용자에게는 그 결정이 “without showing the prompt”(프롬프트를 띄우지 않고) 완료 핸들러로 돌아온다고 합니다. 그러니 두 번째 호출은 해도 안전하고, 프롬프트를 띄울지 말지는 여러분의 코드가 아니라 시스템이 정합니다.3 두 문서 어디에도 없는 것은 호출하기 전에 그 사용자가 재요청 대상인지 물어볼 방법입니다. 호출 자체가 질의입니다.
27.2 베타 시뮬레이터가 보여주는 것
저는 iPhoneSimulator 27.2 SDK를 대상으로 파일 하나짜리 SwiftUI 프로브를 만들고 Info.plist에 두 키를 모두 넣었습니다. NSUserTrackingUsageDescription은 “Probe: the standard usage description.”으로, NSUserTrackingMarkdownUsageDescription은 굵은 낱말 하나, 기울인 구절 하나, 두 항목짜리 글머리 기호 목록으로 채웠습니다. 이것을 iOS 27.2 베타 런타임(24B5084k)의 iPhone 18 Pro 시뮬레이터에서 실행하면서, 매 실행 전에 시뮬레이터를 재부팅하고 지역은 전역 AppleLocale 설정으로 바꿨습니다. 9월 19일의 여섯 번은 미국, 독일, 네덜란드를 preferExpandedInterface: true와 액션으로, 독일을 false로, 프랑스를 true에 액션 없이, 그리고 독일을 예전 호출로 돌린 것입니다.5
9월 19일에는 모든 실행이 같은 결과를 냈습니다. 제목이 “Allow “ATTProbe” to track your activity across other companies’ apps and websites?”인 표준 알림창에 기존 usage description이 담겼고, 버튼은 “Ask App Not to Track”과 “Allow” 둘뿐이었으며 세 번째 버튼은 없었습니다. Markdown 텍스트는 한 번도 나타나지 않았고, 16초 동안의 캡처 안에서 완료 핸들러는 실행되지 않았으며, 확장 호출 다섯 번에서는 3초마다 하는 확인에서 12초 동안 trackingAuthorizationStatus가 notDetermined였습니다. 예전 호출을 쓴 실행은 mode=legacy 줄을 남긴 뒤 아무것도 남기지 않았고, 같은 방식으로 기다렸습니다.5 이는 EU 안에 있지 않은 기기에 대해 Apple의 레퍼런스 페이지가 예고한 그대로입니다. 시뮬레이터의 지역 설정은 로케일이지 위치가 아닙니다. 시트와 Markdown 텍스트와 버튼은 EU 지역 Apple Account를 쓰는 실기기 테스트입니다.
9월 20일에 Mac을 재부팅한 뒤 같은 여섯 번을 다시 돌리자 미국, 독일, 네덜란드는 앞서와 같이 프롬프트가 떴지만, 프랑스 실행은 요청과 같은 초에 완료 핸들러로 notDetermined를 돌려주고 알림창을 띄우지 않았습니다. 그날 아침 프랑스로 두 번 더 실행했을 때도 같았고, 세 번째에는 프롬프트가 떴습니다. 곧바로 돌아온 세 번 가운데 파일에 남은 기록과 겹치는 것은 7:23 하나뿐으로, 다른 스크립트가 그 아래에서 프로브를 다시 설치하고 있었습니다. 7:21과 7:26에는 제가 기록할 수 있는 원인이 없습니다. 다른 어떤 것도 시뮬레이터를 건드리지 않은 상태에서 재부팅 직후 실행을 세 번 더, 액션이 있는 프랑스, 액션이 없는 프랑스, 그리고 미국으로 해 보니 모두 프롬프트가 뜨고 기다렸습니다. 그러니까 같은 프랑스 구성이 이후 재부팅 직후 실행에서는 프롬프트를 띄웠고, 제가 보고할 프랑스 규칙은 없습니다. 있는 것은 주의 하나뿐입니다. 베타 시뮬레이터에서 알림창 없이 곧바로 notDetermined가 돌아왔다면, 믿기 전에 재부팅 직후 상태에서 다시 확인해야 합니다.5

9월 19일, 지역을 독일로 설정한 iOS 27.2 베타 시뮬레이터에서 확장 인터페이스 호출을 한 직후의 모습입니다. 표준 알림창, 기존 설명 문구, 버튼 두 개. 이 이미지는 그날의 나머지 파일을 가져가 버린 재부팅 전에 내보낼 수 있었던 단 하나입니다.
원할 때마다 재현되는 잘못된 길은 대기 중인 프롬프트입니다. 프로브를 실행하고, 알림창에 답하지 않은 채로 앱을 지웠다가 다시 설치한 뒤 또 실행합니다. 그러면 두 번째 실행의 확장 호출은 알림창이 화면에 남아 있는 동안 요청과 같은 초에 완료 핸들러로 notDetermined를 돌려주었고, 예전 호출을 쓴 세 번째 실행도 마찬가지로 1초 안에 legacy-request status=0 (notDetermined)을 남겼습니다. 이것이 헤더가 설명하는 경우입니다. “The authorization prompt doesn’t display if another permission request is pending user confirmation. Concurrent requests aren’t preserved by iOS,”(다른 권한 요청이 사용자 확인을 기다리는 중이면 이 프롬프트는 뜨지 않는다. 동시에 들어온 요청은 iOS가 보존하지 않는다.)에 이어, trackingAuthorizationStatus가 notDetermined인지 확인해서 “to determine if you need to make an additional call”(호출을 한 번 더 해야 하는지 판단하라)는 지시가 붙습니다. 예전 호출의 페이지도 시스템이 프롬프트 없이 완료 핸들러를 실행하는 경우 목록에 “An existing permission request is pending.”(기존 권한 요청이 대기 중이다.)을 올려 두었습니다.345 재부팅하면 풀립니다. 앱이 여러 곳에서 묻거나 일정에 따라 다시 묻는다면, 두 번째로 호출한 쪽이 받는 것이 바로 이 즉시 notDetermined입니다.
무엇을 출시해야 하는가, 단계별로
NSUserTrackingUsageDescription을 그대로 둡니다. 여전히 필수이고, EU 밖의 모든 사용자와 Markdown 키가 없는 EU 사용자 전원이 보게 될 문구입니다.34NSUserTrackingMarkdownUsageDescription을 추가합니다. 같은 요청을 짧은 Markdown으로 씁니다. 굵게나 기울임, 글머리 기호, 문단 나누기까지. 밑줄은 안 되고, 앱 이름도 넣지 않습니다.4- 새 호출은 가용성으로 감쌉니다. 예전 호출은 폴백으로 남겨 둡니다. iOS 27.2 이상에서는
requestTrackingAuthorization(usingExpandedInterface:additionalInformationAction:completionHandler:)를, 그 이전에서는requestTrackingAuthorization(completionHandler:)를 부릅니다. EU의 나머지 나라에서 시트를 띄우려면true를 넘기고, 다섯 나라는 이 플래그를 무시합니다. iOS 26을 하한으로 두고 27.2 SDK에 대해 타입 검사를 통과하는 형태는 이렇습니다.345
#if os(iOS)
if #available(iOS 27.2, *) {
ATTrackingManager.requestTrackingAuthorization(usingExpandedInterface: true,
additionalInformationAction: showPrivacyDetails) { status in
handle(status)
}
} else {
ATTrackingManager.requestTrackingAuthorization { status in handle(status) }
}
#endif
- 버튼을 넣을지 정합니다. 액션은 보여 줄 페이지나 화면이 있을 때만 넘깁니다. 액션이 실행되면 상태를
notDetermined로 다루고, 준비한 안내를 보여 준 다음, 정책 페이지의 표현대로 “you can redirect the user back to the App Tracking Transparency system prompt for your app to ensure their choice is recorded”(선택이 기록되도록 사용자를 앱의 ATT 시스템 프롬프트로 되돌릴 수 있다.) 하면 됩니다. 다만 “you should not redirect users to your ATT prompt if they have opted out of all relevant legal consent choices in the screen or page surfaced”(보여 준 화면이나 페이지에서 관련 법적 동의를 모두 거부한 사용자는 ATT 프롬프트로 되돌리지 말아야 한다.)입니다.23 - 재요청은 타이머가 아니라 호출로 계획합니다. EU에서 1년이 지났는지 알아내는 방법은 다시 부르는 것입니다. 대상이 아닌 사용자에게는 완료 핸들러가 이전 결정을 돌려줍니다.23
- EU 지역 계정을 쓰는 실기기에서 테스트합니다. 시뮬레이터가 프롬프트를 띄운 경우는 어느 지역에서든, 재부팅 직후든 언제나 표준 알림창이었고 시트는 한 번도 나오지 않았습니다. Apple이 내건 조건은 기기의 위치와 Apple Account의 지역 둘 다이므로, 전체 화면 시트는 실기기 테스트입니다.45
- Mac 타깃을 확인합니다. 헤더는 이 메서드를 macOS, tvOS, watchOS, visionOS에서 쓸 수 없다고 표시하므로, 공유하는 호출 지점은
#if os(iOS)로 감싸고 그 안에if #available(iOS 27.2, *)를 두어야 합니다. 가용성 검사만으로는 컴파일이 되지 않고, 각주 5에 적어 둔 대로'requestTrackingAuthorization(usingExpandedInterface:additionalInformationAction:completionHandler:)' is unavailable in macOS로 실패합니다. 레퍼런스 페이지의 Mac Catalyst 27.2 항목과 헤더의API_UNAVAILABLE(macos)는 같은 선을 양쪽에서 그린 것입니다. Catalyst는#if os(iOS)입장에서 iOS이기 때문입니다.345
자주 묻는 질문
대체 프롬프트를 꼭 채택해야 합니까?
프랑스, 독일, 이탈리아, 폴란드, 루마니아에서는 그곳에 배포되는 앱이 쓸 수 있는 버전이 대체 프롬프트뿐이라고 Apple의 공지가 밝히고 있으며, 27.2에서는 어느 호출로도 그것이 나옵니다. 새 호출은 “regardless of what you set for preferExpandedInterface”(preferExpandedInterface에 무엇을 설정하든) 그 다섯 나라에서 전체 화면 시트를 띄우고, 예전 호출에 대한 Apple의 페이지도 “In France, Germany, Italy, Poland, and Romania, the system presents a full-page sheet; otherwise, the system prompts the person with an alert.”라고 하며 Markdown 키는 “if you include it in your app’s target configuration in Xcode.”(Xcode의 타깃 설정에 넣어 두었다면) 표시된다고 합니다. 새 호출로 옮겨서 얻는 것은 EU의 나머지 나라에서의 시트, “Additional Information” 버튼, 그리고 플래그를 직접 정할 권한입니다.1346
허락을 구해야 하는 시점이 바뀝니까?
아닙니다. Apple은 이렇게 말합니다. “The requirements for when you must seek permission to track users will remain the same.”1
Markdown 키가 NSUserTrackingUsageDescription을 대신합니까?
아닙니다. 기존 키는 두 호출 모두에서 여전히 필수이고, Markdown 키가 없거나 기기가 EU 밖에 있을 때 시스템은 기존 키를 씁니다.34
사용자가 거부한 뒤에 다시 물을 수 있습니까?
EU에서는 이전 선택으로부터 1년 뒤에 다시 물을 수 있습니다. “regardless of whether that choice was to accept or reject,”(그 선택이 수락이든 거부든) 다만 EU에서 Apple이 “Allow Apps to Request to Link Your Activity Across Companies”로 이름을 바꾼 설정을 사용자가 꺼 두었다면 그렇지 않습니다.2
새 API가 macOS나 visionOS에도 있습니까?
없습니다. 27.2 SDK 헤더는 API_UNAVAILABLE(macos, tvos, watchos, visionos)로 표시하고 있고, 레퍼런스 페이지가 적어 둔 것은 iOS, iPadOS, Mac Catalyst 27.2입니다.34
출처
-
Apple, “Updates to App Tracking Transparency in the European Union”, 개발자 뉴스, 2026년 9월 16일, 인용. ↩↩↩↩↩
-
Apple, User privacy and data use, “ATT in the European Union” 절과 “Can I provide additional information and consent controls with my app’s ATT prompt implementation” 항목, 2026년 9월 19일 확인, 인용. ↩↩↩↩↩↩↩↩
-
Xcode 27.2 베타(27B5019j) 안의 iPhoneOS 27.2 SDK(
ProductBuildVersion24B5084k,ProductVersion27.2)에 있는AppTrackingTransparency.framework/Headers/ATTrackingManager.h, 2026년 9월 19일 확인.API_AVAILABLE(ios(27.2)) API_UNAVAILABLE(macos, tvos, watchos, visionos)가 붙은requestTrackingAuthorizationUsingExpandedInterface:additionalInformationAction:completionHandler:의 선언과 그 문서 주석을 인용. 예전 메서드의 재요청 및 대기 중인 요청에 대한 주석도 인용. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, requestTrackingAuthorization(usingExpandedInterface:additionalInformationAction:completionHandler:)와 NSUserTrackingMarkdownUsageDescription, 2026년 9월 19일 문서 JSON으로 가져옴. 플랫폼 지원은 메서드가 iOS 27.2, iPadOS 27.2, Mac Catalyst 27.2이고 키가 iOS 27.2, iPadOS 27.2이며 모두 베타 표시. “Display a full-page sheet”와 “Discussion” 절을 인용. Apple, requestTrackingAuthorization(completionHandler:), 2026년 9월 21일 문서 JSON으로 가져옴. 플랫폼 지원은 iOS 14.0, iPadOS 14.0, Mac Catalyst 14.0, macOS 11.0, tvOS 14.0, visionOS 1.0이며 베타 표시 없음. 다섯 나라에 대한 Discussion 문장, Markdown 키에 대한 “Configure the app’s target properties” 문장, 그리고 “the system doesn’t display the prompt”(시스템이 프롬프트를 띄우지 않는) 경우 목록에 있는 대기 중인 요청 항목을 인용. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩
-
저자가 macOS 26.6.2(25G83)에서 2026년 9월 19일과 20일에 실행한 결과. ATTProbe는
App과WindowGroup생애 주기를 쓰는 파일 하나짜리 SwiftUI 앱으로, Xcode 27.2 베타(27B5019j) 아래에서xcrun swiftc -sdk <iPhoneSimulator27.2.sdk> -target arm64-apple-ios26.0-simulator -parse-as-library로 빌드했고, Info.plist에는NSUserTrackingUsageDescription을 “Probe: the standard usage description.”으로,NSUserTrackingMarkdownUsageDescription을 “Probe: Markdown description with a bullet list:”와 그 뒤의 목록 두 항목으로 넣었습니다. 같은 프로브의 이전 UIKit 판본은 scene manifest가 없었고 같은 SDK로 빌드했을 때 요청에 닿기도 전에EXC_BREAKPOINT로 실행 중 멈췄으므로, 원인을 파고들지 않고 교체했습니다. 기기는com.apple.CoreSimulator.SimRuntime.iOS-27-2(24B5084k) 위에simctl create로 만든 iPhone 18 Pro 시뮬레이터이고, Xcode 27.2 베타의simctl로 다뤘습니다. 지역은simctl spawn <udid> defaults write "Apple Global Domain" AppleLocale -string <locale>로 설정했고, 매 실행 전에simctl shutdown과simctl boot를 했습니다. 앱은simctl launch --console-pty로 실행해print줄을 모았고, 스크린샷은 실행 7초 뒤에simctl io <udid> screenshot으로 찍었으며 캡처는 그로부터 9초 뒤에 끝났습니다. 실행 구성은en_US확장에 액션,de_DE확장에 액션,de_DE로 예전requestTrackingAuthorization(completionHandler:),de_DE에preferExpandedInterface: false,nl_NL확장에 액션,fr_FR확장에 nil 액션입니다. 9월 19일에는 매 실행에서 로그가region=<code> status-before=0을 찍었고 16초 캡처 안에 완료 줄은 없었습니다. 확장 다섯 번에서는 3초, 6초, 9초, 12초에status-now=0도 찍혔는데, 이 확인은 프로브의 예전 호출 분기에서는 하지 않습니다. 스크린샷은 모두 표준 알림창이었습니다(이 파일들과, 대기 중 프롬프트 동작을 처음 보여 준 9월 19일 이전 묶음의 파일들은 세션의 임시 디렉터리를 지운 Mac 재부팅을 넘기지 못했으므로, 9월 19일 결과는 그때 읽은 콘솔 출력으로 여기에 기록합니다). 9월 20일 첫 묶음은 매 실행 전에 재부팅하는 같은 스크립트로,en_US7:16:37,de_DE7:17:42,de_DE예전 호출 7:18:42,de_DE에false7:19:33,nl_NL7:20:26이었고, 모두 완료 줄이 없었으며 프로브가 폴링하는 확인마다status-now=0이었고 스크린샷은 모두 표준 알림창이었습니다. 액션 없는fr_FR은 7:21:04였고, 7:21:05에expanded-request status=0 (notDetermined)을 자신의mode=줄과 같은 초에 찍었으며, 스크린샷에는 프로브 자신의 로그만 있고 알림창은 없습니다. 두 번째 시뮬레이터인 iPhone Duo 기기는 7:13에 부팅해 이 묶음 내내 켜져 있었지만, 그동안 어느 쪽 시뮬레이터든 다른 무언가가 건드렸다는 기록은 파일에 없습니다. 두 번째 묶음은 7:23부터 7:27까지이고, 처음 세 번의 실행은 시뮬레이터 오류로 두 번 실패한 대기 중 프롬프트 절차의 첫 시도와 겹칩니다. 액션 없는fr_FR7:23:57은 즉시notDetermined, 액션 있는fr_FR7:24:09는 그 다른 스크립트가 실행한 것으로 프롬프트가 뜨고 완료 줄은 없었으며, 액션 없는de_DE7:24:52는 프롬프트, 액션 있는fr_FR7:26:03은 즉시notDetermined, 액션 없는en_US7:27:43은 프롬프트였습니다. 7:23:09의fr_FR실행은 시뮬레이터가 종료되는 중이어서 실패했고, 7:23:57의 로그는 다른 스크립트가 프로브를 다시 설치하는 바람에 6초에서 끊깁니다. 이 내용은 빠짐없이 적으려고 나열할 뿐 무게를 두지 않습니다. 세 번째 묶음은 다른 어떤 것도 시뮬레이터를 건드리지 않는 상태에서 한 번에 하나씩, 매번 재부팅한 뒤 돌렸습니다. 액션 있는fr_FR7:40:06, 액션 없는fr_FR7:40:45, 그리고 7:41:22는 로케일 문자열us_US(프로브는region=US를 찍었습니다)였고, 모두 프롬프트가 뜨고 완료 줄이 없었으며 확인마다status-now=0이었습니다. 대기 중 프롬프트 경우는 같은 스크립트로 한 번의 부팅 안에서 했습니다. 7:42:00의de_DE는 프롬프트가 떴고 완료 줄이 없었습니다. 그 알림창에 답하지 않은 채simctl uninstall과simctl install을 한 뒤, 7:42:18의 실행은 7:42:19에expanded-request status=0 (notDetermined)을 찍었고 그 스크린샷에는 알림창이 화면에 남아 있습니다. 7:42:40에 예전 호출로 한 세 번째 실행은 7:42:41에legacy-request status=0 (notDetermined)을 찍었습니다. 3단계의 코드 조각은showPrivacyDetails와handle(_:)을 스텁 함수로 두고-target arm64-apple-ios26.0-simulator에서 iPhoneSimulator 27.2 SDK에 대해swiftc -typecheck를 통과했습니다. 같은 파일에서#if os(iOS)줄을 빼고 Xcode 27.2 베타 안의 macOS SDK에 대해-target arm64-apple-macos15.0으로 컴파일하면error: 'requestTrackingAuthorization(usingExpandedInterface:additionalInformationAction:completionHandler:)' is unavailable in macOS로 실패했습니다. ↩↩↩↩↩↩↩↩↩ -
Apple, iOS & iPadOS 27.2 Beta Release Notes, 2026년 9월 17일과 9월 19일에 문서 JSON 엔드포인트로 가져옴, App Tracking Transparency의 New Features에서 인용. ↩↩↩