플러터 iOS App Tracking Transparency(ATT) 구현하기
Flutter 프로젝트에 App Tracking Transparency(ATT) 기능을 추가하기 위해 작업을 진행했다. iOS 14.5 이상부터는 사용자의 데이터를 추적할 때, 명시적으로 허락을 받아야 하기 때문에, 이를 구현하는 것이 필수다. 특히 광고나 사용자 데이터 추적이 필요한 앱이라면 반드시 이 과정을 거쳐야 한다.
Flutter에서 ATT를 어떻게 구현하는지 차근차근 설명하면서, 작업한 과정을 기록해본다.
1. 플러그인 설치
Flutter에서 ATT를 구현하기 위해 필요한 플러그인이 있었다. 다행히 Flutter 생태계에는 app_tracking_transparency 패키지가 제공되어 쉽게 사용할 수 있다.
먼저 pubspec.yaml 파일에 해당 패키지를 추가했다:
dependencies:
flutter:
sdk: flutter
app_tracking_transparency: ^3.0.0
그리고 나서 터미널에서 의존성 패키지를 설치했다:
flutter pub get
설치는 매우 간단했다. 하지만 여기서 중요한 것은 iOS 설정이다. 기본적으로 Android에서는 이 패키지가 무시되기 때문에 별도로 설정할 필요가 없다. 하지만 iOS는 조금 더 손이 간다.
2. iOS 설정
ATT를 구현하려면 iOS 쪽에서 권한 요청 메시지를 설정해줘야 한다. Apple이 요구하는 대로, 사용자가 앱에서 추적을 허용할지 명확하게 안내해야 한다. 이를 위해 iOS의 Info.plist 파일을 수정했다.
ios/Runner/Info.plist 파일을 열고, 다음과 같이 사용자에게 추적 요청을 하는 이유를 설명하는 문구를 추가했다:
<key>NSUserTrackingUsageDescription</key>
<string>이 앱은 맞춤형 광고 및 분석을 위해 사용자 추적 권한을 요청합니다.</string>
이 문구는 앱 실행 시 iOS에서 ATT 팝업에 표시된다. 사용자가 추적을 허락할지, 거부할지 결정할 수 있는 중요한 부분이니 신경 써서 작성해야 한다. 내가 작성한 문구는 광고와 분석을 목적으로 한다는 점을 명확하게 했다.
또한, ATT는 iOS 14.0 이상에서만 지원되기 때문에 ios/Podfile 파일에서 최소 iOS 버전도 확인했다:
platform :ios, '14.0'
만약 여기에서 버전이 14 미만으로 설정되어 있으면, ATT 기능을 사용할 수 없기 때문에 꼭 확인해야 한다.
3. Flutter 코드 작성
이제 실제로 ATT 요청을 Flutter에서 구현할 차례다. 내가 구현한 기본 로직은 앱이 시작되면 자동으로 사용자에게 추적 권한을 요청하는 것이다. main.dart 파일에서 상태 관리와 함께 구현을 했다.
import 'package:flutter/material.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
_initAppTracking();
}
Future<void> _initAppTracking() async {
if (await AppTrackingTransparency.trackingAuthorizationStatus ==
TrackingStatus.notDetermined) {
final status = await AppTrackingTransparency.requestTrackingAuthorization();
if (status == TrackingStatus.authorized) {
print('사용자가 추적을 허용했습니다.');
} else {
print('사용자가 추적을 거부했습니다.');
}
}
final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
print('광고 식별자: $uuid');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App Tracking Transparency Example'),
),
body: Center(
child: Text('ATT 권한 요청 예시'),
),
);
}
}
여기서 몇 가지 중요한 포인트가 있었다:
- 권한 요청 여부 확인: 먼저 앱이 실행되면 AppTrackingTransparency.trackingAuthorizationStatus를 사용해 현재 상태를 확인한다. 권한이 요청되지 않은 상태라면(즉, TrackingStatus.notDetermined), 권한을 요청한다.
- 권한 요청: 권한 요청 팝업이 뜨고 사용자가 허용하거나 거부한 결과에 따라 로그를 출력했다. 실제 앱에서는 추적을 허용하지 않았을 경우 대체 기능을 제공하거나, 사용자의 선택에 맞게 앱을 운영해야 한다.
- 광고 식별자: AppTrackingTransparency.getAdvertisingIdentifier() 메서드를 사용해 광고 식별자를 가져올 수 있다. 하지만 사용자가 추적을 거부하면 이 값은 비어 있을 것이다.
4. 테스트
이제 작업을 마치고 iOS 시뮬레이터와 실제 기기에서 테스트를 진행했다. 시뮬레이터에서 ATT 권한 팝업이 정상적으로 표시되는지 확인하는 것은 간단했다. 또한, 기기에서 팝업이 뜨는지, 추적 허용 여부에 따른 동작을 확인할 수 있었다.
테스트를 진행하면서 발견한 것은, 시뮬레이터에서 이미 권한을 한 번 설정하면 Settings > Privacy > Tracking에서 설정을 초기화해야 다시 팝업을 볼 수 있다는 점이다. 실제 기기에서도 동일하게 한 번 권한을 선택한 이후에는 설정을 수동으로 변경해야 한다.
5. 최적의 구현 방식 고려
Flutter로 ATT를 구현하는 것은 그리 어렵지 않았다. 하지만 언제 이 권한을 요청할 것인지가 중요하다. 나는 앱이 처음 실행되자마자 권한을 요청했지만, 사용자에게 앱의 가치를 전달한 후 요청하는 것이 더 좋을 수 있다는 생각이 들었다.
예를 들어, 특정 기능을 사용할 때 추적이 필요하다는 것을 설명하고, 그때 권한을 요청하는 방식이 사용자 경험에 더 좋을 것이다.
결론
오늘은 Flutter에서 iOS의 App Tracking Transparency를 구현하는 과정을 완료했다. 구현 자체는 간단하지만, Apple의 정책을 따르고 사용자 경험을 고려하는 것이 중요하다. 앞으로도 이런 개인 정보 관련 기능을 개발할 때는 사용자가 더 명확히 이해하고 선택할 수 있도록 신경 써야겠다는 생각이 들었다.
작성한 코드와 설정들을 기반으로 블로그에 올리기 위해 이 일지를 작성했다. 나중에 비슷한 작업을 하게 될 때 참고하기 좋을 것 같다.