AdStage DeepLink Flutter Plugin

AdStage 딥링크 기능을 Flutter 앱에서 사용할 수 있도록 하는 플러그인입니다.

🚀 에어브릿지 방식 - 중요한 설정

⚠️ 반드시 MainActivity에서 AdStage API 키를 설정해야 합니다!

이 플러그인은 라이프사이클 문제를 해결하기 위해 에어브릿지 방식을 사용합니다. MainActivity에서는 간단히 API 키만 설정하고, 딥링크 처리는 Flutter 플러그인에서 담당합니다.

📋 필수 설정

0. iOS 자동 의존성 관리

iOS에서는 CocoaPods를 통해 자동으로 의존성이 관리됩니다:

  • AdapterAdStage 3.0.1 - CocoaPods를 통해 자동 설치
  • 더 이상 수동 Framework 추가가 필요하지 않습니다
# ios/nbase_ad_flutter_sdk.podspec (자동 포함됨)
s.dependency 'AdapterAdStage', '3.0.1'

⚠️ iOS 필수 설정: Apollo SPM 추가

중요: NBase.xcframework에서 Apollo 모듈이 필요하므로 반드시 Swift Package Manager로 추가해야 합니다.

1. Xcode에서 프로젝트 열기

cd ios && open Runner.xcworkspace

2. Package Dependencies 추가

  1. Runner 프로젝트 선택
  2. Package Dependencies 탭 클릭
  3. + 버튼 클릭
  4. Add Package Dependency 선택
  5. URL 입력: https://github.com/apollographql/apollo-ios.git
  6. Up to Next Major: 1.0.0 선택
  7. Add Package 클릭

3. Package Products 추가

Choose Package Products for apollo-ios.git 에서:

  • ApolloRunner 타겟에 추가 ✅
  • ApolloAPIRunner 타겟에 추가 ✅
  • 나머지는 None으로 설정

4. 확인

Package Dependencies에 다음이 추가되었는지 확인:

✅ apollo-ios (1.x.x)
   └── Apollo (Runner)
   └── ApolloAPI (Runner)

1. Android MainActivity 설정

android/app/src/main/kotlin/.../MainActivity.kt 파일을 다음과 같이 수정하세요:

package com.example.your_app

import android.content.Intent
import android.os.Bundle
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import com.nbase.sdk.AdStage

class MainActivity: FlutterActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // ⚠️ 필수: AdStage API Key 설정 (에어브릿지 방식)
        AdStage.setApiKey("your-api-key-here")
        Log.d("AdStage", "✅ API Key 설정 완료 (에어브릿지 방식)")
        
        // 딥링크 Intent 처리 (선택사항 - 플러그인에서 자동 처리됨)
        handleIntent(intent)
    }
    
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleIntent(intent)
    }
    
    private fun handleIntent(intent: Intent?) {
        intent?.data?.let { uri ->
            Log.d("AdStage", "🔗 MainActivity에서 딥링크 수신: $uri")
            // Flutter 플러그인에서 자동으로 처리됨
        }
    }
}

2. iOS AppDelegate 설정 (선택사항)

ios/Runner/AppDelegate.swift 파일을 다음과 같이 수정하세요:

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    
    // ⚠️ 필수: AdStage API Key 설정 (에어브릿지 방식)
    // 주의: Apollo SPM 추가 후에만 이 코드가 동작합니다
    // AdStage.shared.setApiKey("your-api-key-here")
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

참고: iOS에서는 Flutter 플러그인이 자동으로 API 키를 설정하므로 AppDelegate 설정은 선택사항입니다.

2. iOS 설정 (AppDelegate 수정 불필요!)

새로운 방식: iOS에서는 AppDelegate 수정이 전혀 필요 없습니다!
플러그인이 자동으로 모든 초기화와 딥링크 처리를 담당합니다.

특징:

  • AppDelegate 수정 없음 - 기존 AppDelegate 그대로 사용
  • 자동 초기화 - Flutter 플러그인에서 모든 설정 자동 처리
  • Runtime 로딩 - NBase SDK를 동적으로 로드하여 컴파일 의존성 제거
  • 완전 자동화 - API 키 설정부터 딥링크 처리까지 플러그인에서 담당
// ✅ AppDelegate.swift 수정 불필요! 
// 기존 AppDelegate 그대로 사용하면 됩니다.

import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

🎯 모든 초기화는 플러그인에서 자동 처리:

  • API 키 설정
  • NBase SDK 동적 로딩
  • 딥링크 리스너 등록
  • URL Scheme 처리
  • Universal Link 처리

3. iOS Info.plist 설정

**ios/Runner/Info.plist**에 딥링크 스킴 추가:

<!-- AdStage 딥링크 스킴 설정 -->
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>com.adstage.deeplink</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>adstage</string>
            <string>com.nbase.main</string>
        </array>
    </dict>
</array>

4. Android AndroidManifest.xml 설정

**android/app/src/main/AndroidManifest.xml**에 딥링크 스킴 추가:

<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 android:autoVerify="true">
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    
    <!-- AdStage 딥링크 처리 -->
    <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="your_app_scheme" />  <!-- 🔑 여기에 실제 앱 스킴 입력 -->
    </intent-filter>
    
    <!-- AdStage 웹 딥링크 처리 -->
    <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="your_domain.adg.im" />  <!-- 🔑 여기에 실제 도메인 입력 -->
    </intent-filter>
    
</activity>

🔧 Flutter 사용법

1. 패키지 설치

dependencies:
  adstage_deeplink: ^1.0.0

2. 기본 사용법

import 'package:adstage_deeplink/adstage_deeplink.dart';

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  StreamSubscription<AdStageDeepLinkEvent>? _deepLinkSubscription;

  @override
  void initState() {
    super.initState();
    
    // 자동으로 Flutter 리스너 설정
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _setupFlutterListener();
    });
  }

  Future<void> _setupFlutterListener() async {
    try {
      // 🎯 크로스 플랫폼 방식: 플러그인에서 모든 초기화 자동 처리
      // - Android: MainActivity에서 AdStage.setApiKey() 이미 완료
      // - iOS: 플러그인에서 Runtime 로딩 및 API 키 설정 자동 처리
      await AdstageDeeplink.initialize(
        apiKey: 'your_api_key_here',  // iOS에서 사용, Android에서는 무시됨
      );
      
      print('AdStage 초기화 완료 (크로스 플랫폼)');
    } catch (e) {
      print('AdStage 초기화 실패: $e');
    }
  }

  void _setupDeepLinkListener() {
    _deepLinkSubscription = AdstageDeeplink.onDeepLinkReceived.listen(
      (event) {
        print('딥링크 수신: ${event.path}');
        print('파라미터: ${event.parameters}');
        
        // 딥링크에 따른 화면 네비게이션
        _navigateToScreen(event.path, event.parameters);
      },
      onError: (error) {
        print('딥링크 수신 오류: $error');
      },
    );
  }

  void _navigateToScreen(String path, Map<String, dynamic> parameters) {
    // 실제 앱에서는 라우터/네비게이션 로직 구현
    switch (path) {
      case '/product':
        // 상품 상세 페이지로 이동
        final productId = parameters['product_id'];
        Navigator.pushNamed(context, '/product', arguments: productId);
        break;
      case '/event':
        // 이벤트 페이지로 이동
        Navigator.pushNamed(context, '/event');
        break;
      default:
        // 기본 홈 페이지
        Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false);
    }
  }

  @override
  void dispose() {
    _deepLinkSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AdStage DeepLink Demo',
      home: MyHomePage(),
    );
  }
}

🌟 주요 기능

1. 딥링크 생성

Future<void> createDeepLink() async {
  try {
    final result = await AdstageDeeplink.createDeepLink(
      name: 'Product Deep Link',
      description: 'Link to product page',
      shortPath: 'product123',
      channel: 'social',
      campaign: 'summer_sale',
      parameters: {
        'product_id': '12345',
        'category': 'electronics',
        'user_id': 'user_67890',
      },
      androidPackageName: 'com.example.myapp',
      androidAppScheme: 'myapp',
      iosAppStoreId: '123456789',
      iosAppScheme: 'myapp',
      webUrl: 'https://myapp.com/product/12345',
    );
    
    print('딥링크 생성 완료: ${result.shortUrl}');
  } catch (e) {
    print('딥링크 생성 실패: $e');
  }
}

2. 프로모션 열기

Future<void> openPromotion() async {
  try {
    final result = await AdstageDeeplink.openPromotion(
      bannerType: 'NATIVE',
      targetAudience: 'new_user',
      deviceType: 'HIGH_END',
      region: 'KR',
      limit: 10,
      showTodayButton: true,
    );
    
    print('프로모션 열기 완료: ${result.url}');
  } catch (e) {
    print('프로모션 열기 실패: $e');
  }
}

3. 이벤트 추적

Future<void> trackEvent() async {
  try {
    await AdstageDeeplink.trackEvent(
      eventName: 'product_view',
      eventData: {
        'product_id': '12345',
        'category': 'electronics',
        'price': '299000',
      },
    );
    
    print('이벤트 추적 완료');
  } catch (e) {
    print('이벤트 추적 실패: $e');
  }
}

🛠️ 디버깅 팁

1. 로그 확인

# Android 로그 확인
adb logcat | grep -E "(AdstageDeeplinkPlugin|MainActivity|NBaseSDK:AdStage)"

# Flutter 로그 확인
flutter logs

2. 딥링크 테스트

# ADB를 통한 딥링크 테스트
adb shell am start -W -a android.intent.action.VIEW -d "myapp://product/12345" com.example.myapp

# 웹 딥링크 테스트
adb shell am start -W -a android.intent.action.VIEW -d "https://mydomain.adg.im/product123" com.example.myapp

🎯 새로운 방식의 장점

크로스 플랫폼 지원: Android & iOS 완벽 지원
iOS AppDelegate 수정 불필요: 플러그인에서 Runtime 로딩으로 모든 것 자동 처리
완벽한 라이프사이클 처리: 앱 시작 시점부터 딥링크 처리
Install Referrer 지원: 첫 설치 시 자동 처리 (Android)
백그라운드→포그라운드: 모든 상황에서 딥링크 처리
자동 초기화: Flutter 앱 시작과 동시에 리스너 등록
직접 처리: Flutter 플러그인에서 바로 네이티브 SDK 접근
간단한 네이티브 코드: processPendingDeepLink 같은 복잡한 메소드 불필요
Universal Link 지원: iOS Universal Link 완벽 지원
URL Scheme 지원: Android Intent & iOS URL Scheme 지원
타이밍 문제 해결: 네이티브 ↔ Flutter 간 완벽한 동기화
성능 최적화: 네이티브 수준의 빠른 처리
안정성: 검증된 에어브릿지 방식 사용
컴파일 의존성 제거: iOS Runtime 로딩으로 framework 링킹 문제 해결
완전 자동화: 개발자가 네이티브 코드 수정할 필요 없음

🔄 간단해진 구조 (v2.1)

🤖 Android (간단함):

🚀 새로운 방식:
1. MainActivity.onCreate() ← AdStage.setApiKey() (API 키 설정만)
2. Flutter 플러그인 시작 ← AdstageDeeplink.initialize() (리스너 등록)
3. 플러그인이 Activity Intent 직접 접근 ← activity.getIntent() 
4. Flutter 얼럿 표시 🎨 ← 완벽한 딥링크 수신!

🍎 iOS (더 간단함):

🚀 새로운 방식:
1. AppDelegate ← 수정 불필요! (기존 그대로 사용)
2. Flutter 플러그인 시작 ← AdstageDeeplink.initialize() (런타임 로딩 + API 키 설정)
3. 플러그인이 URL 자동 처리 ← Runtime SDK 접근
4. Flutter 얼럿 표시 🎨 ← 완벽한 딥링크 수신!

vs 기존 방식 (복잡함):

❌ 기존 방식:
1. MainActivity.onCreate() ← AdStage.setApiKey() + handleDeepLinkIntent()
2. AppDelegate ← import NBase + AdStage.setApiKey() + 컴파일 의존성 문제
3. Flutter 플러그인 ← processPendingDeepLink() 리플렉션 호출
4. MainActivity ← 저장된 Intent 재처리
5. Flutter 얼럿 표시

핵심 개선:

  • processPendingDeepLink() 메소드 불필요
  • pendingIntent 저장 불필요
  • 리플렉션 호출 불필요
  • iOS AppDelegate 수정 불필요
  • 컴파일 의존성 문제 완전 해결
  • Flutter 플러그인에서 직접 activity.getIntent() 접근
  • iOS Runtime 로딩으로 NSClassFromString() 동적 접근
  • MainActivity는 API 키 설정만 담당 (깔끔)

📚 API 문서

새로운 방식 (권장)

AdstageDeeplink.initialize()

static Future<void> initialize({required String apiKey})

크로스 플랫폼 초기화 메소드. Android와 iOS에서 각각 최적화된 방식으로 동작합니다.

플랫폼별 동작:

  • Android: MainActivity에서 AdStage.setApiKey()가 이미 호출되었으므로 리스너만 등록
  • iOS: 플러그인에서 Runtime 로딩으로 NBase SDK 접근 후 API 키 설정

특징:

  • 크로스 플랫폼: Android & iOS 모두 지원
  • iOS AppDelegate 수정 불필요: Runtime 로딩으로 자동 처리
  • 대기 중인 딥링크 자동 처리: Cold Start 딥링크 완벽 지원
  • 타이밍 문제 완전 해결: 네이티브 ↔ Flutter 동기화
  • 컴파일 의존성 제거: iOS에서 import 없이 동적 접근
// 크로스 플랫폼 초기화
await AdstageDeeplink.initialize(
  apiKey: 'your_api_key_here',  // iOS에서 사용, Android에서는 무시됨
);

기존 방식 (하위 호환성)

AdstageDeeplink.setupListener()

static Future<void> setupListener()

하위 호환성을 위한 메소드. 내부적으로 initialize()를 호출합니다.

참고: API 키가 없으므로 iOS에서는 제대로 동작하지 않을 수 있습니다.

// 하위 호환성을 위해 지원 (권장하지 않음)
await AdstageDeeplink.setupListener();

공통 API

AdstageDeeplink.onDeepLinkReceived

static Stream<AdStageDeepLinkEvent> get onDeepLinkReceived

딥링크 이벤트를 수신하는 스트림입니다.

AdstageDeeplink.onDeepLinkReceived.listen((event) {
  print('딥링크 수신: ${event.path}');
  print('파라미터: ${event.parameters}');
});

AdStageDeepLinkEvent

class AdStageDeepLinkEvent {
  final String type;           // 이벤트 타입 (예: 'deeplink')
  final String path;           // 딥링크 경로
  final Map<String, String> parameters;  // 쿼리 파라미터
  final String eventType;      // 이벤트 종류 ('OPEN' 또는 'INSTALL')
}

🤝 기술 지원

문의사항이 있으시면 다음으로 연락주세요:

📄 라이센스

MIT License

🧪 딥링크 테스트 방법

🎉 v2.1 업데이트: 이제 Flutter 플러그인에서 직접 Activity Intent를 처리하여 더욱 간단하고 안정적입니다!

1. ADB 명령어로 딥링크 테스트

# AdStage 스킴 테스트 (기본)
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://test" \
  com.example.adstage_deeplink_example

# 파라미터가 포함된 딥링크 테스트
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://campaign/123?utm_source=test&utm_campaign=flutter&user_id=12345" \
  com.example.adstage_deeplink_example

# NBase 스킴 테스트
adb shell am start -W -a android.intent.action.VIEW \
  -d "com.nbase.main://product?id=456&category=electronics" \
  com.example.adstage_deeplink_example

# 🧊 Cold Start 테스트 (앱 완전 종료 상태에서)
adb shell am force-stop com.example.adstage_deeplink_example
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://cold_start_test?timestamp=$(date +%s)" \
  com.example.adstage_deeplink_example

# iOS 딥링크 테스트 (시뮬레이터)
xcrun simctl openurl booted "adstage://ios_test?platform=ios&timestamp=$(date +%s)"

# iOS 딥링크 테스트 (실제 디바이스 - Safari에서)
# Safari에서 다음 URL 입력:
# adstage://ios_device_test?platform=ios&source=safari

2. 🎯 예상되는 결과

딥링크 수신 시 Flutter 얼럿이 자동으로 표시됩니다:

🎨 Flutter 얼럿 (어플리케이션 레벨)

  • 제목: "🔗 딥링크 수신" (아이콘 포함)
  • 상세 정보:
    • 타입: deeplink
    • 경로: 딥링크 경로 (예: /test, /campaign/123)
    • 이벤트 타입: OPEN (일반) 또는 INSTALL (첫 설치)
    • 파라미터: 딥링크에 포함된 모든 쿼리 파라미터
  • 버튼: "로그 출력", "확인"

📱 추가 피드백

  • SnackBar: 하단에 초록색 성공 메시지
  • 콘솔 로그: 각 단계별 상세 로그 출력

3. 🔍 로그 확인

# 전체 AdStage 관련 로그
adb logcat | grep -E "(MainActivity|AdstageDeeplinkPlugin|NBaseSDK:AdStage)"

# MainActivity 로그만
adb logcat | grep "MainActivity"

# Flutter 플러그인 로그만
adb logcat | grep "AdstageDeeplinkPlugin"

4. 📱 다양한 시나리오 테스트

# 1. 앱이 실행 중일 때 (Warm Start)
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://warm_start?scenario=running" \
  com.example.adstage_deeplink_example

# 2. 앱이 백그라운드에 있을 때
# (먼저 홈 버튼을 눌러 앱을 백그라운드로 보낸 후)
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://background_to_foreground?scenario=background" \
  com.example.adstage_deeplink_example

# 3. 앱이 완전히 종료된 상태에서 (Cold Start)
adb shell am force-stop com.example.adstage_deeplink_example
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://cold_start?scenario=terminated" \
  com.example.adstage_deeplink_example

# 4. 복잡한 파라미터 테스트
adb shell am start -W -a android.intent.action.VIEW \
  -d "adstage://test?user_id=12345&product_id=67890&campaign=summer_sale&utm_source=facebook&utm_medium=social&custom_param=special_value" \
  com.example.adstage_deeplink_example

5. ✅ 성공 지표

다음 사항들이 모두 확인되면 정상 동작:

  1. 앱 자동 시작: 딥링크 클릭 시 앱이 즉시 실행됨
  2. Flutter 얼럿: 상세한 딥링크 정보가 예쁘게 표시됨
  3. 로그 출력: 각 단계별 로그가 정상적으로 출력됨
  4. SnackBar: 하단에 초록색 성공 메시지 표시됨
  5. Cold Start 지원: 앱이 완전히 종료된 상태에서도 정상 동작

6. 🐛 트러블슈팅

만약 딥링크가 동작하지 않는다면:

# 1. 앱이 설치되어 있는지 확인
adb shell pm list packages | grep adstage_deeplink_example

# 2. Intent Filter가 제대로 등록되었는지 확인
adb shell dumpsys package com.example.adstage_deeplink_example | grep -A 5 -B 5 "adstage"

# 3. 앱을 완전히 재설치
flutter clean
flutter build apk
flutter install

🐛 iOS 초기화 실패 디버깅 가이드

iOS에서 "AdStage 클래스를 찾을 수 없다"는 오류가 발생할 때 다음 단계를 따라 해결하세요:

1. 상세 디버깅 로그 확인

Flutter 앱을 실행하고 Xcode 콘솔에서 다음 로그를 확인하세요:

// 초기화 시도 시 나타나는 로그들
🔧 [AdStage] NBase SDK 초기화 시작...
🔍 [AdStage] 클래스 시도: AdStage
🔍 [AdStage] 클래스 시도: NBase.AdStage
🔍 [AdStage] 클래스 시도: AdStageManager
// ... 더 많은 디버깅 정보

2. Framework 링킹 확인

콘솔에서 다음을 확인하세요:

# Xcode 콘솔에서 확인할 내용
📦 Main Bundle: /path/to/app
📱 로드된 이미지 수: XXX
✅ Framework 발견: /path/to/NBase.framework
✅ Framework 발견: /path/to/AdapterAdStage.framework

만약 Framework가 발견되지 않으면:

3. CocoaPods 재설치

cd ios
rm -rf Pods
rm Podfile.lock
pod install --repo-update

4. Framework 파일 확인

# 플러그인 폴더에서 framework 파일이 있는지 확인
ls -la ~/.pub-cache/hosted/pub.dev/adstage_deeplink-*/ios/Frameworks/
# 또는 로컬에서
ls -la ios/Frameworks/

# 다음 파일들이 있어야 함:
# - NBase.xcframework/
# - AdapterAdStage.xcframework/

5. iOS Deployment Target 확인

ios/Podfile에서:

platform :ios, '15.0'  # 최소 15.0이어야 함

6. 수동 Framework 추가 (최후 수단)

  1. Xcode에서 프로젝트 열기
  2. Runner 타겟 선택
  3. GeneralFrameworks, Libraries, and Embedded Content
  4. + 버튼 클릭
  5. Add Other...Add Files
  6. 다음 framework 파일들 추가:
    • NBase.xcframework
    • AdapterAdStage.xcframework
  7. Embed & Sign으로 설정

7. 에러별 해결 방법

"모든 AdStage 클래스명 시도 실패"

❌ [AdStage] 모든 클래스명 시도 실패
❌ [AdStage] 가능한 원인:
   - NBase.xcframework가 앱에 제대로 링크되지 않음
   - AdapterAdStage.xcframework가 앱에 제대로 링크되지 않음

해결 방법: CocoaPods 재설치 후 Clean Build

"Framework 발견되지 않음"

📱 로드된 이미지 수: 150
❌ Framework 발견되지 않음

해결 방법: 수동 Framework 추가

"shared 메서드 미지원"

⚠️ [AdStage] shared 메서드 미지원: AdStage

해결 방법: Framework 버전 확인 및 업데이트

8. 최종 테스트

정상 동작 시 다음과 같은 로그가 출력됩니다:

✅ [AdStage] 클래스 발견: AdStage -> <NBase.AdStage>
✅ [AdStage] NSObject 타입 캐스팅 성공: AdStage
✅ [AdStage] shared 셀렉터 응답 가능: AdStage
✅ [AdStage] shared 인스턴스 획득 성공: AdStage
🔍 [AdStage] 사용 가능한 메서드 확인:
   ✅ setApiKey:
   ✅ setUnifiedListener:
   ✅ createDeepLink
   ✅ handleDeepLink:
   ✅ handleUniversalLink:
✅ [AdStage] API key 설정 완료
✅ [AdStage] 리스너 설정 완료

9. 문제 신고

위 모든 단계를 시도해도 문제가 해결되지 않으면, 다음 정보와 함께 문의하세요:

  • iOS 버전
  • Xcode 버전
  • Flutter 버전
  • 전체 콘솔 로그
  • Podfile.lock 내용