Flutter에서 Deep Links: 초보자를 위한 완벽 가이드 (타사 패키지 없이) (파트 1)
Source: Dev.to
Imagine isso: seu usuário recebe um link de desconto, clica nele — e BOOM! Ele não só abre seu app, mas já está na tela de checkout com o cupom aplicado.
Isso é mágica? Não — são Deep Links!
Objetivo da série
- Implementar deep links em Flutter sem utilizar pacotes prontos.
- Aprender como tudo funciona por baixo dos panos.
이 기사에서 배울 내용
- 딥 링크가 무엇인지.
- App Links와 Custom Schemes의 차이점.
- Flutter에서 기본 구조를 설정하는 방법.
기본 개념
Deep links는 사용자를 브라우저가 아니라 앱의 특정 화면으로 바로 이동시키는 URL입니다.
실제 예시
| 전통적인 흐름 | 딥 링크 |
|---|---|
| 1️⃣ 브라우저 열기 → 2️⃣ 사용자가 앱 설치 → 3️⃣ 앱 열기 → 4️⃣ 원하는 화면으로 이동 | 1️⃣ 앱이 아직 설치되지 않아도 Deferred Deep Linking을 통해 올바른 화면으로 바로 열기. |
Source: …
지연 딥링크 (Deferred Deep Linking)
아래 다이어그램은 지연 딥링크 라고 알려진 라우팅을 보여줍니다. 사용자가 아직 앱을 설치하지 않았더라도, 링크의 컨텍스트가 앱 스토어를 거친 후에도 보존됩니다.
전체 흐름:
1. 사용자가 링크를 클릭 →
2. 앱이 설치되지 않은 경우 스토어로 리디렉션 →
3. 사용자가 앱을 설치 →
4. 앱을 열면 원래 링크를 받아 올바른 화면으로 이동합니다.
링크 예시
https://fitconnect.app/signup?referralCode=TRAINER12345
| 부분 | 값 |
|---|---|
| Scheme | https |
| Host | fitconnect.app |
| Path | /signup |
| Query | referralCode=TRAINER12345 |
각 부분은 네비게이션에서 특정 역할을 합니다: scheme 은 프로토콜(또는 커스텀 스킴일 경우 앱)을 식별하고, host 와 path 는 라우트를 결정하며, query parameters 는 추가 데이터를 전달합니다(예: 추천 코드).
딥 링크 종류
1️⃣ Custom Scheme
fitconnect://fitconnect.app/signup?referralCode=TRAINER12345
- ✅ 구현이 빠름.
- ✅ 로컬 테스트에 적합.
- ⚠️ 보안이 낮음 — 어떤 앱이든 같은 스킴을 등록할 수 있음.
- ⚠️ 앱이 설치되지 않은 경우, 시스템이 눈에 거슬리는 오류를 표시함.
2️⃣ HTTPS (App Links / Universal Links)
https://fitconnect.app/signup?referralCode=TRAINER12345
- ✅ 안전함 — 앱과 서버 간 양방향 검증이 이루어짐.
- ✅ 앱이 설치되지 않은 경우, 브라우저에서 정상적으로 열림.
- ✅ 프로덕션에 권장됨.
- ⚠️ 자체 도메인이 필요함.
- ⚠️ 설정이 복잡함.
양방향 검증이란?
운영체제는 양쪽 모두가 서로를 인식할 때만 앱을 엽니다:
-
앱이 처리할 도메인을 선언합니다.
-
서버가 해당 도메인에 호스팅된 파일을 통해 어떤 앱이 접근 권한을 갖는지 확인합니다:
- Android →
assetlinks.json - iOS →
apple-app-site-association
- Android →
이 파일 중 하나라도 없거나 일치하지 않으면, 링크는 폴백으로 브라우저에서 열리며 악성 앱이 링크를 가로채는 것을 방지합니다.
팁: 개발 단계에서는 커스텀 스킴을 사용하고, 프로덕션에서는 HTTPS (App Links / Universal Links) 로 전환하세요.
사용 사례: FitConnect
시나리오
- Maria, 퍼스널 트레이너가 자신의 추천 링크를 공유합니다.
- 학생이 해당 링크를 통해 회원가입을 하면 Maria는 보너스를 받고, 학생은 할인을 받습니다.
시리즈 주요 딥 링크
https://fitconnect.app/signup?referralCode=TRAINER12345678901234
클릭하면 앱이 바로 TRAINER12345678901234 코드가 입력된 회원가입 화면으로 열려야 합니다.
| 항목 | 값 |
|---|---|
| 도메인 | fitconnect.app |
| Custom scheme | fitconnect:// |
| Package (Android) | com.fitconnect.app |
Source: …
구조 준비하기
네이티브 코드를 작성하기 전에, 앱의 모든 레이어에서 공유될 상수, enum, 모델을 정의합니다. 문자열(예: 채널 이름)을 중앙화하면 추적하기 어려운 오타를 방지할 수 있습니다.
상수
// lib/shared/const/deep_link_const.dart
class DeepLinkConst {
static const String methodChannel = 'com.fitconnect.app/deeplink';
static const String eventChannel = 'com.fitconnect.app/deeplink_stream';
static const String customScheme = 'fitconnect';
static const String httpsScheme = 'https';
static const String appHost = 'fitconnect.app';
static const String signupPath = '/signup';
static const String referralCodeParam = 'referralCode';
static const int referralCodeLength = 20;
}
Deep Link 타입 Enum
// lib/shared/enums/deep_link_type.dart
enum DeepLinkType {
customScheme,
appLink, // Android HTTPS
universalLink, // iOS HTTPS
unknown;
bool get isSecure => this == appLink || this == universalLink;
}
isSecuregetter는 코드를 더 표현력 있게 만들어 줍니다 — 문자열을 비교하거나 scheme을 직접 확인하는 대신data.type.isSecure만 사용하면 됩니다.
데이터 모델 (Freezed 사용)
// lib/shared/models/deep_link_data.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'deep_link_type.dart';
part 'deep_link_data.freezed.dart';
part 'deep_link_data.g.dart';
@freezed
class DeepLinkData with _$DeepLinkData {
const factory DeepLinkData({
required String url,
required DeepLinkType type,
required String scheme,
String? host,
String? path,
@Default({}) Map<String, dynamic> queryParameters,
String? referralCode,
}) = _DeepLinkData;
factory DeepLinkData.fromJson(Map<String, dynamic> json) =>
_$DeepLinkDataFromJson(json);
}
Freezed를 사용하는 이유
- 불변성을 보장합니다.
copyWith,==,hashCode및 JSON (de)serialization 코드를 자동으로 생성합니다.- 중요한 파라미터(예: 추천 코드)를 담는 객체의 유지보수를 용이하게 합니다.
Source: …
다음 단계
- 네이티브 레이어 구현 (Android & iOS) – 링크를 가로채기 위해.
- Flutter에서 DeepLinkData를 소비하는 네비게이션 흐름 만들기.
- App Links / Universal Links 설정 (
assetlinks.json및apple-app-site-association파일). - 디버그 모드(커스텀 스킴)와 프로덕션 모드(HTTPS) 모두에서 테스트하기.
다음 글에서는 각 항목을 자세히 다루며, 양방향 검증 파일 설정(포스트 5)과 Flutter와의 완전한 통합을 소개합니다.
다음에 또 만나요! 🚀
eferralCode,
required DateTime receivedAt,
}) = _DeepLinkData;
}
이 단계가 끝나면 다음을 갖추게 됩니다:
- 딥 링크가 어떻게 동작하는지에 대한 명확한 이해.
- 다양한 종류의 링크 간 차이점 파악.
- 구현을 시작할 수 있는 탄탄한 Flutter 기반.
이 기반을 바탕으로 다음 단계에서 네이티브 코드를 통합하고 엔드‑투‑엔드 흐름을 완성합니다.
다음 단계
다음 단계에서는 Android 네이티브 구현으로 넘어갑니다 – AndroidManifest.xml 및 MainActivity.kt 전체 예시 포함.
전체 코드는 GitHub의 FitConnect 저장소에서 확인할 수 있습니다.
시리즈 소개
이 글은 9편 시리즈 중 첫 번째 포스트이며, Flutter에서 딥 링크를 다룹니다. 다음 글에서는 다음 주제를 다룹니다:
- Android와 iOS용 네이티브 코드
- 연기된 링크(Deferred links)
- 리다이렉트 페이지
- 테스트
모두 별도 패키지 없이 구현합니다.
궁금한 점이나 제안, 혹은 딥 링크와 관련된 경험이 있다면 댓글로 알려 주세요! 실제 프로젝트에 어떻게 적용했는지 듣고 싶습니다.
다음 포스트를 놓치고 싶지 않다면 Medium에서 저를 팔로우해 주세요.
피드백
이 내용이 도움이 되었다면 DEV.to에 ❤️ 혹은 🔖를 남겨 주세요 – 더 많은 개발자에게 포스트가 전달되는 데 도움이 됩니다.
커뮤니티 질문
여러분은 앱에 딥 링크를 구현해 본 적이 있나요?
가장 큰 도전 과제는 무엇이었나요? 다음 포스트에 실제 사례로 활용하고 싶습니다 👇
태그
flutter android ios deeplinks mobile programming