StageUp
모바일 SDK딥링크

React Native

AdStage DeepLink 통합 가이드 (React Native)

목차

  1. 개요
  2. 설치
  3. 플랫폼별 설정
  4. SDK 초기화
  5. 딥링크 수신 처리
  6. 딥링크 생성
  7. 트러블슈팅

개요

AdStage DeepLink SDK for React Native는 다음 기능을 제공합니다:

  • 실시간 딥링크: URL Scheme, App Link/Universal Links를 통한 즉시 처리
  • 디퍼드 딥링크: 앱 설치 후 첫 실행 시 자동 복원
  • 동적 딥링크 생성: 서버 API를 통한 추적 가능한 링크 생성
  • 어트리뷰션 추적: UTM 파라미터 기반 마케팅 분석
  • 크로스 플랫폼: Android/iOS 동일 API

지원 딥링크 타입

  • URL Scheme: myapp://promo/summer
  • Android App Links: https://go.myapp.com/abc123
  • iOS Universal Links: https://go.myapp.com/abc123
  • 디퍼드 딥링크: 앱 미설치 시 스토어 → 설치 → 앱 실행 시 복원

설치

npm / yarn 설치

# npm
npm install @adstage/react-native-sdk
 
# yarn
yarn add @adstage/react-native-sdk

iOS 의존성 설치

cd ios && pod install

플랫폼별 설정

iOS 설정

1. ATT (App Tracking Transparency) 권한 (필수)

ios/YourApp/Info.plist에 다음을 추가:

<key>NSUserTrackingUsageDescription</key>
<string>광고 성과 측정 및 개인화된 광고 제공을 위해 사용됩니다.</string>

2. URL Scheme 설정

ios/YourApp/Info.plist에 다음을 추가:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLName</key>
        <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>your_app_scheme</string>
        </array>
    </dict>
</array>

ios/YourApp/YourApp.entitlements에 다음을 추가:

<key>com.apple.developer.associated-domains</key>
<array>
    <string>applinks:go.yourapp.com</string>
</array>

4. AppDelegate.mm 수정

ios/YourApp/AppDelegate.mm 파일에서 딥링크 처리를 위한 메서드를 추가합니다:

#import <AdapterAdStage/AdapterAdStage-Swift.h>
 
// URL Scheme 처리
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
    // AdStage 딥링크 처리
    [[DeepLinkManager shared] handleDeepLinkFrom:url];
    return YES;
}
 
// Universal Links 처리
- (BOOL)application:(UIApplication *)application
    continueUserActivity:(NSUserActivity *)userActivity
      restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
    if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
        [[DeepLinkManager shared] handleUniversalLinkWithUserActivity:userActivity];
        return YES;
    }
    return NO;
}

Android 설정

1. Maven 저장소 추가 (필수)

android/settings.gradle 또는 android/build.gradle에 추가:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
        maven { url "https://maven.adstage.io/repository/public" }
    }
}

2. minSdkVersion 설정

android/build.gradle에서 확인:

buildscript {
    ext {
        minSdkVersion = 24  // 최소 24 이상 필요
    }
}

3. AndroidManifest.xml 설정

android/app/src/main/AndroidManifest.xml에 Intent Filter 추가:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"
    android:exported="true">
    
    <!-- 기본 런처 -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    
    <!-- URL Scheme 딥링크 -->
    <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="your_app_scheme" />
    </intent-filter>
    
    <!-- App Links (HTTPS) -->
    <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" />
        <data
            android:scheme="https"
            android:host="go.yourapp.com" />
    </intent-filter>
</activity>

4. launchMode 중요 사항

android:launchMode="singleTask"
  • singleTask: 기존 Activity 재사용 (권장)
  • ⚠️ singleTop: 스택 최상단에 있을 때만 재사용
  • standard: 매번 새 인스턴스 생성 (딥링크 중복 발생)

SDK 초기화

기본 초기화

import { AdStage } from '@adstage/react-native-sdk';
 
// 앱 시작 시 초기화
const initializeAdStage = async () => {
  try {
    await AdStage.initialize({
      apiKey: 'your-api-key-here'
    });
    
    // 딥링크 리스너 설정
    setupDeepLinkListener();
    
    // Pending 딥링크 확인 (콜드 스타트)
    AdStage.deepLink.checkPendingDeepLink();
    
    console.log('✅ AdStage SDK 초기화 완료');
  } catch (error) {
    console.error('❌ AdStage 초기화 실패:', error);
  }
};
 
// App.tsx에서 호출
useEffect(() => {
  initializeAdStage();
}, []);

딥링크 수신 처리

1. 딥링크 리스너 설정

import { AdStage } from '@adstage/react-native-sdk';
 
const setupDeepLinkListener = () => {
  // 통합 딥링크 리스너
  AdStage.deepLink.setListener((data) => {
    console.log('✅ 딥링크 수신:', data);
    console.log('  - Short Path:', data.shortPath);
    console.log('  - Link ID:', data.linkId);
    console.log('  - Parameters:', data.parameters);
    
    // 비즈니스 로직 처리
    handleDeepLink(data);
  });
};
 
const handleDeepLink = (data: DeepLinkData) => {
  const { shortPath, parameters } = data;
  
  // 파라미터에 따른 화면 이동
  if (parameters?.product_id) {
    // 상품 상세 화면으로 이동
    navigation.navigate('ProductDetail', { 
      productId: parameters.product_id 
    });
  } else if (parameters?.campaign) {
    // 캠페인 화면으로 이동
    navigation.navigate('Campaign', { 
      campaignId: parameters.campaign 
    });
  } else if (parameters?.promo) {
    // 프로모션 코드 적용
    applyPromoCode(parameters.promo);
  } else {
    // 기본: 홈 화면
    navigation.navigate('Home');
  }
};

2. DeepLinkData 구조

interface DeepLinkData {
  shortPath: string;           // 딥링크 short path (예: "abc123")
  linkId: string;              // 딥링크 고유 ID
  source: DeepLinkSource;      // 딥링크 소스 (실시간/디퍼드)
  eventType: string;           // 이벤트 타입
  parameters: Record<string, string>; // 커스텀 파라미터
  createdAt?: string;          // 생성 시간
}
 
type DeepLinkSource = 
  | 'url_scheme'      // URL Scheme으로 수신
  | 'app_link'        // Android App Links로 수신
  | 'universal_link'  // iOS Universal Links로 수신
  | 'deferred';       // 디퍼드 딥링크 (설치 후 복원)

3. Pending 딥링크 처리

앱이 완전히 종료된 상태에서 딥링크로 실행된 경우:

// SDK 초기화 후 Pending 딥링크 확인
await AdStage.initialize({ apiKey: 'your-api-key' });
 
// 리스너 먼저 설정
AdStage.deepLink.setListener((data) => {
  console.log('딥링크:', data);
  handleDeepLink(data);
});
 
// Pending 딥링크 확인 및 처리
AdStage.deepLink.checkPendingDeepLink();

4. 실전 예제: React Navigation 연동

import React, { useEffect } from 'react';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { AdStage } from '@adstage/react-native-sdk';
 
function App() {
  const navigationRef = React.useRef(null);
  
  useEffect(() => {
    const initSDK = async () => {
      await AdStage.initialize({ apiKey: 'your-api-key' });
      
      // 딥링크 리스너 설정
      AdStage.deepLink.setListener((data) => {
        const { parameters } = data;
        
        // React Navigation으로 화면 이동
        if (navigationRef.current) {
          if (parameters?.screen) {
            navigationRef.current.navigate(parameters.screen, parameters);
          }
        }
      });
      
      // Cold start 딥링크 확인
      AdStage.deepLink.checkPendingDeepLink();
    };
    
    initSDK();
  }, []);
  
  return (
    <NavigationContainer ref={navigationRef}>
      {/* 네비게이션 스택 */}
    </NavigationContainer>
  );
}

딥링크 생성

기본 딥링크 생성

import { AdStage } from '@adstage/react-native-sdk';
 
const createDeepLink = async () => {
  try {
    const result = await AdStage.deepLink.create({
      name: '여름 프로모션 링크',
      description: '2025년 여름 할인 이벤트',
      
      // UTM 파라미터
      campaign: 'summer_sale_2025',
      source: 'instagram',
      medium: 'social',
      
      // 커스텀 파라미터
      parameters: {
        promo_code: 'SUMMER25',
        discount: '20',
        screen: 'PromoDetail',
      },
      
      // 리다이렉트 설정
      redirectType: 'app', // 'app' | 'store' | 'web'
      
      // 플랫폼별 설정
      androidConfig: {
        packageName: 'com.yourapp.android',
        scheme: 'yourapp',
        fallbackUrl: 'https://yourapp.com/promo',
      },
      iosConfig: {
        appStoreId: '1234567890',
        scheme: 'yourapp',
        fallbackUrl: 'https://yourapp.com/promo',
      },
      webConfig: {
        fallbackUrl: 'https://yourapp.com/promo',
      },
    });
    
    console.log('✅ 딥링크 생성 성공');
    console.log('  - Short URL:', result.shortUrl);
    console.log('  - Short Path:', result.shortPath);
    console.log('  - Link ID:', result.linkId);
    
    // 링크 공유
    shareDeepLink(result.shortUrl);
    
  } catch (error) {
    console.error('❌ 딥링크 생성 실패:', error);
  }
};

CreateDeepLinkRequest 파라미터

파라미터타입필수설명
namestring딥링크 이름
descriptionstring-딥링크 설명
campaignstring-UTM 캠페인
sourcestring-UTM 소스
mediumstring-UTM 미디엄
parametersobject-커스텀 파라미터
redirectTypestring-리다이렉트 타입 (app/store/web)
androidConfigobject-Android 설정
iosConfigobject-iOS 설정
webConfigobject-웹 설정

RedirectType 설명

type RedirectType = 'app' | 'store' | 'web';
타입앱 설치됨앱 미설치
store스토어 이동스토어 이동
app앱 실행 (실시간 딥링크)스토어 이동 → 설치 후 디퍼드 딥링크
web웹 URL 이동웹 URL 이동

유틸리티 함수

Short Path 추출

// URL에서 Short Path 추출
const shortPath = AdStage.deepLink.extractShortPath('https://go.adstage.io/ABCDEF');
console.log(shortPath); // "ABCDEF"

Android Intent 수동 처리

import { Linking } from 'react-native';
 
// Android에서 앱이 이미 실행 중일 때 새 Intent 처리
Linking.addEventListener('url', ({ url }) => {
  // 네이티브에서 자동 처리되지만, 필요시 수동 호출
  AdStage.deepLink.handleIntent();
});

트러블슈팅

iOS 문제

딥링크가 수신되지 않음

  1. Info.plist에 URL Scheme이 올바르게 설정되었는지 확인
  2. AppDelegate.mm에 딥링크 처리 메서드가 추가되었는지 확인
  3. Universal Links의 경우 Associated Domains가 설정되었는지 확인

ATT 권한 팝업이 표시되지 않음

  • Info.plist에 NSUserTrackingUsageDescription 키가 있는지 확인

Android 문제

딥링크 중복 수신

  • android:launchMode="singleTask" 설정 확인

딥링크가 수신되지 않음

  1. AndroidManifest.xml의 Intent Filter 확인
  2. android:exported="true" 설정 확인
  3. App Links의 경우 Digital Asset Links 파일 확인

공통 문제

디퍼드 딥링크가 작동하지 않음

  1. SDK 초기화가 완료된 후 리스너를 설정했는지 확인
  2. checkPendingDeepLink() 호출 여부 확인
  3. 네트워크 연결 상태 확인

파라미터가 전달되지 않음

  • 딥링크 생성 시 parameters 객체에 올바르게 값을 설정했는지 확인

목차