모바일 SDK인앱 이벤트
Android
AdStage 인앱 이벤트 통합 가이드 (Android)
목차
개요
AdStage 인앱 이벤트는 사용자 행동과 앱 이벤트를 추적하여 마케팅 분석 및 최적화를 지원합니다.
주요 기능
- 유연한 이벤트 전송: 간단한 호출부터 상세한 컨텍스트까지
- 자동 컨텍스트 수집: 디바이스 정보, 사용자 속성 자동 포함
- 세션 관리: 자동 세션 추적 및 관리
- Builder 패턴: 가독성 높은 DSL 스타일 지원
- 비동기 처리: Coroutine 기반 suspend 함수
- 오프라인 지원: 네트워크 재연결 시 자동 재전송
기본 설정
1. Gradle 의존성 추가
settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://repo.nbase.io/repository/nbase-releases") }
}
}build.gradle.kts (Module: app)
dependencies {
implementation("io.nbase:nbase-adapter-adstage:3.0.5")
// 필수 의존성
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("com.squareup.okhttp3:okhttp:4.11.0")
}2. SDK 초기화
import io.nbase.adapter.adstage.AdStageManager
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// AdStage 초기화
AdStageManager.initialize(
context = this,
apiKey = "your-api-key-here",
serverUrl = "https://api.adstage.app"
)
Log.d("AdStage", "✅ SDK 초기화 완료")
}
}3. AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 필수 권한 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<!-- ... -->
</application>
</manifest>타입 안전 이벤트 전송
1. 가장 간단한 방식
import io.nbase.adapter.adstage.AdStageManager
import io.nbase.adapter.adstage.models.AdStageEvent
// 파라미터 없는 이벤트
AdStageManager.trackEvent(AdStageEvent.FirstOpen())
// 로그인 이벤트
AdStageManager.trackEvent(
AdStageEvent.Login(method = SignUpMethod.EMAIL)
)2. 구매 이벤트 (검증 예제)
// ✅ GOOD: value와 currency 함께 제공
AdStageManager.trackEvent(
AdStageEvent.Purchase(
value = 29.99,
currency = "USD",
transactionId = "TXN_123456"
)
)
// ❌ BAD: value만 제공 시 컴파일 에러!
AdStageManager.trackEvent(
AdStageEvent.Purchase(
value = 29.99 // ❌ 에러: currency 필수!
)
)
// ✅ GOOD: currency 없이 transactionId만
AdStageManager.trackEvent(
AdStageEvent.Purchase(
transactionId = "TXN_123456"
)
)3. 상품 조회
// 파라미터와 함께
AdStageManager.trackEvent(
AdStageEvent.ProductDetailsView(
itemId = "PROD_123",
itemName = "Wireless Earbuds"
)
)
// 파라미터 없이
AdStageManager.trackEvent(AdStageEvent.ProductListView())4. 커스텀 이벤트 (event_name 자동 승격)
표준 이벤트 외에 앱 고유의 이벤트를 전송할 때는 AdStageEvent.Custom을 사용합니다.
파라미터에 event_name 키를 포함하면, 해당 값이 실제 이벤트 이름으로 자동 승격되어 대시보드에 저장됩니다.
// 예: 'promotion_click'이라는 커스텀 이벤트 전송
AdStageManager.trackEvent(
AdStageEvent.Custom(
params = mapOf(
"event_name" to "promotion_click",
"promotion_id" to "summer_sale_2025",
"screen" to "home_banner"
)
)
)
// 대시보드에는 "promotion_click" 이벤트로 수집됨
// event_name 없이 일반 커스텀 이벤트
AdStageManager.trackEvent(
AdStageEvent.Custom(
params = mapOf(
"action" to "button_click",
"button_id" to "promo_banner",
"screen" to "home",
"timestamp" to System.currentTimeMillis()
)
)
)
// 대시보드에는 "custom" 이벤트로 수집됨
// Click, View도 자유 파라미터 지원
AdStageManager.trackEvent(
AdStageEvent.Click(
params = mapOf(
"campaign_id" to "SUMMER2025",
"ad_group" to "electronics"
)
)
)표준 이벤트 카탈로그
AdStage SDK는 46개의 표준 이벤트를 제공합니다.
📌 광고 추적 (4개)
// 1. 광고 클릭
AdStageManager.trackEvent(
AdStageEvent.Click(
params = mapOf("campaign_id" to "CAMP_123")
)
)
// 2. 광고 노출
AdStageManager.trackEvent(
AdStageEvent.View(
params = mapOf("impression_id" to "IMP_456")
)
)
// 3. 앱 설치
AdStageManager.trackEvent(AdStageEvent.Install())
// 4. 커스텀 이벤트 (event_name으로 이벤트 이름 지정)
AdStageManager.trackEvent(
AdStageEvent.Custom(
params = mapOf(
"event_name" to "promotion_click",
"promotion_id" to "summer_sale_2025"
)
)
)👤 사용자 라이프사이클 (5개)
// SignUpMethod enum
enum class SignUpMethod(val value: String) {
EMAIL("email"),
GOOGLE("google"),
APPLE("apple"),
FACEBOOK("facebook"),
KAKAO("kakao"),
NAVER("naver")
}
// 1. 회원가입 완료
AdStageManager.trackEvent(
AdStageEvent.SignUp(method = SignUpMethod.GOOGLE)
)
// 2. 회원가입 시작
AdStageManager.trackEvent(AdStageEvent.SignUpStart())
// 3. 로그인
AdStageManager.trackEvent(
AdStageEvent.Login(method = SignUpMethod.EMAIL)
)
// 4. 로그아웃
AdStageManager.trackEvent(AdStageEvent.Logout())
// 5. 앱 최초 실행
AdStageManager.trackEvent(AdStageEvent.FirstOpen())📄 콘텐츠 조회 (6개)
// 1. 홈 화면
AdStageManager.trackEvent(AdStageEvent.HomeView())
// 2. 상품 목록
AdStageManager.trackEvent(
AdStageEvent.ProductListView(itemCategory = "electronics")
)
// 3. 검색 결과
AdStageManager.trackEvent(
AdStageEvent.SearchResultView(searchTerm = "wireless headphones")
)
// 4. 상품 상세
AdStageManager.trackEvent(
AdStageEvent.ProductDetailsView(
itemId = "PROD_123",
itemName = "Wireless Earbuds"
)
)
// 5. 페이지 조회 (웹)
AdStageManager.trackEvent(
AdStageEvent.PageView(
pageUrl = "https://example.com/products",
pageTitle = "Products"
)
)
// 6. 화면 조회 (앱)
AdStageManager.trackEvent(
AdStageEvent.ScreenView(
screenName = "product_detail",
screenClass = "ProductDetailActivity"
)
)🛒 전자상거래 (8개)
// 1. 장바구니 추가
AdStageManager.trackEvent(
AdStageEvent.AddToCart(
value = 99000.0,
currency = "KRW",
items = listOf(
EcommerceItem(
itemId = "PROD_123",
itemName = "Wireless Earbuds",
price = 99000.0,
quantity = 1
)
)
)
)
// 2. 장바구니 제거
AdStageManager.trackEvent(
AdStageEvent.RemoveFromCart(
value = 50000.0,
currency = "KRW"
)
)
// 3. 위시리스트 추가
AdStageManager.trackEvent(
AdStageEvent.AddToWishlist(
itemId = "PROD_456",
itemName = "Smart Watch"
)
)
// 4. 결제 정보 입력
AdStageManager.trackEvent(
AdStageEvent.AddPaymentInfo(paymentType = "credit_card")
)
// 5. 결제 시작
AdStageManager.trackEvent(
AdStageEvent.BeginCheckout(
value = 150000.0,
currency = "KRW"
)
)
// 6. 구매 완료 ⭐⭐⭐
AdStageManager.trackEvent(
AdStageEvent.Purchase(
value = 129000.0,
currency = "KRW",
transactionId = "ORDER_20250105_001",
tax = 12900.0,
shipping = 3000.0,
coupon = "SUMMER2025",
items = listOf(
EcommerceItem(
itemId = "PROD_123",
itemName = "Wireless Earbuds",
itemCategory = "electronics",
price = 126000.0,
quantity = 1
)
)
)
)
// 7. 환불
AdStageManager.trackEvent(
AdStageEvent.Refund(
transactionId = "ORDER_20250105_001",
value = 129000.0,
currency = "KRW"
)
)🎮 진행/성취 (4개)
// 1. 튜토리얼 시작
AdStageManager.trackEvent(
AdStageEvent.TutorialBegin(
params = mapOf("tutorial_id" to "intro")
)
)
// 2. 튜토리얼 완료
AdStageManager.trackEvent(
AdStageEvent.TutorialComplete(
params = mapOf("duration_seconds" to 120)
)
)
// 3. 레벨 업
AdStageManager.trackEvent(
AdStageEvent.LevelUp(
level = 25,
character = "warrior"
)
)
// 4. 업적 달성
AdStageManager.trackEvent(
AdStageEvent.Achievement(achievementId = "first_win")
)💬 상호작용 (3개)
// 1. 검색
AdStageManager.trackEvent(
AdStageEvent.Search(searchTerm = "gaming laptop")
)
// 2. 공유
AdStageManager.trackEvent(
AdStageEvent.Share(
contentType = "product",
itemId = "PROD_789",
method = "kakao"
)
)
// 3. 광고 클릭
AdStageManager.trackEvent(
AdStageEvent.AdClick(adId = "AD_12345")
)🎮 게임 특화 (4개)
// 1. 게임 플레이
AdStageManager.trackEvent(
AdStageEvent.GamePlay(
level = 10,
levelName = "Dragon's Lair",
character = "mage",
contentType = "dungeon"
)
)
// 2. 보너스 획득
AdStageManager.trackEvent(
AdStageEvent.AcquireBonus(
contentType = "reward",
itemId = "ITEM_123",
itemName = "Gold Chest",
quantity = 1
)
)
// 3. 게임 서버 선택
AdStageManager.trackEvent(
AdStageEvent.SelectGameServer(
contentId = "SERVER_01",
contentType = "pvp",
itemName = "Asia Server"
)
)
// 4. 패치 완료
AdStageManager.trackEvent(
AdStageEvent.CompletePatch(
contentId = "PATCH_2.1.0",
contentType = "update"
)
)📅 구독/체험 (3개)
// 1. 무료 체험 시작
AdStageManager.trackEvent(
AdStageEvent.StartTrial(
value = 9900.0,
currency = "KRW",
trialDays = 14
)
)
// 2. 구독 시작
AdStageManager.trackEvent(
AdStageEvent.Subscribe(
value = 9900.0,
currency = "KRW",
subscriptionId = "premium_monthly"
)
)
// 3. 구독 취소
AdStageManager.trackEvent(
AdStageEvent.Unsubscribe(subscriptionId = "premium_monthly")
)💰 가상 화폐 (2개)
// 1. 가상 화폐 획득
AdStageManager.trackEvent(
AdStageEvent.EarnVirtualCurrency(
virtualCurrencyName = "gold",
value = 500.0
)
)
// 2. 가상 화폐 사용
AdStageManager.trackEvent(
AdStageEvent.SpendVirtualCurrency(
virtualCurrencyName = "gold",
value = 100.0,
itemName = "health_potion"
)
)🎯 기타 (7개)
// 1. 일정 등록
AdStageManager.trackEvent(
AdStageEvent.Schedule(
params = mapOf("event_type" to "appointment")
)
)
// 2. 크레딧 사용
AdStageManager.trackEvent(
AdStageEvent.SpendCredits(
value = 10.0,
itemName = "premium_feature"
)
)
// 3. 프로모션 조회
AdStageManager.trackEvent(
AdStageEvent.ViewPromotion(
promotionId = "PROMO_SUMMER",
promotionName = "Summer Sale 2025",
creativeSlot = "home_banner_1"
)
)
// 4. 프로모션 선택
AdStageManager.trackEvent(
AdStageEvent.SelectPromotion(
promotionId = "PROMO_SUMMER",
promotionName = "Summer Sale 2025"
)
)이벤트 타입별 예제
1. 앱 라이프사이클
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// SDK 초기화
AdStageManager.initialize(this, apiKey, serverUrl)
// 첫 실행 이벤트는 SDK가 자동으로 전송
Log.d("App", "✅ 앱 시작")
}
}2. 사용자 인증
class AuthManager {
// 회원가입
fun onSignUpComplete(method: String) {
val signUpMethod = when(method) {
"email" -> SignUpMethod.EMAIL
"google" -> SignUpMethod.GOOGLE
"apple" -> SignUpMethod.APPLE
"kakao" -> SignUpMethod.KAKAO
"naver" -> SignUpMethod.NAVER
else -> SignUpMethod.EMAIL
}
AdStageManager.trackEvent(
AdStageEvent.SignUp(method = signUpMethod)
)
Log.d("Auth", "✅ 회원가입 완료: $method")
}
// 로그인
fun onLoginSuccess(userId: String, method: String) {
val loginMethod = when(method) {
"email" -> SignUpMethod.EMAIL
"google" -> SignUpMethod.GOOGLE
else -> SignUpMethod.EMAIL
}
AdStageManager.trackEvent(
AdStageEvent.Login(method = loginMethod)
)
Log.d("Auth", "✅ 로그인: $userId")
}
// 로그아웃
fun onLogout() {
AdStageManager.trackEvent(AdStageEvent.Logout())
Log.d("Auth", "🚪 로그아웃")
}
}3. 화면 추적 (BaseActivity 패턴)
abstract class BaseActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
trackScreenView()
}
abstract fun getScreenName(): String
private fun trackScreenView() {
AdStageManager.trackEvent(
AdStageEvent.ScreenView(
screenName = getScreenName(),
screenClass = this::class.java.simpleName
)
)
Log.d("Screen", "📺 ${getScreenName()}")
}
}
// 사용 예제
class HomeActivity : BaseActivity() {
override fun getScreenName() = "home"
}
class ProductDetailActivity : BaseActivity() {
override fun getScreenName() = "product_detail"
private fun loadProduct(productId: String) {
// 상품 데이터 로딩...
// 상품 상세 조회 이벤트
AdStageManager.trackEvent(
AdStageEvent.ProductDetailsView(
itemId = productId,
itemName = product.name
)
)
}
}4. 전자상거래 전체 플로우
class EcommerceManager {
// 1. 상품 목록 조회
fun trackProductList(category: String) {
AdStageManager.trackEvent(
AdStageEvent.ProductListView(itemCategory = category)
)
}
// 2. 검색
fun trackSearch(query: String) {
AdStageManager.trackEvent(
AdStageEvent.Search(searchTerm = query)
)
}
// 3. 검색 결과 조회
fun trackSearchResults(query: String) {
AdStageManager.trackEvent(
AdStageEvent.SearchResultView(searchTerm = query)
)
}
// 4. 상품 상세 조회
fun trackProductView(product: Product) {
AdStageManager.trackEvent(
AdStageEvent.ProductDetailsView(
itemId = product.id,
itemName = product.name
)
)
}
// 5. 장바구니 추가
fun trackAddToCart(product: Product, quantity: Int) {
val item = EcommerceItem(
itemId = product.id,
itemName = product.name,
itemCategory = product.category,
price = product.price,
quantity = quantity
)
AdStageManager.trackEvent(
AdStageEvent.AddToCart(
value = product.price * quantity,
currency = "KRW",
items = listOf(item)
)
)
}
// 6. 위시리스트 추가
fun trackAddToWishlist(product: Product) {
AdStageManager.trackEvent(
AdStageEvent.AddToWishlist(
itemId = product.id,
itemName = product.name
)
)
}
// 7. 결제 시작
fun trackBeginCheckout(cart: Cart) {
val items = cart.items.map { cartItem ->
EcommerceItem(
itemId = cartItem.product.id,
itemName = cartItem.product.name,
itemCategory = cartItem.product.category,
price = cartItem.product.price,
quantity = cartItem.quantity
)
}
AdStageManager.trackEvent(
AdStageEvent.BeginCheckout(
value = cart.totalAmount,
currency = "KRW",
items = items
)
)
}
// 8. 결제 정보 입력
fun trackAddPaymentInfo(paymentMethod: String) {
AdStageManager.trackEvent(
AdStageEvent.AddPaymentInfo(paymentType = paymentMethod)
)
}
// 9. 구매 완료 ⭐⭐⭐
fun trackPurchase(order: Order) {
val items = order.items.map { orderItem ->
EcommerceItem(
itemId = orderItem.product.id,
itemName = orderItem.product.name,
itemCategory = orderItem.product.category,
price = orderItem.product.price,
quantity = orderItem.quantity
)
}
AdStageManager.trackEvent(
AdStageEvent.Purchase(
value = order.totalAmount,
currency = "KRW",
transactionId = order.id,
tax = order.tax,
shipping = order.shippingFee,
coupon = order.couponCode,
items = items
)
)
Log.d("Ecommerce", "✅ 구매 완료: ${order.id}, ${order.totalAmount}원")
}
// 10. 환불
fun trackRefund(order: Order) {
AdStageManager.trackEvent(
AdStageEvent.Refund(
transactionId = order.id,
value = order.totalAmount,
currency = "KRW"
)
)
}
// 11. 공유
fun trackShare(product: Product, method: String) {
AdStageManager.trackEvent(
AdStageEvent.Share(
contentType = "product",
itemId = product.id,
method = method
)
)
}
}5. 게임 이벤트
class GameEventManager {
// 튜토리얼
fun trackTutorialBegin(tutorialId: String) {
AdStageManager.trackEvent(
AdStageEvent.TutorialBegin(
params = mapOf("tutorial_id" to tutorialId)
)
)
}
fun trackTutorialComplete(tutorialId: String, duration: Long) {
AdStageManager.trackEvent(
AdStageEvent.TutorialComplete(
params = mapOf(
"tutorial_id" to tutorialId,
"duration_seconds" to duration / 1000
)
)
)
}
// 레벨
fun trackLevelUp(level: Int, character: String) {
AdStageManager.trackEvent(
AdStageEvent.LevelUp(
level = level,
character = character
)
)
}
// 업적
fun trackAchievement(achievementId: String) {
AdStageManager.trackEvent(
AdStageEvent.Achievement(achievementId = achievementId)
)
}
// 게임 플레이
fun trackGameStart(level: Int, levelName: String, character: String) {
AdStageManager.trackEvent(
AdStageEvent.GamePlay(
level = level,
levelName = levelName,
character = character,
contentType = "pvp"
)
)
}
// 보너스 획득
fun trackBonusAcquired(itemId: String, itemName: String, quantity: Int) {
AdStageManager.trackEvent(
AdStageEvent.AcquireBonus(
contentType = "reward",
itemId = itemId,
itemName = itemName,
quantity = quantity
)
)
}
// 가상 화폐
fun trackEarnCurrency(currencyName: String, amount: Double) {
AdStageManager.trackEvent(
AdStageEvent.EarnVirtualCurrency(
virtualCurrencyName = currencyName,
value = amount
)
)
}
fun trackSpendCurrency(currencyName: String, amount: Double, itemName: String) {
AdStageManager.trackEvent(
AdStageEvent.SpendVirtualCurrency(
virtualCurrencyName = currencyName,
value = amount,
itemName = itemName
)
)
}
}베스트 프랙티스
1. Extension 함수 활용
// ActivityExtensions.kt
fun Activity.trackScreen() {
val screenName = this::class.java.simpleName
.removeSuffix("Activity")
.lowercase()
AdStageManager.trackEvent(
AdStageEvent.ScreenView(
screenName = screenName,
screenClass = this::class.java.simpleName
)
)
}
// 사용
class ProfileActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
trackScreen() // ✅ 간단!
}
}2. ViewModel에서 이벤트 추적
class ProductViewModel : ViewModel() {
private val _productState = MutableLiveData<Product>()
val productState: LiveData<Product> = _productState
fun loadProduct(productId: String) {
viewModelScope.launch {
try {
val product = repository.getProduct(productId)
_productState.value = product
// 상품 조회 이벤트
AdStageManager.trackEvent(
AdStageEvent.ProductDetailsView(
itemId = product.id,
itemName = product.name
)
)
} catch (e: Exception) {
Log.e("ProductVM", "Failed to load product", e)
}
}
}
fun addToCart(product: Product, quantity: Int) {
viewModelScope.launch {
try {
repository.addToCart(product, quantity)
val item = EcommerceItem(
itemId = product.id,
itemName = product.name,
price = product.price,
quantity = quantity
)
AdStageManager.trackEvent(
AdStageEvent.AddToCart(
value = product.price * quantity,
currency = "KRW",
items = listOf(item)
)
)
} catch (e: Exception) {
Log.e("ProductVM", "Failed to add to cart", e)
}
}
}
}3. Compose UI에서 사용
@Composable
fun ProductDetailScreen(
productId: String,
viewModel: ProductViewModel = hiltViewModel()
) {
val product by viewModel.productState.collectAsState()
// 화면 진입 시 이벤트
LaunchedEffect(productId) {
viewModel.loadProduct(productId)
AdStageManager.trackEvent(
AdStageEvent.ScreenView(
screenName = "product_detail",
screenClass = "ProductDetailScreen"
)
)
}
Column {
// UI...
Button(
onClick = {
viewModel.addToCart(product, 1)
AdStageManager.trackEvent(
AdStageEvent.Custom(
params = mapOf(
"action" to "add_to_cart_button",
"product_id" to product.id
)
)
)
}
) {
Text("장바구니에 추가")
}
}
}4. 이벤트 래퍼 클래스
object AnalyticsManager {
private const val TAG = "Analytics"
fun trackScreen(screenName: String, screenClass: String? = null) {
AdStageManager.trackEvent(
AdStageEvent.ScreenView(
screenName = screenName,
screenClass = screenClass
)
)
Log.d(TAG, "📺 Screen: $screenName")
}
fun trackPurchase(order: Order) {
val items = order.items.map {
EcommerceItem(
itemId = it.product.id,
itemName = it.product.name,
price = it.product.price,
quantity = it.quantity
)
}
AdStageManager.trackEvent(
AdStageEvent.Purchase(
value = order.totalAmount,
currency = "KRW",
transactionId = order.id,
items = items
)
)
Log.d(TAG, "💰 Purchase: ${order.id}")
}
fun trackError(error: Throwable, context: String) {
AdStageManager.trackEvent(
AdStageEvent.Custom(
params = mapOf(
"event_type" to "error",
"error_message" to (error.message ?: "unknown"),
"context" to context
)
)
)
Log.e(TAG, "❌ Error: $context", error)
}
}5. 성능 최적화: Throttling
class ThrottledEventTracker {
private val lastTrackTimes = mutableMapOf<String, Long>()
private val throttleInterval = 2000L // 2초
fun trackEvent(event: AdStageEvent) {
val eventKey = event.eventName
val now = System.currentTimeMillis()
val lastTime = lastTrackTimes[eventKey] ?: 0L
if (now - lastTime >= throttleInterval) {
AdStageManager.trackEvent(event)
lastTrackTimes[eventKey] = now
} else {
Log.d("AdStage", "⏱️ Throttled: $eventKey")
}
}
}
// 사용 (스크롤 이벤트 등)
val throttledTracker = ThrottledEventTracker()
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
throttledTracker.trackEvent(
AdStageEvent.Custom(
params = mapOf(
"action" to "scroll",
"delta_y" to dy
)
)
)
}
})변환 예제
// 1. 기본 이벤트
AdStage.trackEvent("first_open")
→ AdStageManager.trackEvent(AdStageEvent.FirstOpen())
// 2. 로그인
AdStage.trackEvent("login", mapOf("method" to "email"))
→ AdStageManager.trackEvent(AdStageEvent.Login(method = SignUpMethod.EMAIL))
// 3. 화면 조회
AdStage.trackEvent("screen_view", mapOf("screen_name" to "home"))
→ AdStageManager.trackEvent(AdStageEvent.ScreenView(screenName = "home"))
// 4. 커스텀
AdStage.trackEvent("custom", mapOf("action" to "click"))
→ AdStageManager.trackEvent(AdStageEvent.Custom(params = mapOf("action" to "click")))트러블슈팅
1. 컴파일 에러: "currency 파라미터 필수"
문제:
// ❌ 에러
AdStageManager.trackEvent(
AdStageEvent.Purchase(value = 9900.0)
)해결:
// ✅ currency 추가 (ISO 4217, 3자리)
AdStageManager.trackEvent(
AdStageEvent.Purchase(
value = 9900.0,
currency = "KRW"
)
)2. IDE 자동완성 작동 안 함
해결:
- Gradle Sync:
File → Sync Project with Gradle Files - Invalidate Caches:
File → Invalidate Caches / Restart... - Import 확인:
import io.nbase.adapter.adstage.models.AdStageEvent.*
// 이제 자동완성 작동
AdStageManager.trackEvent(Purchase(...))3. ProGuard/R8 난독화 문제
# proguard-rules.pro
# AdStage 이벤트 모델 보존
-keep class io.nbase.adapter.adstage.models.** { *; }
-keepclassmembers class io.nbase.adapter.adstage.models.** { *; }
# AdStageEvent sealed class
-keep class io.nbase.adapter.adstage.models.AdStageEvent { *; }
-keep class io.nbase.adapter.adstage.models.AdStageEvent$* { *; }
# Kotlin Metadata
-keep class kotlin.Metadata { *; }
4. 통화 코드 검증 에러
// ❌ 2자리 코드
AdStageEvent.Purchase(value = 100.0, currency = "KR")
// ValidationException: "Currency must be 3-letter ISO 4217 code"
// ✅ 3자리 ISO 4217 코드
AdStageEvent.Purchase(value = 100.0, currency = "KRW") // 한국 원
AdStageEvent.Purchase(value = 100.0, currency = "USD") // 미국 달러
AdStageEvent.Purchase(value = 100.0, currency = "JPY") // 일본 엔주요 통화 코드:
| 국가 | 통화 | 코드 |
|---|---|---|
| 한국 | 원 | KRW |
| 미국 | 달러 | USD |
| 일본 | 엔 | JPY |
| 유럽연합 | 유로 | EUR |
| 영국 | 파운드 | GBP |
5. 디버그 로그 확인
// Application.onCreate()
if (BuildConfig.DEBUG) {
AdStageManager.setDebugMode(true)
}Logcat 필터:
# Android Studio
tag:AdStage OR tag:AdapterAdStage
# adb
adb logcat | grep -i adstage참고 자료
표준 참조
FAQ
Q: 커스텀 이벤트는 어떻게 전송하나요?
A: AdStageEvent.Custom(params = mapOf(...)) 사용
Q: value 없이 currency만 사용할 수 있나요?
A: 아니요, value 사용 시 currency는 필수입니다.
Q: 오프라인에서도 작동하나요?
A: 예, SDK가 자동으로 이벤트를 큐에 저장하고 네트워크 복구 시 전송합니다.
지원
연락처:
- 이메일: support@nbase.io
© 2025 NBase. All rights reserved.

