Flutter 개발

Flutter 딥링킹 가이드 1편: 기초 개념과 플랫폼 설정

딥링킹의 개념부터 Android/iOS 플랫폼별 상세 설정까지

John Doe
2025년 9월 16일
10분 읽기
154

딥링킹이란 무엇인가

딥링킹(Deep Linking)은 사용자를 앱의 특정 화면이나 콘텐츠로 직접 이동시키는 기술입니다. 웹의 URL과 유사한 개념으로, 모바일 앱에서도 특정 리소스에 직접 접근할 수 있게 해줘요.

딥링킹이 필요한 실제 상황:
- 푸시 알림: "새 메시지가 도착했습니다" 알림을 탭하면 해당 채팅방으로 직접 이동
- 이메일 마케팅: 프로모션 이메일의 링크를 통해 앱 내 특정 상품 페이지로 이동
- 소셜 미디어 공유: Instagram에 공유된 링크로 앱의 특정 게시물 열기
- QR 코드: 오프라인 매장의 QR 코드로 앱 내 쿠폰 페이지 접근
- 앱 간 연동: 카카오톡에서 배달 앱의 특정 메뉴로 바로 이동

딥링킹의 세 가지 유형

딥링킹은 구현 방식과 동작 원리에 따라 세 가지 주요 유형으로 분류되죠.

1. 전통적 딥링크 (URI Scheme)

URI 스킴은 가장 오래되고 간단한 딥링킹 방식예요. 커스텀 URL 스킴을 사용하여 앱을 식별하고 실행합니다.

- 형식: myapp://product/123 또는 myapp://user/profile
- 장점: 구현이 매우 간단하고 모든 OS 버전에서 지원
- 단점: 앱이 설치되어 있지 않으면 오류 발생, 다른 앱이 동일한 스킴을 사용할 수 있어 보안 취약

2. 유니버설 링크 (iOS) / 앱 링크 (Android)

일반 웹 URL을 사용하되, 앱이 설치되어 있으면 앱으로, 없으면 웹사이트로 연결되는 스마트한 방식입니다.

- 형식: https://myapp.com/product/123
- 장점: 웹 폴백 지원, SEO 친화적, 보안성 높음, 앱 설치 유무와 관계없이 작동
- 단점: 도메인 소유권 인증 필요, 설정이 복잡, 서버 구성 필요

3. 디퍼드 딥링크 (Deferred Deep Link)

앱이 설치되어 있지 않은 경우, 사용자가 앱을 설치한 후에도 원래 의도했던 콘텐츠로 이동시키는 고급 기술입니다.

- 동작 과정: 링크 클릭 → 앱스토어로 이동 → 앱 설치 → 첫 실행 시 원래 목적지로 자동 이동
- 장점: 완벽한 사용자 경험 제공, 마케팅 캠페인에 매우 효과적
- 단점: 구현이 복잡, 보통 Firebase Dynamic Links 같은 서드파티 서비스 필요

Android 플랫폼 설정

Android에서 딥링킹을 구현하려면 AndroidManifest.xml 파일을 수정해야 합니다. 각 설정의 의미와 목적을 상세히 알아보죠.
xml
<!-- android/app/src/main/AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            
            <!-- 기본 런처 인텐트 필터 -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            
            <!-- 커스텀 URL 스킴 설정 -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <!-- 여러 스킴을 지원할 수 있음 -->
                <data android:scheme="myflutterapp" />
                <data android:scheme="myapp" />
            </intent-filter>
            
            <!-- App Links 설정 (Android 6.0+) -->
            <!-- autoVerify="true"는 자동으로 도메인 소유권을 확인 -->
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                
                <!-- HTTPS 스킴만 지원 -->
                <data android:scheme="https" />
                
                <!-- 여러 호스트 지원 가능 -->
                <data android:host="myapp.example.com" />
                <data android:host="www.myapp.example.com" />
                <data android:host="m.myapp.example.com" />
                
                <!-- 특정 경로 패턴만 처리하고 싶을 때 -->
                <data android:pathPrefix="/app" />
                <data android:pathPattern="/share/.*" />
            </intent-filter>
            
            <!-- 특정 파일 타입 처리 (선택사항) -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="content" />
                <data android:mimeType="application/myapp" />
            </intent-filter>
        </activity>
    </application>
</manifest>
Android 설정 주요 속성 설명:

- android:exported="true": Android 12부터 필수. 다른 앱이 이 액티비티를 시작할 수 있도록 허용
- android:launchMode="singleTop": 이미 실행 중인 앱에서 딥링크를 처리할 때 새 인스턴스를 생성하지 않음
- android:autoVerify="true": App Links를 위한 자동 도메인 확인 활성화
- BROWSABLE 카테고리: 웹 브라우저에서 링크를 열 수 있도록 허용

iOS 플랫폼 설정

iOS에서는 Info.plist 파일과 Associated Domains 설정을 통해 딥링킹을 구현합니다.
xml
<!-- ios/Runner/Info.plist -->
<?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>
    <!-- 기존 설정들... -->
    
    <!-- URL Schemes 설정 (커스텀 스킴) -->
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <!-- 스킴 식별자 (역방향 도메인 형식 권장) -->
            <key>CFBundleURLName</key>
            <string>com.example.myflutterapp.deeplink</string>
            
            <!-- 실제 URL 스킴들 -->
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myflutterapp</string>
                <string>myapp</string>
                <!-- 여러 스킴 등록 가능 -->
            </array>
        </dict>
    </array>
    
    <!-- iOS 9+ 보안 설정 (필요한 경우) -->
    <key>LSApplicationQueriesSchemes</key>
    <array>
        <!-- 앱에서 체크하거나 열 수 있는 다른 앱의 스킴 -->
        <string>whatsapp</string>
        <string>instagram</string>
        <string>fb</string>
    </array>
</dict>
</plist>
Universal Links를 위한 추가 설정:

1. Xcode에서 프로젝트 선택
2. Signing & Capabilities 탭 이동
3. "+ Capability" 클릭
4. "Associated Domains" 추가
5. 도메인 추가: applinks:myapp.example.com
xml
// iOS Runner.entitlements 파일 (자동 생성됨)
<?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>com.apple.developer.associated-domains</key>
    <array>
        <!-- applinks: 접두사는 Universal Links를 의미 -->
        <string>applinks:myapp.example.com</string>
        <string>applinks:*.myapp.example.com</string>
        <!-- 와일드카드 서브도메인 지원 -->
        <string>applinks:www.myapp.example.com</string>
    </array>
</dict>
</plist>

서버 설정: apple-app-site-association

iOS Universal Links가 작동하려면 웹 서버에 특별한 파일을 호스팅해야 합니다.
json
// https://myapp.example.com/.well-known/apple-app-site-association
{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "TEAM_ID.com.example.myflutterapp",
        "paths": [
          "/app/*",
          "/product/*",
          "/user/*",
          "/share/*",
          "NOT /api/*",
          "NOT /admin/*"
        ]
      },
      {
        // 여러 앱 지원 가능
        "appID": "TEAM_ID.com.example.myflutterapp.beta",
        "paths": ["/beta/*"]
      }
    ]
  },
  "webcredentials": {
    // 자동 로그인 지원 (선택사항)
    "apps": ["TEAM_ID.com.example.myflutterapp"]
  }
}

서버 설정: assetlinks.json (Android)

json
// https://myapp.example.com/.well-known/assetlinks.json
[
  {
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.myflutterapp",
      "sha256_cert_fingerprints": [
        // Play Console에서 확인 가능한 SHA256 지문
        "14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"
      ]
    }
  },
  {
    // 여러 빌드 변형 지원 (debug, release 등)
    "relation": ["delegate_permission/common.handle_all_urls"],
    "target": {
      "namespace": "android_app",
      "package_name": "com.example.myflutterapp.debug",
      "sha256_cert_fingerprints": [
        "디버그용_SHA256_지문"
      ]
    }
  }
]

Flutter에서 딥링크 테스트하기

설정이 완료되면 다음 명령어로 딥링킹을 테스트할 수 있습니다:
bash
# Android 테스트 (에뮬레이터 또는 연결된 기기에서)
# 커스텀 스킴
adb shell am start -a android.intent.action.VIEW \
    -d "myflutterapp://product/123" com.example.myflutterapp

# App Link (HTTPS)
adb shell am start -a android.intent.action.VIEW \
    -d "https://myapp.example.com/product/123" com.example.myflutterapp

# iOS 테스트 (시뮬레이터에서)
# 커스텀 스킴
xcrun simctl openurl booted "myflutterapp://product/123"

# Universal Link
xcrun simctl openurl booted "https://myapp.example.com/product/123"

# 실제 기기 테스트
# 1. 메모 앱이나 메시지 앱에 링크 입력
# 2. 링크를 탭하여 앱이 열리는지 확인
# 3. 앱이 설치되어 있지 않은 경우 웹 페이지가 열리는지 확인

일반적인 문제 해결

Universal Links/App Links가 작동하지 않을 때:

1. 도메인 검증 실패
- apple-app-site-association 파일이 HTTPS로 제공되는지 확인
- 파일이 리다이렉션 없이 직접 제공되는지 확인
- Content-Type이 application/json인지 확인

2. 앱이 열리지 않고 웹사이트가 열릴 때
- 사용자가 이전에 "Safari에서 열기"를 선택했을 수 있음
- 설정 > 앱 > 기본 앱에서 확인 및 재설정

3. 특정 경로만 작동하지 않을 때
- paths 배열의 패턴이 올바른지 확인
- NOT 연산자가 우선순위를 가지므로 순서 확인

4. 개발 중 테스트 문제
- 디버그 빌드와 릴리스 빌드의 서명이 다름을 인지
- 로컬 테스트 시 ngrok 같은 터널링 도구 활용

다음 단계

딥링킹의 기초 개념과 플랫폼별 설정을 완료했어요. 다음 편에서는 GoRouter를 활용한 고급 라우터 관리 시스템 구축 방법을 다루겠습니다.
#딥링킹
#URL스킴
#유니버설링크
#앱링크
#Android
#iOS
#플랫폼설정