adstage
Mobile SDKDeep Link

React Native

คู่มือการรวม AdStage DeepLink (React Native)

สารบัญ

  1. ภาพรวม
  2. การติดตั้ง
  3. การตั้งค่าตามแพลตฟอร์ม
  4. การเริ่มต้น SDK
  5. การจัดการ Deep Link ที่เข้ามา
  6. การสร้าง Deep Link
  7. การแก้ไขปัญหา

ภาพรวม

AdStage DeepLink SDK สำหรับ React Native มีฟีเจอร์ดังนี้:

  • Deep Link แบบเรียลไทม์: จัดการทันทีผ่าน URL Scheme, App Link/Universal Links
  • Deferred Deep Link: กู้คืนอัตโนมัติเมื่อเปิดแอปครั้งแรกหลังติดตั้ง
  • สร้าง Deep Link แบบไดนามิก: สร้างลิงก์ที่ติดตามได้ผ่าน API เซิร์ฟเวอร์
  • การติดตาม Attribution: วิเคราะห์การตลาดตามพารามิเตอร์ UTM
  • ข้ามแพลตฟอร์ม: API เดียวกันสำหรับ Android/iOS
  • URL Scheme: myapp://promo/summer
  • Android App Links: https://go.myapp.com/abc123
  • iOS Universal Links: https://go.myapp.com/abc123
  • Deferred Deep Link: เมื่อไม่ได้ติดตั้งแอป → Store → ติดตั้ง → กู้คืนเมื่อเปิดแอป

การติดตั้ง

ติดตั้งผ่าน npm / yarn

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

ติดตั้ง Dependencies สำหรับ 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

เพิ่มเมธอดสำหรับจัดการ Deep Link ในไฟล์ 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] handleDeepLink: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] handleUniversalLink:userActivity];
        return YES;
    }
    return NO;
}

การตั้งค่า Android

1. เพิ่ม Maven Repository (จำเป็น)

เพิ่มใน 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

เพิ่ม Intent Filter ใน android/app/src/main/AndroidManifest.xml:

<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: ใช้ซ้ำเมื่ออยู่บนสุดของ Stack เท่านั้น
  • ❌ standard: สร้าง Instance ใหม่ทุกครั้ง (ทำให้ Deep Link ซ้ำ)

การเริ่มต้น 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();
}, []);

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 {
  linkId: string;              // 딥링크 고유 ID (서버 발급)
  shortPath: string;           // 딥링크 short path (예: "abc123")
  parameters: Record<string, string>; // 커스텀 파라미터
  source: DeepLinkSource;      // 딥링크 소스 (실시간/디퍼드)
  eventType: string;           // 이벤트 타입 (예: "OPEN", "INSTALL")
  timestamp?: string;          // 타임스탬프
}
 
type DeepLinkSource =
  | 'realtime'   // 실시간 딥링크 (앱 실행 중/URL·Universal Link 수신)
  | 'install'    // 디퍼드 딥링크 (설치 후 첫 실행 시 복원)
  | 'unknown';   // 알 수 없음

เมื่อแอปถูกเปิดจาก Deep Link ขณะที่ปิดอยู่สนิท:

// 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년 여름 할인 이벤트',
      
      // 어트리뷰션 파라미터
      channel: 'instagram',
      subChannel: 'social',
      campaign: 'summer_sale_2025',
      
      // 리다이렉트 설정
      redirectConfig: {
        type: 'APP', // 'STORE' | 'APP' | 'WEB'
        android: {
          packageName: 'com.yourapp.android',
          appScheme: 'yourapp://promo',
          webUrl: 'https://yourapp.com/promo',
        },
        ios: {
          appStoreId: '1234567890',
          appScheme: 'yourapp://promo',
          webUrl: 'https://yourapp.com/promo',
        },
        desktop: {
          webUrl: 'https://yourapp.com/promo',
        },
      },
      
      // 커스텀 파라미터
      parameters: {
        promo_code: 'SUMMER25',
        discount: '20',
        screen: 'PromoDetail',
      },
    });
    
    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✅ชื่อ Deep Link
descriptionstring-คำอธิบาย Deep Link
shortPathstring-กำหนด Short Path เอง
channelstring-ช่องทาง
subChannelstring-ช่องทางย่อย
campaignstring-แคมเปญ
adGroupstring-กลุ่มโฆษณา
creativestring-ครีเอทีฟโฆษณา
contentstring-เนื้อหา
keywordstring-คีย์เวิร์ด
redirectConfigRedirectConfig-การตั้งค่า Redirect
parametersobject-พารามิเตอร์กำหนดเอง

โครงสร้าง RedirectConfig

interface RedirectConfig {
  type: 'STORE' | 'APP' | 'WEB';   // 리다이렉트 타입
  android?: PlatformConfig;          // Android 플랫폼 설정
  ios?: PlatformConfig;              // iOS 플랫폼 설정
  desktop?: { webUrl?: string };     // 데스크톱 설정
}
 
interface PlatformConfig {
  storeUrl?: string;     // 앱 스토어 URL
  appScheme?: string;    // 앱 커스텀 스킴
  webUrl?: string;       // 웹 폴백 URL
  packageName?: string;  // 패키지명(Android) / 번들 ID(iOS)
  appStoreId?: string;   // App Store ID (iOS)
}
ประเภทติดตั้งแอปแล้วไม่ได้ติดตั้งแอป
STOREไป Storeไป Store
APPเปิดแอป (Deep Link เรียลไทม์)ไป Store → Deferred Deep Link หลังติดตั้ง
WEBไป URL เว็บไป URL เว็บ

ฟังก์ชันยูทิลิตี้

ดึง Short Path

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

จัดการ Intent ของ Android แบบ Manual

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

การแก้ไขปัญหา

ปัญหา iOS

  1. ตรวจสอบว่า URL Scheme ถูกตั้งค่าอย่างถูกต้องใน Info.plist
  2. ตรวจสอบว่าเมธอดจัดการ Deep Link ถูกเพิ่มใน AppDelegate.mm
  3. สำหรับ Universal Links ตรวจสอบว่า Associated Domains ถูกตั้งค่าแล้ว
  • ตรวจสอบว่ามี Key NSUserTrackingUsageDescription ใน Info.plist

ปัญหา Android

  • ตรวจสอบการตั้งค่า android:launchMode="singleTask"
  1. ตรวจสอบ Intent Filter ใน AndroidManifest.xml
  2. ตรวจสอบการตั้งค่า android:exported="true"
  3. สำหรับ App Links ตรวจสอบไฟล์ Digital Asset Links

ปัญหาทั่วไป

  1. ตรวจสอบว่า Listener ถูกตั้งค่าหลังจากเริ่มต้น SDK เสร็จสมบูรณ์
  2. ตรวจสอบว่าเรียกใช้ checkPendingDeepLink() แล้วหรือไม่
  3. ตรวจสอบสถานะการเชื่อมต่อเครือข่าย

พารามิเตอร์ไม่ถูกส่ง

  • ตรวจสอบว่าค่าถูกตั้งค่าอย่างถูกต้องในอ็อบเจกต์ parameters เมื่อสร้าง Deep Link

สารบัญ

คู่มือการรวม AdStage DeepLink (React Native)สารบัญภาพรวมประเภท Deep Link ที่รองรับการติดตั้งติดตั้งผ่าน npm / yarnติดตั้ง Dependencies สำหรับ iOSการตั้งค่าตามแพลตฟอร์มการตั้งค่า iOS1. สิทธิ์ ATT (App Tracking Transparency) (จำเป็น)2. การตั้งค่า URL Scheme3. การตั้งค่า Universal Links (ไม่บังคับ)4. แก้ไข AppDelegate.mmการตั้งค่า Android1. เพิ่ม Maven Repository (จำเป็น)2. การตั้งค่า minSdkVersion3. การตั้งค่า AndroidManifest.xml4. ข้อควรระวังเรื่อง launchModeการเริ่มต้น SDKการเริ่มต้นพื้นฐานการจัดการ Deep Link ที่เข้ามา1. ตั้งค่า Deep Link Listener2. โครงสร้าง DeepLinkData3. การจัดการ Pending Deep Link4. ตัวอย่างจริง: การรวมกับ React Navigationการสร้าง Deep Linkการสร้าง Deep Link พื้นฐานพารามิเตอร์ CreateDeepLinkRequestโครงสร้าง RedirectConfigฟังก์ชันยูทิลิตี้ดึง Short Pathจัดการ Intent ของ Android แบบ Manualการแก้ไขปัญหาปัญหา iOSไม่ได้รับ Deep LinkPopup ขอสิทธิ์ ATT ไม่แสดงปัญหา Androidได้รับ Deep Link ซ้ำไม่ได้รับ Deep Linkปัญหาทั่วไปDeferred Deep Link ไม่ทำงานพารามิเตอร์ไม่ถูกส่ง