adstage
モバイル SDKアプリ内イベント

Android

AdStage アプリ内イベント統合ガイド(Android)

目次

  1. 概要
  2. 基本設定
  3. 型安全なイベント送信
  4. 標準イベントカタログ
  5. イベントタイプ別の例
  6. ベストプラクティス
  7. トラブルシューティング

概要

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.9")
    
    // 必須の依存関係
    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.AdStage
 
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        
        // AdStage の初期化
        AdStage.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. 最もシンプルな方法

trackEvent は suspend 関数とコールバックのオーバーロードをあわせて提供します。 suspend 関数はコルーチンスコープの中で呼び出し、コルーチンの外ではコールバック版を使います。

import io.nbase.adapter.adstage.AdStage
import io.nbase.adapter.adstage.models.AdStageEvent
import io.nbase.adapter.adstage.models.SignUpMethod
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
 
CoroutineScope(Dispatchers.IO).launch {
    // パラメータのないイベント(suspend)
    AdStage.trackEvent(AdStageEvent.FirstOpen())
 
    // ログインイベント(method は文字列。SignUpMethod enum の value を使用)
    AdStage.trackEvent(
        AdStageEvent.Login(method = SignUpMethod.EMAIL.value)
    )
}
 
// コールバック版(コルーチンなしで呼び出し)
AdStage.trackEvent(AdStageEvent.Login(method = SignUpMethod.EMAIL.value)) { result ->
    when (result) {
        is TrackEventResult.Success -> Log.d("AdStage", "送信に成功しました")
        is TrackEventResult.Failure -> Log.e("AdStage", "送信に失敗しました: ${result.error}")
    }
}

2. 購入イベント(検証の例)

value がある場合、currency は必須です。指定しないと、イベントオブジェクトの作成時点で IllegalArgumentException が発生します(ランタイム検証)。

// ✅ GOOD: value と currency をあわせて指定
AdStage.trackEvent(
    AdStageEvent.Purchase(
        value = 29.99,
        currency = "USD",
        transactionId = "TXN_123456"
    )
)
 
// ❌ BAD: value だけを指定するとランタイム例外 (IllegalArgumentException)
AdStage.trackEvent(
    AdStageEvent.Purchase(
        value = 29.99  // ❌ 例外:value がある場合は currency が必須!
    )
)
 
// ✅ GOOD: currency なしで transactionId のみ
AdStage.trackEvent(
    AdStageEvent.Purchase(
        transactionId = "TXN_123456"
    )
)

3. 商品の閲覧

// パラメータあり
AdStage.trackEvent(
    AdStageEvent.ProductDetailsView(
        itemId = "PROD_123",
        itemName = "Wireless Earbuds"
    )
)
 
// パラメータなし
AdStage.trackEvent(AdStageEvent.ProductListView())

4. カスタムイベント(event_name の自動昇格)

標準イベント以外のアプリ固有のイベントを送信するときは、AdStageEvent.Custom を使います。 パラメータに event_name キーを含めると、その値が実際のイベント名に自動で昇格され、ダッシュボードに保存されます。

// 例:'promotion_click' というカスタムイベントを送信
AdStage.trackEvent(
    AdStageEvent.Custom(
        params = mapOf(
            "event_name" to "promotion_click",
            "promotion_id" to "summer_sale_2025",
            "screen" to "home_banner"
        )
    )
)
// ダッシュボードには "promotion_click" イベントとして収集される
 
// event_name なしの一般的なカスタムイベント
AdStage.trackEvent(
    AdStageEvent.Custom(
        params = mapOf(
            "action" to "button_click",
            "button_id" to "promo_banner",
            "screen" to "home",
            "timestamp" to System.currentTimeMillis()
        )
    )
)
// ダッシュボードには "custom" イベントとして収集される
 
// Click、View も自由なパラメータに対応
AdStage.trackEvent(
    AdStageEvent.Click(
        params = mapOf(
            "campaign_id" to "SUMMER2025",
            "ad_group" to "electronics"
        )
    )
)

標準イベントカタログ

AdStage SDK は 46 個の標準イベントを提供します。

📌 広告トラッキング(4 個)

// 1. 広告のクリック
AdStage.trackEvent(
    AdStageEvent.Click(
        params = mapOf("campaign_id" to "CAMP_123")
    )
)
 
// 2. 広告のインプレッション
AdStage.trackEvent(
    AdStageEvent.View(
        params = mapOf("impression_id" to "IMP_456")
    )
)
 
// 3. アプリのインストール
AdStage.trackEvent(AdStageEvent.Install())
 
// 4. カスタムイベント(event_name でイベント名を指定)
AdStage.trackEvent(
    AdStageEvent.Custom(
        params = mapOf(
            "event_name" to "promotion_click",
            "promotion_id" to "summer_sale_2025"
        )
    )
)

👤 ユーザーライフサイクル(5 個)

SignUp と Login の method は文字列(String?)のパラメータです。文字列を直接 指定するか、SDK が提供する SignUpMethod enum の .value を使います。

// SDK が提供する SignUpMethod enum(参考用)
enum class SignUpMethod(val value: String) {
    EMAIL("email"),
    GOOGLE("google"),
    APPLE("apple"),
    FACEBOOK("facebook"),
    KAKAO("kakao"),
    NAVER("naver")
}
 
// 1. 会員登録の完了
AdStage.trackEvent(
    AdStageEvent.SignUp(method = SignUpMethod.GOOGLE.value)
)
 
// 2. 会員登録の開始
AdStage.trackEvent(AdStageEvent.SignUpStart())
 
// 3. ログイン(文字列を直接使うことも可能: method = "email")
AdStage.trackEvent(
    AdStageEvent.Login(method = SignUpMethod.EMAIL.value)
)
 
// 4. ログアウト
AdStage.trackEvent(AdStageEvent.Logout())
 
// 5. アプリの初回起動
AdStage.trackEvent(AdStageEvent.FirstOpen())

📄 コンテンツの閲覧(6 個)

// 1. ホーム画面
AdStage.trackEvent(AdStageEvent.HomeView())
 
// 2. 商品一覧
AdStage.trackEvent(
    AdStageEvent.ProductListView(itemCategory = "electronics")
)
 
// 3. 検索結果
AdStage.trackEvent(
    AdStageEvent.SearchResultView(searchTerm = "wireless headphones")
)
 
// 4. 商品詳細
AdStage.trackEvent(
    AdStageEvent.ProductDetailsView(
        itemId = "PROD_123",
        itemName = "Wireless Earbuds"
    )
)
 
// 5. ページビュー(ウェブ)
AdStage.trackEvent(
    AdStageEvent.PageView(
        pageUrl = "https://example.com/products",
        pageTitle = "Products"
    )
)
 
// 6. 画面ビュー(アプリ)
AdStage.trackEvent(
    AdStageEvent.ScreenView(
        screenName = "product_detail",
        screenClass = "ProductDetailActivity"
    )
)

🛒 EC(7 個)

EcommerceItem が持つフィールドは itemId、itemName、price、quantity の 4 つだけです。

// 1. カートに追加
AdStage.trackEvent(
    AdStageEvent.AddToCart(
        value = 99000.0,
        currency = "KRW",
        items = listOf(
            EcommerceItem(
                itemId = "PROD_123",
                itemName = "Wireless Earbuds",
                price = 99000.0,
                quantity = 1
            )
        )
    )
)
 
// 2. カートから削除
AdStage.trackEvent(
    AdStageEvent.RemoveFromCart(
        value = 50000.0,
        currency = "KRW"
    )
)
 
// 3. ウィッシュリストに追加
AdStage.trackEvent(
    AdStageEvent.AddToWishlist(
        itemId = "PROD_456",
        itemName = "Smart Watch"
    )
)
 
// 4. 支払い情報の入力
AdStage.trackEvent(
    AdStageEvent.AddPaymentInfo(paymentType = "credit_card")
)
 
// 5. 決済の開始
AdStage.trackEvent(
    AdStageEvent.BeginCheckout(
        value = 150000.0,
        currency = "KRW"
    )
)
 
// 6. 購入の完了 ⭐⭐⭐
AdStage.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",
                price = 126000.0,
                quantity = 1
            )
        )
    )
)
 
// 7. 返金
AdStage.trackEvent(
    AdStageEvent.Refund(
        transactionId = "ORDER_20250105_001",
        value = 129000.0,
        currency = "KRW"
    )
)

🎮 進行・達成(4 個)

// 1. チュートリアルの開始
AdStage.trackEvent(
    AdStageEvent.TutorialBegin(
        params = mapOf("tutorial_id" to "intro")
    )
)
 
// 2. チュートリアルの完了
AdStage.trackEvent(
    AdStageEvent.TutorialComplete(
        params = mapOf("duration_seconds" to 120)
    )
)
 
// 3. レベルアップ
AdStage.trackEvent(
    AdStageEvent.LevelUp(
        level = 25,
        character = "warrior"
    )
)
 
// 4. 実績の達成
AdStage.trackEvent(
    AdStageEvent.Achievement(achievementId = "first_win")
)

💬 インタラクション(7 個)

// 1. 検索
AdStage.trackEvent(
    AdStageEvent.Search(searchTerm = "gaming laptop")
)
 
// 2. コンテンツの選択
AdStage.trackEvent(
    AdStageEvent.SelectContent(
        contentType = "product",
        contentId = "PROD_789"
    )
)
 
// 3. 共有
AdStage.trackEvent(
    AdStageEvent.Share(
        contentType = "product",
        method = "kakao"
    )
)
 
// 4. いいね
AdStage.trackEvent(
    AdStageEvent.Like(
        contentType = "product",
        contentId = "PROD_789"
    )
)
 
// 5. 評価
AdStage.trackEvent(
    AdStageEvent.Rate(
        contentType = "product",
        contentId = "PROD_789",
        score = 4.5
    )
)
 
// 6. 予定の登録
AdStage.trackEvent(
    AdStageEvent.Schedule(
        params = mapOf("event_type" to "appointment")
    )
)
 
// 7. クレジットの使用
AdStage.trackEvent(
    AdStageEvent.SpendCredits(
        value = 10.0,
        itemName = "premium_feature"
    )
)

📢 アプリ内広告(2 個)

// 1. アプリ内広告のインプレッション
AdStage.trackEvent(
    AdStageEvent.AdImpression(
        adPlatform = "admob",
        adFormat = "rewarded_video",
        adUnitName = "main_reward"
    )
)
 
// 2. アプリ内広告のクリック
AdStage.trackEvent(
    AdStageEvent.AdClick(
        adPlatform = "admob",
        adFormat = "banner",
        adUnitName = "home_bottom"
    )
)

🎮 ゲーム向け(4 個)

// 1. ゲームプレイ
AdStage.trackEvent(
    AdStageEvent.GamePlay(
        level = 10,
        levelName = "Dragon's Lair",
        character = "mage",
        contentType = "dungeon"
    )
)
 
// 2. ボーナスの獲得
AdStage.trackEvent(
    AdStageEvent.AcquireBonus(
        contentType = "reward",
        itemId = "ITEM_123",
        itemName = "Gold Chest",
        quantity = 1
    )
)
 
// 3. ゲームサーバーの選択
AdStage.trackEvent(
    AdStageEvent.SelectGameServer(
        contentId = "SERVER_01",
        contentType = "pvp",
        itemName = "Asia Server"
    )
)
 
// 4. パッチの完了
AdStage.trackEvent(
    AdStageEvent.CompletePatch(
        contentId = "PATCH_2.1.0",
        contentType = "update"
    )
)

📅 サブスクリプション・トライアル(3 個)

// 1. 無料トライアルの開始
AdStage.trackEvent(
    AdStageEvent.StartTrial(
        value = 9900.0,
        currency = "KRW",
        trialDays = 14
    )
)
 
// 2. サブスクリプションの開始
AdStage.trackEvent(
    AdStageEvent.Subscribe(
        value = 9900.0,
        currency = "KRW",
        subscriptionId = "premium_monthly"
    )
)
 
// 3. サブスクリプションの解約
AdStage.trackEvent(
    AdStageEvent.Unsubscribe(subscriptionId = "premium_monthly")
)

💰 金融向け(4 個)

// 1. 株式の買い付け
AdStage.trackEvent(
    AdStageEvent.BuyStock(
        itemId = "005930",
        itemName = "サムスン電子",
        quantity = 10,
        price = 70000.0,
        value = 700000.0,
        currency = "KRW"
    )
)
 
// 2. 株式の売却
AdStage.trackEvent(
    AdStageEvent.SellStock(
        itemId = "005930",
        itemName = "サムスン電子",
        quantity = 5,
        price = 72000.0,
        value = 360000.0,
        currency = "KRW"
    )
)
 
// 3. 口座開設の完了
AdStage.trackEvent(
    AdStageEvent.CompleteOpenAccount(
        contentType = "証券口座",
        contentId = "ACC_123",
        method = "mobile"
    )
)
 
// 4. カードの申し込み
AdStage.trackEvent(
    AdStageEvent.ApplyCard(
        contentType = "クレジットカード",
        itemName = "プレミアムカード",
        itemId = "CARD_001"
    )
)

イベントタイプ別の例

1. アプリのライフサイクル

class MyApplication : Application() {
    
    override fun onCreate() {
        super.onCreate()
        
        // SDK の初期化
        AdStage.initialize(this, apiKey, serverUrl)
        
        // 初回起動イベントは SDK が自動で送信
        Log.d("App", "✅ アプリを起動しました")
    }
}

2. ユーザー認証

class AuthManager {
    
    // 会員登録(method は文字列のパラメータ)
    fun onSignUpComplete(method: String) {
        AdStage.trackEvent(
            AdStageEvent.SignUp(method = method)
        )
        
        Log.d("Auth", "✅ 会員登録が完了しました: $method")
    }
    
    // ログイン
    fun onLoginSuccess(userId: String, method: String) {
        AdStage.trackEvent(
            AdStageEvent.Login(method = method)
        )
        
        Log.d("Auth", "✅ ログイン: $userId")
    }
    
    // ログアウト
    fun onLogout() {
        AdStage.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() {
        AdStage.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) {
        // 商品データを読み込み中...
        
        // 商品詳細の閲覧イベント
        AdStage.trackEvent(
            AdStageEvent.ProductDetailsView(
                itemId = productId,
                itemName = product.name
            )
        )
    }
}

4. EC の一連のフロー

class EcommerceManager {
    
    // 1. 商品一覧の閲覧
    fun trackProductList(category: String) {
        AdStage.trackEvent(
            AdStageEvent.ProductListView(itemCategory = category)
        )
    }
    
    // 2. 検索
    fun trackSearch(query: String) {
        AdStage.trackEvent(
            AdStageEvent.Search(searchTerm = query)
        )
    }
    
    // 3. 検索結果の閲覧
    fun trackSearchResults(query: String) {
        AdStage.trackEvent(
            AdStageEvent.SearchResultView(searchTerm = query)
        )
    }
    
    // 4. 商品詳細の閲覧
    fun trackProductView(product: Product) {
        AdStage.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,
            price = product.price,
            quantity = quantity
        )
        
        AdStage.trackEvent(
            AdStageEvent.AddToCart(
                value = product.price * quantity,
                currency = "KRW",
                items = listOf(item)
            )
        )
    }
    
    // 6. ウィッシュリストに追加
    fun trackAddToWishlist(product: Product) {
        AdStage.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,
                price = cartItem.product.price,
                quantity = cartItem.quantity
            )
        }
        
        AdStage.trackEvent(
            AdStageEvent.BeginCheckout(
                value = cart.totalAmount,
                currency = "KRW",
                items = items
            )
        )
    }
    
    // 8. 支払い情報の入力
    fun trackAddPaymentInfo(paymentMethod: String) {
        AdStage.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,
                price = orderItem.product.price,
                quantity = orderItem.quantity
            )
        }
        
        AdStage.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) {
        AdStage.trackEvent(
            AdStageEvent.Refund(
                transactionId = order.id,
                value = order.totalAmount,
                currency = "KRW"
            )
        )
    }
    
    // 11. 共有
    fun trackShare(product: Product, method: String) {
        AdStage.trackEvent(
            AdStageEvent.Share(
                contentType = "product",
                method = method
            )
        )
    }
}

5. ゲームイベント

class GameEventManager {
    
    // チュートリアル
    fun trackTutorialBegin(tutorialId: String) {
        AdStage.trackEvent(
            AdStageEvent.TutorialBegin(
                params = mapOf("tutorial_id" to tutorialId)
            )
        )
    }
    
    fun trackTutorialComplete(tutorialId: String, duration: Long) {
        AdStage.trackEvent(
            AdStageEvent.TutorialComplete(
                params = mapOf(
                    "tutorial_id" to tutorialId,
                    "duration_seconds" to duration / 1000
                )
            )
        )
    }
    
    // レベル
    fun trackLevelUp(level: Int, character: String) {
        AdStage.trackEvent(
            AdStageEvent.LevelUp(
                level = level,
                character = character
            )
        )
    }
    
    // 実績
    fun trackAchievement(achievementId: String) {
        AdStage.trackEvent(
            AdStageEvent.Achievement(achievementId = achievementId)
        )
    }
    
    // ゲームプレイ
    fun trackGameStart(level: Int, levelName: String, character: String) {
        AdStage.trackEvent(
            AdStageEvent.GamePlay(
                level = level,
                levelName = levelName,
                character = character,
                contentType = "pvp"
            )
        )
    }
    
    // ボーナスの獲得
    fun trackBonusAcquired(itemId: String, itemName: String, quantity: Int) {
        AdStage.trackEvent(
            AdStageEvent.AcquireBonus(
                contentType = "reward",
                itemId = itemId,
                itemName = itemName,
                quantity = quantity
            )
        )
    }
    
    // クレジット(通貨)の使用
    fun trackSpendCredits(amount: Double, itemName: String) {
        AdStage.trackEvent(
            AdStageEvent.SpendCredits(
                value = amount,
                itemName = itemName
            )
        )
    }
}

ベストプラクティス

1. Extension 関数の活用

// ActivityExtensions.kt
fun Activity.trackScreen() {
    val screenName = this::class.java.simpleName
        .removeSuffix("Activity")
        .lowercase()
    
    AdStage.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
                
                // 商品閲覧イベント
                AdStage.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
                )
                
                AdStage.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)
        
        AdStage.trackEvent(
            AdStageEvent.ScreenView(
                screenName = "product_detail",
                screenClass = "ProductDetailScreen"
            )
        )
    }
    
    Column {
        // UI...
        
        Button(
            onClick = {
                viewModel.addToCart(product, 1)
                
                AdStage.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) {
        AdStage.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
            )
        }
        
        AdStage.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) {
        AdStage.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) {
            AdStage.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
                )
            )
        )
    }
})

変換の例(文字列ベース → 型安全 API)

現在の SDK は、AdStageEvent の型安全なイベントのみに対応しています。以下は、文字列ベースの イベント名を型安全なイベントに変換する例です(矢印の右側が実際の使用形式)。

// 1. 基本イベント
"first_open"
→ AdStage.trackEvent(AdStageEvent.FirstOpen())
 
// 2. ログイン(method は文字列のパラメータ)
"login", method = "email"
→ AdStage.trackEvent(AdStageEvent.Login(method = "email"))
 
// 3. 画面ビュー
"screen_view", screen_name = "home"
→ AdStage.trackEvent(AdStageEvent.ScreenView(screenName = "home"))
 
// 4. カスタム
"custom", action = "click"
→ AdStage.trackEvent(AdStageEvent.Custom(params = mapOf("action" to "click")))

トラブルシューティング

1. ランタイム例外:「value がある場合、currency は必須です」

問題:

// ❌ IllegalArgumentException (イベントオブジェクトの作成時点)
AdStage.trackEvent(
    AdStageEvent.Purchase(value = 9900.0)
)

解決:

// ✅ currency を追加(ISO 4217、3 文字)
AdStage.trackEvent(
    AdStageEvent.Purchase(
        value = 9900.0,
        currency = "KRW"
    )
)

2. IDE の自動補完が機能しない

解決:

  1. Gradle Sync: File → Sync Project with Gradle Files
  2. Invalidate Caches: File → Invalidate Caches / Restart...
  3. Import を確認:
import io.nbase.adapter.adstage.models.AdStageEvent.*
 
// これで自動補完が機能します
AdStage.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")
// IllegalArgumentException: "currency は ISO 4217 の 3 文字コードである必要があります(例: USD, KRW)"
 
// ✅ 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. デバッグログの確認

SDK は AdStage / AdapterAdStage タグでログを出力します。以下のフィルターを使うと、Logcat で イベント送信の流れを確認できます。

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 がイベントを自動でキューに保存し、ネットワークの復旧時に送信します。


サポート

お問い合わせ先:


© 2025 NBase. All rights reserved.

目次

AdStage アプリ内イベント統合ガイド(Android)目次概要主な機能基本設定1. Gradle 依存関係の追加2. SDK の初期化3. AndroidManifest.xml型安全なイベント送信1. 最もシンプルな方法2. 購入イベント(検証の例)3. 商品の閲覧4. カスタムイベント(event_name の自動昇格)標準イベントカタログ📌 広告トラッキング(4 個)👤 ユーザーライフサイクル(5 個)📄 コンテンツの閲覧(6 個)🛒 EC(7 個)🎮 進行・達成(4 個)💬 インタラクション(7 個)📢 アプリ内広告(2 個)🎮 ゲーム向け(4 個)📅 サブスクリプション・トライアル(3 個)💰 金融向け(4 個)イベントタイプ別の例1. アプリのライフサイクル2. ユーザー認証3. 画面トラッキング(BaseActivity パターン)4. EC の一連のフロー5. ゲームイベントベストプラクティス1. Extension 関数の活用2. ViewModel でのイベントトラッキング3. Compose UI での使用4. イベントラッパークラス5. パフォーマンス最適化:Throttling変換の例(文字列ベース → 型安全 API)トラブルシューティング1. ランタイム例外:「value がある場合、currency は必須です」2. IDE の自動補完が機能しない3. ProGuard/R8 の難読化の問題4. 通貨コードの検証エラー5. デバッグログの確認参考資料標準リファレンスFAQサポート