오늘도 공부
Flutter에서 설치 후에도 레퍼럴 코드를 유지하는 방법 본문
Android는 Install Referrer, iOS는 딥링크+서버 설계로 풀어야 한다
추천인 코드를 유저가 직접 입력하게 하면 전환율이 떨어집니다.
가장 좋은 UX는 이겁니다.
추천 링크를 누른다 → 앱을 설치한다 → 가입하면 추천인이 자동 적용된다.
문제는 이 흐름이 Android와 iOS에서 같은 방식으로 동작하지 않는다는 점입니다.
Android는 Google Play의 Install Referrer API가 있어서 “설치 직전 클릭 정보”를 앱이 읽을 수 있습니다. 반면 iOS는 Apple 공식 문서 기준으로 Android의 Install Referrer 같은 1:1 post-install referrer retrieval API가 보이지 않고, 공식 축은 Universal Links, campaign links, custom product pages, 그리고 측정용 attribution입니다. 이 차이를 이해하고 설계해야 Flutter에서도 제대로 구현됩니다. (Android Developers)
1. 먼저 결론부터
Flutter에서 크로스플랫폼으로 가장 현실적인 구조는 아래입니다.
권장 구조
- 추천 링크는 항상 내 도메인으로 받는다.
예: https://myapp.com/r/ABC123 - 서버가 클릭을 기록하고 click_id를 만든다.
- Android면 Google Play로 보내면서 referrer 파라미터에 click_id 또는 referral_code를 넣는다.
- iOS면 App Store로 보낸다.
다만 iOS는 앱 설치 후 App Store에서 그 값을 그대로 앱이 읽는 공식 경로를 기대하면 안 된다. - 앱 첫 실행 시
- Android: Install Referrer에서 값 복구
- iOS: 자체 서버 매칭, 로그인 기반 복구, 또는 서드파티 deferred deep linking 도입 검토
즉, Android는 스토어를 넘어 referrer를 복구할 수 있고, iOS는 스토어 이후를 서버/딥링크 인프라로 보완해야 합니다. (Android Developers)
2. Android: 공식적으로 가장 깔끔한 해법
Google의 Install Referrer 문서는, Google Play Install Referrer API로 다음 정보를 안전하게 가져올 수 있다고 설명합니다.
가져올 수 있는 값에는 referrer URL, 클릭 시각, 설치 시작 시각, 최초 설치 당시 앱 버전 등이 포함됩니다. 또한 Google Play Games on PC의 UA 문서에서는 실제 예시로 play.google.com/...&referrer=... 형태의 링크를 써서, 설치 후 게임 클라이언트가 그 referrer 문자열을 받는 흐름을 보여줍니다. referrer 문자열은 URL 인코딩되어야 하고 512자 이하여야 합니다. (Android Developers)
Android 추천 링크 예시
https://play.google.com/store/apps/details?id=com.example.app
&referrer=click_id%3Dclk_12345%26referral_code%3DABC123%26utm_source%3Dinvite
복호화하면 이런 의미입니다.
click_id=clk_12345&referral_code=ABC123&utm_source=invite
이 방식의 장점은 명확합니다.
- 유저가 코드를 따로 입력할 필요가 없다
- Play 설치 직전의 referral payload를 앱이 첫 실행 때 읽을 수 있다
- 마케팅 UTM과 추천 코드, 내부 click_id를 한 번에 담을 수 있다
3. Flutter에서 Android 구현
Flutter 쪽에서는 Android deep link와는 별개로, Play Install Referrer를 읽는 단계가 필요합니다.
Flutter 공식 문서는 Android 앱 링크와 iOS 유니버설 링크 설정을 각각 안내하고 있고, Flutter의 기본 deep link handler와 외부 플러그인이 충돌할 수 있어 필요 시 FlutterDeepLinkingEnabled 또는 flutter_deeplinking_enabled를 조정하라고 설명합니다. (Flutter 문서)
실무 구현은 보통 두 갈래입니다.
방법 A. Flutter 플러그인 사용
pub.dev에는 Play Install Referrer를 읽는 Flutter 패키지가 있습니다. 예를 들어 play_install_referrer는 Android Play Install Referrer API를 쓰기 위한 플러그인으로 소개되고 있습니다. (Dart packages)
예시 흐름:
final details = await PlayInstallReferrer.installReferrer;
final raw = details.installReferrer;
// "click_id=clk_12345&referral_code=ABC123&utm_source=invite"
final uri = Uri(query: raw);
final clickId = uri.queryParameters['click_id'];
final referralCode = uri.queryParameters['referral_code'];
방법 B. MethodChannel로 네이티브 Android 구현
조금 더 통제하려면 Android 쪽에서 Play Install Referrer Client Library를 직접 붙이고 Flutter로 넘기는 방식도 가능합니다.
Google 문서는 Kotlin/Java에서는 Play Install Referrer Client Library 사용을 권장합니다. (Android Developers)
Android 첫 실행 처리 권장 순서
앱 첫 실행
→ Install Referrer 조회
→ click_id / referral_code 파싱
→ 서버에 claim API 호출
→ 서버가 “이 유저는 추천인 ABC123으로 귀속” 처리
→ 로컬에도 저장
여기서 핵심은 앱에서 바로 보상 지급을 확정하지 말고, 서버에서 최종 귀속을 결정하는 것입니다. 그래야 중복 설치, 재설치, 조작 시도에 대응하기 쉽습니다.
4. iOS: Android처럼 생각하면 안 된다
여기서 많은 팀이 막힙니다.
Apple 공식 문서를 보면 iOS 쪽의 축은 다음입니다.
- Universal Links: 앱이 설치되어 있으면 웹 링크가 앱 안 특정 화면으로 연결됨 (Apple Developer)
- Campaign Links / App Analytics: 어떤 마케팅 링크가 다운로드를 만들었는지 측정 가능 (Apple Developer)
- Custom Product Pages: App Store 내 여러 상품 페이지를 만들고, 각 페이지별 성과 측정 가능. iOS 18 이상에서는 custom product page에 deep link를 붙여 앱의 특정 위치로 보낼 수 있음 (Apple Developer)
- Ad attribution / privacy: 측정은 가능하지만 개인정보·추적 정책 제약이 큼 (Apple Developer)
중요한 포인트는 이것입니다.
iOS에서 공식 문서만 기준으로 보면
“App Store 설치 이후 앱이 install referrer 문자열을 직접 읽는 Android식 공식 API”는 확인되지 않습니다.
Apple은 campaign links로 측정을 제공하고, universal links로 앱 오픈 경로를 제공하지만, Android Install Referrer처럼 “스토어 설치 후 referral payload를 앱이 복구”하는 이야기를 공식 문서에서 같은 수준으로 제공하지 않습니다. 이건 문서 비교에 기반한 실무적 해석입니다. (Android Developers)
즉, iOS는 다음처럼 생각해야 합니다.
Android
- 스토어 설치 후 앱이 referrer를 읽을 수 있음
iOS
- 설치 전 링크 클릭은 잡을 수 있음
- 설치 후 앱 내부 복구는 서버/딥링크/서드파티 attribution 전략이 필요함
5. iOS에서 가능한 현실적 방법
방법 1. Universal Link 기반 + 서버 매칭
Flutter 공식 문서에 따르면 iOS universal links를 쓰려면 내가 소유한 웹 도메인과 apple-app-site-association 설정이 필요합니다. (Flutter 문서)
추천 링크를 이렇게 만듭니다.
https://myapp.com/r/ABC123
서버는 이 링크 클릭을 기록합니다.
referral_code = ABC123
click_id = clk_98765
user_agent / ip / created_at 저장
설치 전이면 App Store로 보냅니다.
설치 후 다시 같은 universal link를 열면 앱이 열리면서 ABC123을 바로 받을 수 있습니다.
다만 이 방법은 “설치 직후 첫 실행에서 자동 복구” 보장용은 아닙니다.
유저가 스토어에서 설치한 뒤 앱을 직접 열어버리면, Android처럼 referrer 복구가 되지 않습니다. 그래서 이 방식만으로는 완전한 deferred deep linking이 아닙니다. (Apple Developer)
방법 2. 로그인/가입 정보로 서버 귀속
실무에서는 이 방법이 가장 견고합니다.
흐름은 이렇습니다.
- 추천 링크 클릭 시 서버가 click_id와 referral_code 저장
- 유저가 설치 후 회원가입
- 가입 시점의 식별자(이메일, 전화번호, 소셜 로그인 subject, 초대받은 번호 등)를 기준으로 서버가 최근 클릭과 매칭
- 추천인 귀속 처리
이 방식은 iOS에서 App Store referrer를 못 읽는 문제를 서버 레벨에서 우회합니다.
특히 친구 초대형 서비스에서는 “초대받은 전화번호”, “이메일 초대”, “로그인 후 자동 귀속”이 제일 안정적입니다.
방법 3. 서드파티 deferred deep linking SDK
브랜치, 앱스플라이어, 어저스트 같은 솔루션이 보통 이 영역을 담당합니다.
다만 Apple은 third-party deep-linking or deferred deep-linking tools가 앱 간 식별자 공유나 광고 측정 목적 tracking에 해당하면 ATT 허가가 필요할 수 있다고 명시합니다. (Apple Developer)
즉, 이 방법은 구현은 쉽지만 정책 검토가 반드시 필요합니다.
6. 그래서 Flutter에서는 어떻게 설계해야 하나
제가 추천하는 구조는 아래입니다.
A안. 가장 현실적인 구조
Android는 Install Referrer, iOS는 서버 매칭
[공용 추천 링크]
https://myapp.com/r/ABC123
|
v
[내 서버]
- referral_code 저장
- click_id 생성
- 클릭 로그 저장
|
+--> Android: Play URL + referrer=click_id/referral_code
|
+--> iOS: App Store URL로 이동
앱 첫 실행 시:
Android
- play_install_referrer 또는 네이티브로 Install Referrer 조회
- click_id, referral_code 추출
- 서버 POST /referrals/claim
- 서버 귀속 확정
iOS
- 앱이 시작되면 로컬에 귀속 정보 없으면 서버에 POST /referrals/pending-match
- 가입/로그인 완료 시 서버가 최근 click 기록과 계정 정보를 기반으로 매칭
- 귀속 확정
이 설계의 장점은:
- Android는 자동 복구
- iOS도 유저 입력 최소화
- Flutter 공통 비즈니스 로직 유지 가능
- 보상 지급 로직을 서버 중앙에서 통제 가능
7. Flutter 앱 구조 예시
패키지 역할 분리
- app_links 또는 Router 기반: 딥링크/유니버설 링크 수신
- play_install_referrer: Android Install Referrer 조회
- shared_preferences 또는 secure storage: 1회 귀속 결과 캐시
- 백엔드 API: claim / reconcile / finalize
공통 서비스 인터페이스 예시
abstract class ReferralSource {
Future<ReferralPayload?> getInitialReferral();
}
class AndroidReferralSource implements ReferralSource {
@override
Future<ReferralPayload?> getInitialReferral() async {
// Play Install Referrer 읽기
// query string 파싱
}
}
class IOSReferralSource implements ReferralSource {
@override
Future<ReferralPayload?> getInitialReferral() async {
// universal link로 열렸다면 해당 payload 반환
// 아니면 null
}
}
앱 시작 시 처리
Future<void> bootstrapReferral() async {
final payload = await referralSource.getInitialReferral();
if (payload != null) {
await api.claimReferral(payload);
return;
}
// iOS 대비: 가입/로그인 이후 서버 매칭 시도
await api.reconcileReferralAfterSignup();
}
8. 링크 설계는 이렇게 하는 게 좋다
추천 링크를 처음부터 Play/App Store 링크로 직접 뿌리지 말고,
항상 내 도메인 링크 하나로 통일하는 게 좋습니다.
예:
https://myapp.com/r/ABC123
이유는 명확합니다.
- Android/iOS 라우팅을 서버에서 분기할 수 있다
- 클릭 로그를 먼저 저장할 수 있다
- 추후 광고, 초대, 파트너, 인플루언서별 토큰 구조를 확장하기 쉽다
- Flutter 앱이 아니어도 웹 랜딩, QR, SMS, 카카오 공유에 공통으로 쓸 수 있다
Android 쪽 최종 이동 링크는 이런 식입니다.
https://play.google.com/store/apps/details?id=com.example.app
&referrer=click_id%3Dclk_12345%26referral_code%3DABC123
iOS는 보통 App Store URL로 보내고, 앱 설치 후에는 로그인/가입 완료 시점에 서버가 귀속을 마무리합니다.
9. iOS에서 꼭 알아야 할 정책 포인트
Apple은 App Store privacy 문서에서,
앱이 third-party deep-linking or deferred deep-linking tools를 사용하면서 고유 식별자 전달이나 cross-company identity 생성이 tracking에 해당하면 AppTrackingTransparency 권한이 필요하다고 안내합니다. (Apple Developer)
즉:
- 자체 도메인 + 자체 서버 중심 설계는 정책 리스크가 상대적으로 낮다
- 외부 MMP/딥링크 SDK를 쓰면 ATT, 개인정보 처리, 데이터 공유 구조를 함께 검토해야 한다
10. 실전 권장안
추천 코드 자동 적용이 목표라면
가장 실무적인 조합은 이겁니다.
1단계
- 추천 링크는 https://myapp.com/r/{code} 형식으로 통일
2단계
- 서버가 클릭 저장 + click_id 생성
3단계
- Android는 Play referrer에 click_id와 referral_code 전달
4단계
- iOS는 App Store로 보내되, 가입/로그인 시 서버가 귀속 처리
5단계
- 필요하면 나중에만 서드파티 deferred deep linking 도입 검토
이렇게 하면
- Android는 거의 완전 자동
- iOS는 정책과 플랫폼 제약 안에서 가장 안정적
- Flutter 코드베이스는 공통 유지
- 추천인 보상 로직은 서버에서 안전하게 관리
11. 한 줄 요약
Flutter에서 설치 후 레퍼럴 유지의 정답은 “플랫폼별로 다르게 구현하되, 서버에서 하나로 묶는 것”입니다.
Android는 Google Play Install Referrer가 핵심이고, iOS는 Universal Link + 서버 매칭 + 필요 시 deferred deep linking 솔루션 조합으로 가야 합니다. Apple 공식 문서 기준으로 iOS는 Android처럼 설치 후 referrer 문자열을 바로 읽는 방식보다, 링크 처리·캠페인 측정·privacy-compliant attribution 쪽이 중심입니다. (Android Developers)
'스터디 > Flutter' 카테고리의 다른 글
| IOS push 기능 체크 리스트 (0) | 2026.03.23 |
|---|---|
| Flutter & Dart 2026 로드맵 (0) | 2026.03.03 |
| Flutter Android 뒤로가기 버튼이 안 먹히는 문제 해결기 (0) | 2026.02.07 |
| Flutter Riverpod + Drift 완벽 가이드 (2) | 2025.10.22 |
| Flutter프로젝트가 안드로이드 프로젝트로 인식 되는 오류 (0) | 2025.09.15 |
