メインコンテンツへスキップ

概要

ネイティブ広告は、アプリのデザインに合わせて広告UIを自由にカスタマイズできる広告フォーマットです。広告素材(画像、動画)、タイトル、説明、CTAボタンなどの要素を個別に配置して、自然なユーザー体験を提供できます。

主な機能

  • 完全なUIカスタマイズ:アプリのデザインシステムに合わせて広告レイアウトを自由に構成
  • 様々なメディアサポート:画像および動画広告素材サポート
  • 柔軟なクリック領域設定:全体クリックまたは個別要素別クリック処理可能
  • プロフィール情報表示:広告主プロフィールロゴ、名前、リンクサポート

クラスとインターフェース

AdropNativeAd

ネイティブ広告をロードして管理するメインクラスです。
unitId
String
必須
広告ユニットID(コンソールで発行)
contextId
String
コンテキストターゲティング用のID(オプション)
listener
AdropNativeAdListener
広告イベントを処理するリスナー
useCustomClick
Boolean
デフォルト:"false"
カスタムクリック処理の使用有無

主なプロパティ

プロパティタイプ説明
headlineString広告タイトル
bodyString広告本文
iconStringアイコン画像URL
coverStringカバー画像URL
advertiserString非推奨。 代わりにprofile.displayNameを使用してください。
advertiserURLString非推奨。 代わりにprofile.linkを使用してください。
accountTagJSONObject非推奨。 サポート終了。
creativeTagJSONObject非推奨。 サポート終了。
callToActionString行動喚起文言(例:「今すぐ確認」)
profileAdropNativeAdProfile広告主プロフィール情報
isLoadedBoolean広告ロード完了状態
isDestroyedBoolean広告削除状態

AdropNativeAdView

ネイティブ広告を表示するコンテナビューです。
isEntireClick
Boolean
デフォルト:"false"
全体領域クリックの有効化有無。trueに設定すると広告ビュー全体領域でクリックイベントが発生します。

主なメソッド

メソッド説明
setIconView(view, listener)アイコン画像ビュー設定(ImageViewタイプ)
setHeadLineView(view, listener)タイトルテキストビュー設定(TextViewタイプ)
setBodyView(view)本文テキストビュー設定(TextViewタイプ)
setMediaView(view)メディアコンテナビュー設定(AdropMediaViewタイプ)
setAdvertiserView(view, listener)広告主名テキストビュー設定(TextViewタイプ)
setCallToActionView(view)CTAボタンまたはテキストビュー設定
setProfileLogoView(view, listener)プロフィールロゴ画像ビュー設定(ImageViewタイプ)
setProfileNameView(view, listener)プロフィール名テキストビュー設定(TextViewタイプ)
setNativeAd(ad)広告データをビューにバインド
destroy()リソース解放

AdropMediaView

広告画像または動画を表示するメディアコンテナビューです。
<io.adrop.ads.nativeAd.AdropMediaView
    android:id="@+id/ad_media"
    android:layout_width="match_parent"
    android:layout_height="200dp" />
動画クリエイティブの場合、必ずAdropNativeAdView.setMediaView(...)を通じてAdropMediaViewをバインドする必要があります。ad.asset URLを読み取り、独自プレイヤー(ExoPlayerMediaPlayerまたはサードパーティライブラリ)で直接再生すると、SDKの動画トラッキングパイプラインを経由しなくなり、VTRが計測されずonAdVideoStart / onAdVideoEndコールバックも呼び出されません。動画トラッキングとVTRセクションを参照してください。

AdropNativeAdListener

広告イベントを処理するインターフェースです。
interface AdropNativeAdListener {
    fun onAdReceived(ad: AdropNativeAd)
    fun onAdClicked(ad: AdropNativeAd)
    fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode)
    fun onAdImpression(ad: AdropNativeAd) // オプション実装
    fun onAdVideoStart(ad: AdropNativeAd) // オプション実装
    fun onAdVideoEnd(ad: AdropNativeAd) // オプション実装
}

AdropNativeAdProfile

広告主プロフィール情報を含むデータクラスです。
プロパティタイプ説明
displayLogoStringプロフィールロゴ画像URL
displayNameStringプロフィール表示名
linkStringプロフィールリンクURL

実装ガイド

1. XMLレイアウト設定

ネイティブ広告を表示するレイアウトを定義します。AdropNativeAdViewをルートとして、内部に広告要素を配置します。
res/layout/native_ad_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<io.adrop.ads.nativeAd.AdropNativeAdView
    android:id="@+id/native_ad_view"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="16dp">

        <!-- プロフィール領域 -->
        <ImageView
            android:id="@+id/ad_profile_logo"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:scaleType="centerCrop"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/ad_profile_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintStart_toEndOf="@id/ad_profile_logo"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/ad_badge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="4dp"
            android:text="広告"
            android:textSize="12sp"
            app:layout_constraintStart_toEndOf="@id/ad_profile_logo"
            app:layout_constraintTop_toBottomOf="@id/ad_profile_name" />

        <!-- メディア領域 -->
        <io.adrop.ads.nativeAd.AdropMediaView
            android:id="@+id/ad_media"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_marginTop="12dp"
            app:layout_constraintTop_toBottomOf="@id/ad_profile_logo" />

        <!-- 広告コンテンツ -->
        <TextView
            android:id="@+id/ad_headline"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintTop_toBottomOf="@id/ad_media" />

        <TextView
            android:id="@+id/ad_body"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:textSize="14sp"
            app:layout_constraintTop_toBottomOf="@id/ad_headline" />

        <!-- 下部領域 -->
        <TextView
            android:id="@+id/ad_advertiser"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:textSize="14sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/ad_body" />

        <Button
            android:id="@+id/ad_call_to_action"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/ad_body" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</io.adrop.ads.nativeAd.AdropNativeAdView>

2. 広告のロードと表示(Kotlin)

import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import io.adrop.ads.model.AdropErrorCode
import io.adrop.ads.nativeAd.AdropMediaView
import io.adrop.ads.nativeAd.AdropNativeAd
import io.adrop.ads.nativeAd.AdropNativeAdListener
import io.adrop.ads.nativeAd.AdropNativeAdView

class NativeAdActivity : AppCompatActivity() {

    private lateinit var nativeAd: AdropNativeAd
    private lateinit var nativeAdView: AdropNativeAdView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_native_ad)

        nativeAdView = findViewById(R.id.native_ad_view)
        loadNativeAd()
    }

    private fun loadNativeAd() {
        // 1. ネイティブ広告インスタンス作成
        nativeAd = AdropNativeAd(
            context = this,
            unitId = "YOUR_UNIT_ID"  // 実際のユニットIDに置き換え
        )

        // 2. リスナー設定
        nativeAd.listener = object : AdropNativeAdListener {
            override fun onAdReceived(ad: AdropNativeAd) {
                Log.d("Adrop", "広告受信成功")
                populateNativeAdView(ad)
            }

            override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {
                Log.e("Adrop", "広告受信失敗:$errorCode")
            }

            override fun onAdClicked(ad: AdropNativeAd) {
                Log.d("Adrop", "広告クリック")
            }

            override fun onAdImpression(ad: AdropNativeAd) {
                Log.d("Adrop", "広告インプレッション")
            }

            override fun onAdVideoStart(ad: AdropNativeAd) {
                Log.d("Adrop", "広告動画再生開始")
            }

            override fun onAdVideoEnd(ad: AdropNativeAd) {
                Log.d("Adrop", "広告動画再生終了")
            }
        }

        // 3. 広告ロード
        nativeAd.load()
    }

    private fun populateNativeAdView(ad: AdropNativeAd) {
        // プロフィール設定
        val profileLogoView = findViewById<ImageView>(R.id.ad_profile_logo)
        Glide.with(this).load(ad.profile.displayLogo).into(profileLogoView)
        nativeAdView.setProfileLogoView(profileLogoView)

        val profileNameView = findViewById<TextView>(R.id.ad_profile_name)
        profileNameView.text = ad.profile.displayName
        nativeAdView.setProfileNameView(profileNameView)

        // タイトル設定
        val headlineView = findViewById<TextView>(R.id.ad_headline)
        headlineView.text = ad.headline
        nativeAdView.setHeadLineView(headlineView)

        // メディア設定
        val mediaView = findViewById<AdropMediaView>(R.id.ad_media)
        nativeAdView.setMediaView(mediaView)

        // 本文設定
        val bodyView = findViewById<TextView>(R.id.ad_body)
        bodyView.text = ad.body
        nativeAdView.setBodyView(bodyView)

        // 広告主設定
        val advertiserView = findViewById<TextView>(R.id.ad_advertiser)
        advertiserView.text = ad.profile.displayName
        nativeAdView.setAdvertiserView(advertiserView)

        // CTAボタン設定
        val ctaView = findViewById<Button>(R.id.ad_call_to_action)
        ctaView.text = ad.callToAction
        nativeAdView.setCallToActionView(ctaView)

        // 広告データバインド
        nativeAdView.setNativeAd(ad)
    }

    override fun onDestroy() {
        // リソース解放
        nativeAdView.destroy()
        nativeAd.destroy()
        super.onDestroy()
    }
}
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import io.adrop.ads.model.AdropErrorCode
import io.adrop.ads.nativeAd.AdropMediaView
import io.adrop.ads.nativeAd.AdropNativeAd
import io.adrop.ads.nativeAd.AdropNativeAdListener
import io.adrop.ads.nativeAd.AdropNativeAdView

class NativeAdFragment : Fragment() {

    private var nativeAd: AdropNativeAd? = null
    private var nativeAdView: AdropNativeAdView? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_native_ad, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        nativeAdView = view.findViewById(R.id.native_ad_view)
        loadNativeAd()
    }

    private fun loadNativeAd() {
        nativeAd = AdropNativeAd(
            context = requireContext(),
            unitId = "YOUR_UNIT_ID"
        )

        nativeAd?.listener = object : AdropNativeAdListener {
            override fun onAdReceived(ad: AdropNativeAd) {
                populateNativeAdView(ad)
            }

            override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {
                Log.e("Adrop", "広告ロード失敗:$errorCode")
            }

            override fun onAdClicked(ad: AdropNativeAd) {
                Log.d("Adrop", "広告クリック")
            }
        }

        nativeAd?.load()
    }

    private fun populateNativeAdView(ad: AdropNativeAd) {
        val view = requireView()

        // プロフィールロゴ
        val profileLogo = view.findViewById<ImageView>(R.id.ad_profile_logo)
        Glide.with(this).load(ad.profile.displayLogo).into(profileLogo)
        nativeAdView?.setProfileLogoView(profileLogo)

        // プロフィール名
        val profileName = view.findViewById<TextView>(R.id.ad_profile_name)
        profileName.text = ad.profile.displayName
        nativeAdView?.setProfileNameView(profileName)

        // タイトル
        val headline = view.findViewById<TextView>(R.id.ad_headline)
        headline.text = ad.headline
        nativeAdView?.setHeadLineView(headline)

        // メディア
        val media = view.findViewById<AdropMediaView>(R.id.ad_media)
        nativeAdView?.setMediaView(media)

        // 本文
        val body = view.findViewById<TextView>(R.id.ad_body)
        body.text = ad.body
        nativeAdView?.setBodyView(body)

        // 広告主
        val advertiser = view.findViewById<TextView>(R.id.ad_advertiser)
        advertiser.text = ad.profile.displayName
        nativeAdView?.setAdvertiserView(advertiser)

        // CTA
        val cta = view.findViewById<Button>(R.id.ad_call_to_action)
        cta.text = ad.callToAction
        nativeAdView?.setCallToActionView(cta)

        // バインド
        nativeAdView?.setNativeAd(ad)
    }

    override fun onDestroyView() {
        nativeAdView?.destroy()
        nativeAd?.destroy()
        super.onDestroyView()
    }
}

3. 広告のロードと表示(Java)

Java
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import io.adrop.ads.model.AdropErrorCode;
import io.adrop.ads.nativeAd.AdropMediaView;
import io.adrop.ads.nativeAd.AdropNativeAd;
import io.adrop.ads.nativeAd.AdropNativeAdListener;
import io.adrop.ads.nativeAd.AdropNativeAdView;

public class NativeAdActivity extends AppCompatActivity {

    private AdropNativeAd nativeAd;
    private AdropNativeAdView nativeAdView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_native_ad);

        nativeAdView = findViewById(R.id.native_ad_view);
        loadNativeAd();
    }

    private void loadNativeAd() {
        // 1. ネイティブ広告インスタンス作成
        nativeAd = new AdropNativeAd(
            this,
            "YOUR_UNIT_ID",  // 実際のユニットIDに置き換え
            null  // contextId(オプション)
        );

        // 2. リスナー設定
        nativeAd.setListener(new AdropNativeAdListener() {
            @Override
            public void onAdReceived(AdropNativeAd ad) {
                Log.d("Adrop", "広告受信成功");
                populateNativeAdView(ad);
            }

            @Override
            public void onAdFailedToReceive(AdropNativeAd ad, AdropErrorCode errorCode) {
                Log.e("Adrop", "広告受信失敗:" + errorCode);
            }

            @Override
            public void onAdClicked(AdropNativeAd ad) {
                Log.d("Adrop", "広告クリック");
            }

            @Override
            public void onAdImpression(AdropNativeAd ad) {
                Log.d("Adrop", "広告インプレッション");
            }

            @Override
            public void onAdVideoStart(AdropNativeAd ad) {
                Log.d("Adrop", "広告動画再生開始");
            }

            @Override
            public void onAdVideoEnd(AdropNativeAd ad) {
                Log.d("Adrop", "広告動画再生終了");
            }
        });

        // 3. 広告ロード
        nativeAd.load();
    }

    private void populateNativeAdView(AdropNativeAd ad) {
        // プロフィールロゴ設定
        ImageView profileLogoView = findViewById(R.id.ad_profile_logo);
        Glide.with(this).load(ad.getProfile().getDisplayLogo()).into(profileLogoView);
        nativeAdView.setProfileLogoView(profileLogoView, null);

        // プロフィール名設定
        TextView profileNameView = findViewById(R.id.ad_profile_name);
        profileNameView.setText(ad.getProfile().getDisplayName());
        nativeAdView.setProfileNameView(profileNameView, null);

        // タイトル設定
        TextView headlineView = findViewById(R.id.ad_headline);
        headlineView.setText(ad.getHeadline());
        nativeAdView.setHeadLineView(headlineView, null);

        // メディア設定
        AdropMediaView mediaView = findViewById(R.id.ad_media);
        nativeAdView.setMediaView(mediaView);

        // 本文設定
        TextView bodyView = findViewById(R.id.ad_body);
        bodyView.setText(ad.getBody());
        nativeAdView.setBodyView(bodyView);

        // 広告主設定
        TextView advertiserView = findViewById(R.id.ad_advertiser);
        advertiserView.setText(ad.getProfile().getDisplayName());
        nativeAdView.setAdvertiserView(advertiserView, null);

        // CTAボタン設定
        Button ctaView = findViewById(R.id.ad_call_to_action);
        ctaView.setText(ad.getCallToAction());
        nativeAdView.setCallToActionView(ctaView);

        // 広告データバインド
        nativeAdView.setNativeAd(ad);
    }

    @Override
    protected void onDestroy() {
        // リソース解放
        if (nativeAdView != null) {
            nativeAdView.destroy();
        }
        if (nativeAd != null) {
            nativeAd.destroy();
        }
        super.onDestroy();
    }
}

高度な機能

全体クリック領域設定

広告ビュー全体領域でクリックイベントが発生するよう設定できます。
nativeAdView.isEntireClick = true
nativeAdView.setEntireClick(true);
isEntireClicktrueに設定すると広告ビュー全体がクリック可能な領域になります。個別要素のクリックリスナーは動作しません。

個別要素クリックリスナー

特定の広告要素にカスタムクリックリスナーを設定できます。
// 広告主クリック時のカスタム動作
nativeAdView.setAdvertiserView(advertiserView) {
    Log.d("Adrop", "広告主クリック")
    // カスタム動作実装
}

// プロフィールロゴクリック時のカスタム動作
nativeAdView.setProfileLogoView(profileLogoView) {
    Log.d("Adrop", "プロフィールロゴクリック")
    // カスタム動作実装
}
// 広告主クリック時のカスタム動作
nativeAdView.setAdvertiserView(advertiserView, new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("Adrop", "広告主クリック");
        // カスタム動作実装
    }
});

// プロフィールロゴクリック時のカスタム動作
nativeAdView.setProfileLogoView(profileLogoView, new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("Adrop", "プロフィールロゴクリック");
        // カスタム動作実装
    }
});

コンテキストターゲティング

特定のコンテキストに合った広告をリクエストできます。
val nativeAd = AdropNativeAd(
    context = this,
    unitId = "YOUR_UNIT_ID",
    contextId = "SPORTS_NEWS"  // コンテキストID
)
AdropNativeAd nativeAd = new AdropNativeAd(
    this,
    "YOUR_UNIT_ID",
    "SPORTS_NEWS"  // コンテキストID
);

RecyclerViewでの使用

RecyclerViewのアイテムとしてネイティブ広告を表示できます。
RecyclerView Adapter
class ContentAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    companion object {
        const val VIEW_TYPE_CONTENT = 0
        const val VIEW_TYPE_AD = 1
        const val AD_INTERVAL = 5  // 5アイテムごとに広告表示
    }

    private val items = mutableListOf<Any>()
    private val nativeAds = mutableMapOf<Int, AdropNativeAd>()

    override fun getItemViewType(position: Int): Int {
        return if (position % (AD_INTERVAL + 1) == AD_INTERVAL) {
            VIEW_TYPE_AD
        } else {
            VIEW_TYPE_CONTENT
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            VIEW_TYPE_AD -> {
                val view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.item_native_ad, parent, false)
                NativeAdViewHolder(view)
            }
            else -> {
                val view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.item_content, parent, false)
                ContentViewHolder(view)
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder) {
            is NativeAdViewHolder -> loadNativeAd(holder, position)
            is ContentViewHolder -> holder.bind(items[position])
        }
    }

    private fun loadNativeAd(holder: NativeAdViewHolder, position: Int) {
        // 既にロードした広告があれば再利用
        nativeAds[position]?.let { ad ->
            if (ad.isLoaded) {
                holder.bind(ad)
                return
            }
        }

        // 新しい広告をロード
        val nativeAd = AdropNativeAd(holder.itemView.context, "YOUR_UNIT_ID")
        nativeAd.listener = object : AdropNativeAdListener {
            override fun onAdReceived(ad: AdropNativeAd) {
                nativeAds[position] = ad
                holder.bind(ad)
            }

            override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {
                Log.e("Adrop", "広告ロード失敗:$errorCode")
            }

            override fun onAdClicked(ad: AdropNativeAd) {
                Log.d("Adrop", "広告クリック")
            }
        }
        nativeAd.load()
    }

    class NativeAdViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val nativeAdView: AdropNativeAdView = itemView.findViewById(R.id.native_ad_view)

        fun bind(ad: AdropNativeAd) {
            val profileLogo = itemView.findViewById<ImageView>(R.id.ad_profile_logo)
            Glide.with(itemView.context).load(ad.profile.displayLogo).into(profileLogo)
            nativeAdView.setProfileLogoView(profileLogo)

            val profileName = itemView.findViewById<TextView>(R.id.ad_profile_name)
            profileName.text = ad.profile.displayName
            nativeAdView.setProfileNameView(profileName)

            val headline = itemView.findViewById<TextView>(R.id.ad_headline)
            headline.text = ad.headline
            nativeAdView.setHeadLineView(headline)

            val media = itemView.findViewById<AdropMediaView>(R.id.ad_media)
            nativeAdView.setMediaView(media)

            val body = itemView.findViewById<TextView>(R.id.ad_body)
            body.text = ad.body
            nativeAdView.setBodyView(body)

            val advertiser = itemView.findViewById<TextView>(R.id.ad_advertiser)
            advertiser.text = ad.profile.displayName
            nativeAdView.setAdvertiserView(advertiser)

            val cta = itemView.findViewById<Button>(R.id.ad_call_to_action)
            cta.text = ad.callToAction
            nativeAdView.setCallToActionView(cta)

            nativeAdView.setNativeAd(ad)
        }
    }

    fun destroy() {
        nativeAds.values.forEach { it.destroy() }
        nativeAds.clear()
    }
}

テストユニットID

開発およびテスト時に以下のテストユニットIDを使用してください。
フォーマットテストユニットID
ネイティブ(画像)PUBLIC_TEST_UNIT_ID_NATIVE
ネイティブ動画(16:9)PUBLIC_TEST_UNIT_ID_NATIVE_VIDEO_16_9
ネイティブ動画(9:16)PUBLIC_TEST_UNIT_ID_NATIVE_VIDEO_9_16
本番リリース前に必ず実際のユニットIDに置き換えてください。

ライフサイクル管理

Activity/Fragmentでのリソース解放

ネイティブ広告はメモリリークを防ぐために使用終了後に必ず解放する必要があります。
override fun onDestroy() {
    nativeAdView.destroy()
    nativeAd.destroy()
    super.onDestroy()
}
override fun onDestroyView() {
    nativeAdView?.destroy()
    nativeAd?.destroy()
    super.onDestroyView()
}
@Override
protected void onDestroy() {
    if (nativeAdView != null) {
        nativeAdView.destroy();
    }
    if (nativeAd != null) {
        nativeAd.destroy();
    }
    super.onDestroy();
}

RecyclerViewでのリソース解放

RecyclerView Adapterで広告を使用する場合、ActivityやFragmentが終了する時にすべての広告を解放する必要があります。
override fun onDestroy() {
    adapter.destroy()
    super.onDestroy()
}

動画トラッキングとVTR

Adropはネイティブ広告の動画指標 — VTR(動画完了率)、onAdVideoStartonAdVideoEnd — を、SDKメディアコンテナ(AdropNativeAdView.setMediaView(...)でバインドされたAdropMediaView)内で動画がレンダリングされる場合にのみ収集します。 AdropNativeAd.assetプロパティは元の画像または動画ファイルのURLを返します。これはサムネイル表示や媒体社独自分析などの補助メタデータとして公開されており、再生を直接行うためのものではありません。
動画ネイティブ広告のasset URLを独自の動画プレイヤー(ExoPlayerMediaPlayerまたはサードパーティプレイヤー)に直接渡さないでください。SDKメディアコンテナを経由しないと以下の現象が発生します。
  • 該当面でVTR(動画完了率)が収集されません。
  • onAdVideoStart / onAdVideoEndコールバックが呼び出されません。
  • 該当ユニットの動画パフォーマンス集計が欠落または0として報告されます。
クリック(onAdClicked)とインプレッション(onAdImpression)トラッキングはコンテナビューに接続されているため引き続き動作しますが、動画関連シグナルは失われます。

推奨パターン

動画ネイティブ広告には必ずSDKメディアコンテナをバインドしてください。
val mediaView = findViewById<AdropMediaView>(R.id.ad_media)
nativeAdView.setMediaView(mediaView)   // 動画トラッキングのため必須
nativeAdView.setNativeAd(ad)
AdropMediaView mediaView = findViewById(R.id.ad_media);
nativeAdView.setMediaView(mediaView);   // 動画トラッキングのため必須
nativeAdView.setNativeAd(ad);
特定の面がどうしても独自プレイヤーを使う必要があり、VTRが計測されないことを許容する場合、広告をAdropNativeAdViewにバインドしたままにすることで、クリックとインプレッションのアトリビューションは引き続き確保できます。ただしその面を社内レポートで非VTRインベントリとして分類し、SDKが計測した動画パフォーマンスと混在させないでください。

ベストプラクティス

1. 必要な要素のみ表示

すべての広告要素を表示する必要はありません。アプリのデザインに合わせて必要な要素のみ選択的に使用してください。
// 最小構成例(メディア + CTAのみ使用)
nativeAdView.setMediaView(mediaView)
nativeAdView.setCallToActionView(ctaView)
nativeAdView.setNativeAd(ad)

2. 画像ロードライブラリの使用

アイコン、カバー、プロフィール画像を表示する際はGlide、Coilなどの画像ロードライブラリを使用してください。
// Glide使用例
Glide.with(context)
    .load(ad.icon)
    .placeholder(R.drawable.placeholder)
    .error(R.drawable.error)
    .into(iconView)

3. 広告ビューの再利用

RecyclerViewで広告を表示する際は広告インスタンスをキャッシュして再利用してください。

4. 適切な広告配置

ユーザー体験を損なわない範囲で自然に広告を配置してください。
  • コンテンツフィード:5〜10アイテムごとに1つの広告
  • 詳細画面:コンテンツ下部に配置
  • スクロールビュー:自然なコンテンツフローに合わせて配置

5. エラー処理

広告ロード失敗に備えて適切なフォールバック処理を実装してください。
override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {
    when (errorCode) {
        AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
            // 広告なし - 広告領域を非表示
            nativeAdView.visibility = View.GONE
        }
        AdropErrorCode.ERROR_CODE_NETWORK -> {
            // ネットワークエラー - リトライロジック
            Handler(Looper.getMainLooper()).postDelayed({
                nativeAd.load()
            }, 3000)
        }
        else -> {
            Log.e("Adrop", "広告ロード失敗:$errorCode")
        }
    }
}

完全な例

import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import io.adrop.ads.model.AdropErrorCode
import io.adrop.ads.nativeAd.AdropMediaView
import io.adrop.ads.nativeAd.AdropNativeAd
import io.adrop.ads.nativeAd.AdropNativeAdListener
import io.adrop.ads.nativeAd.AdropNativeAdView

class NativeAdExampleActivity : AppCompatActivity() {

    private lateinit var nativeAd: AdropNativeAd
    private lateinit var nativeAdView: AdropNativeAdView
    private lateinit var loadingView: View
    private lateinit var errorView: View

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_native_ad_example)

        nativeAdView = findViewById(R.id.native_ad_view)
        loadingView = findViewById(R.id.loading_view)
        errorView = findViewById(R.id.error_view)

        findViewById<Button>(R.id.retry_button).setOnClickListener {
            loadNativeAd()
        }

        loadNativeAd()
    }

    private fun loadNativeAd() {
        showLoading()

        nativeAd = AdropNativeAd(
            context = this,
            unitId = "PUBLIC_TEST_UNIT_ID_NATIVE"
        )

        nativeAd.listener = object : AdropNativeAdListener {
            override fun onAdReceived(ad: AdropNativeAd) {
                Log.d("Adrop", "広告受信:unitId=${ad.unitId}, txId=${ad.txId}")
                populateNativeAdView(ad)
                showAd()
            }

            override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {
                Log.e("Adrop", "広告受信失敗:$errorCode")
                showError()
            }

            override fun onAdClicked(ad: AdropNativeAd) {
                Log.d("Adrop", "広告クリック:txId=${ad.txId}")
            }

            override fun onAdImpression(ad: AdropNativeAd) {
                Log.d("Adrop", "広告インプレッション:txId=${ad.txId}")
            }
        }

        nativeAd.load()
    }

    private fun populateNativeAdView(ad: AdropNativeAd) {
        // 全体クリック領域を有効化(オプション)
        // nativeAdView.isEntireClick = true

        // プロフィールロゴ
        val profileLogoView = findViewById<ImageView>(R.id.ad_profile_logo)
        Glide.with(this)
            .load(ad.profile.displayLogo)
            .circleCrop()
            .into(profileLogoView)
        nativeAdView.setProfileLogoView(profileLogoView)

        // プロフィール名
        val profileNameView = findViewById<TextView>(R.id.ad_profile_name)
        profileNameView.text = ad.profile.displayName
        nativeAdView.setProfileNameView(profileNameView)

        // タイトル
        val headlineView = findViewById<TextView>(R.id.ad_headline)
        headlineView.text = ad.headline
        nativeAdView.setHeadLineView(headlineView)

        // メディア(画像または動画)
        val mediaView = findViewById<AdropMediaView>(R.id.ad_media)
        nativeAdView.setMediaView(mediaView)

        // 本文
        val bodyView = findViewById<TextView>(R.id.ad_body)
        bodyView.text = ad.body
        nativeAdView.setBodyView(bodyView)

        // 広告主
        val advertiserView = findViewById<TextView>(R.id.ad_advertiser)
        advertiserView.text = ad.profile.displayName
        nativeAdView.setAdvertiserView(advertiserView) {
            Log.d("Adrop", "広告主クリック:${ad.profile.displayName}")
        }

        // CTAボタン
        val ctaView = findViewById<Button>(R.id.ad_call_to_action)
        ctaView.text = ad.callToAction
        nativeAdView.setCallToActionView(ctaView)

        // 広告データバインド
        nativeAdView.setNativeAd(ad)
    }

    private fun showLoading() {
        loadingView.visibility = View.VISIBLE
        nativeAdView.visibility = View.GONE
        errorView.visibility = View.GONE
    }

    private fun showAd() {
        loadingView.visibility = View.GONE
        nativeAdView.visibility = View.VISIBLE
        errorView.visibility = View.GONE
    }

    private fun showError() {
        loadingView.visibility = View.GONE
        nativeAdView.visibility = View.GONE
        errorView.visibility = View.VISIBLE
    }

    override fun onDestroy() {
        nativeAdView.destroy()
        nativeAd.destroy()
        super.onDestroy()
    }
}
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import io.adrop.ads.model.AdropErrorCode;
import io.adrop.ads.nativeAd.AdropMediaView;
import io.adrop.ads.nativeAd.AdropNativeAd;
import io.adrop.ads.nativeAd.AdropNativeAdListener;
import io.adrop.ads.nativeAd.AdropNativeAdView;

public class NativeAdExampleActivity extends AppCompatActivity {

    private AdropNativeAd nativeAd;
    private AdropNativeAdView nativeAdView;
    private View loadingView;
    private View errorView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_native_ad_example);

        nativeAdView = findViewById(R.id.native_ad_view);
        loadingView = findViewById(R.id.loading_view);
        errorView = findViewById(R.id.error_view);

        findViewById(R.id.retry_button).setOnClickListener(v -> loadNativeAd());

        loadNativeAd();
    }

    private void loadNativeAd() {
        showLoading();

        nativeAd = new AdropNativeAd(
            this,
            "PUBLIC_TEST_UNIT_ID_NATIVE",
            null
        );

        nativeAd.setListener(new AdropNativeAdListener() {
            @Override
            public void onAdReceived(AdropNativeAd ad) {
                Log.d("Adrop", "広告受信:unitId=" + ad.getUnitId() + ", txId=" + ad.getTxId());
                populateNativeAdView(ad);
                showAd();
            }

            @Override
            public void onAdFailedToReceive(AdropNativeAd ad, AdropErrorCode errorCode) {
                Log.e("Adrop", "広告受信失敗:" + errorCode);
                showError();
            }

            @Override
            public void onAdClicked(AdropNativeAd ad) {
                Log.d("Adrop", "広告クリック:txId=" + ad.getTxId());
            }

            @Override
            public void onAdImpression(AdropNativeAd ad) {
                Log.d("Adrop", "広告インプレッション:txId=" + ad.getTxId());
            }
        });

        nativeAd.load();
    }

    private void populateNativeAdView(AdropNativeAd ad) {
        // プロフィールロゴ
        ImageView profileLogoView = findViewById(R.id.ad_profile_logo);
        Glide.with(this)
            .load(ad.getProfile().getDisplayLogo())
            .circleCrop()
            .into(profileLogoView);
        nativeAdView.setProfileLogoView(profileLogoView, null);

        // プロフィール名
        TextView profileNameView = findViewById(R.id.ad_profile_name);
        profileNameView.setText(ad.getProfile().getDisplayName());
        nativeAdView.setProfileNameView(profileNameView, null);

        // タイトル
        TextView headlineView = findViewById(R.id.ad_headline);
        headlineView.setText(ad.getHeadline());
        nativeAdView.setHeadLineView(headlineView, null);

        // メディア
        AdropMediaView mediaView = findViewById(R.id.ad_media);
        nativeAdView.setMediaView(mediaView);

        // 本文
        TextView bodyView = findViewById(R.id.ad_body);
        bodyView.setText(ad.getBody());
        nativeAdView.setBodyView(bodyView);

        // 広告主
        TextView advertiserView = findViewById(R.id.ad_advertiser);
        advertiserView.setText(ad.getProfile().getDisplayName());
        nativeAdView.setAdvertiserView(advertiserView, v -> {
            Log.d("Adrop", "広告主クリック:" + ad.getProfile().getDisplayName());
        });

        // CTAボタン
        Button ctaView = findViewById(R.id.ad_call_to_action);
        ctaView.setText(ad.getCallToAction());
        nativeAdView.setCallToActionView(ctaView);

        // 広告データバインド
        nativeAdView.setNativeAd(ad);
    }

    private void showLoading() {
        loadingView.setVisibility(View.VISIBLE);
        nativeAdView.setVisibility(View.GONE);
        errorView.setVisibility(View.GONE);
    }

    private void showAd() {
        loadingView.setVisibility(View.GONE);
        nativeAdView.setVisibility(View.VISIBLE);
        errorView.setVisibility(View.GONE);
    }

    private void showError() {
        loadingView.setVisibility(View.GONE);
        nativeAdView.setVisibility(View.GONE);
        errorView.setVisibility(View.VISIBLE);
    }

    @Override
    protected void onDestroy() {
        if (nativeAdView != null) {
            nativeAdView.destroy();
        }
        if (nativeAd != null) {
            nativeAd.destroy();
        }
        super.onDestroy();
    }
}

一括ロード (loads)

AdropNativeAd.loads()を使用すると、1回の呼び出しで複数のネイティブ広告をまとめてリクエストできます。フィード・カルーセル・ページネーションリストへ挿入する広告プールのプリフェッチに有用です。

シグネチャ

AdropNativeAd.loads(
    context: Context,
    unitId: String,
    contextId: String? = null,
    listener: AdropNativeAdListener,
)
AdropNativeAd.loads(context, "YOUR_UNIT_ID", null, listener);

使用方法

AdropNativeAd.loads(
    context = this,
    unitId = "YOUR_UNIT_ID",
    contextId = null,
    listener = object : AdropNativeAdListener {
        // バッチ成功 — 各広告はレンダリング完了状態で渡されます。
        override fun onAdsReceived(ads: List<AdropNativeAd>) {
            ads.forEach { ad ->
                // AdropNativeAdViewへバインドするか、ライフサイクル用に保持
                bindToView(ad)
            }
        }

        // バッチ失敗
        override fun onAdsFailedToReceive(errorCode: AdropErrorCode) {
            Log.e("Adrop", "バッチロード失敗: $errorCode")
        }

        // 単体用コールバックはloads経路では呼ばれません。
        override fun onAdReceived(ad: AdropNativeAd) { /* batch path */ }
        override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {}

        // クリック/インプレッション/動画コールバックは各インスタンスで通常通り呼ばれます。
        override fun onAdClicked(ad: AdropNativeAd) {
            Log.d("Adrop", "ネイティブクリック: ${ad.creativeId}")
        }

        override fun onAdImpression(ad: AdropNativeAd) {
            Log.d("Adrop", "ネイティブインプレッション: ${ad.creativeId}")
        }
    },
)
AdropNativeAd.loads(this, "YOUR_UNIT_ID", null, new AdropNativeAdListener() {
    @Override
    public void onAdsReceived(@NotNull List<AdropNativeAd> ads) {
        for (AdropNativeAd ad : ads) {
            bindToView(ad);
        }
    }

    @Override
    public void onAdsFailedToReceive(@NotNull AdropErrorCode errorCode) {
        Log.e("Adrop", "バッチロード失敗: " + errorCode);
    }

    @Override
    public void onAdReceived(@NotNull AdropNativeAd ad) { }

    @Override
    public void onAdFailedToReceive(@NotNull AdropNativeAd ad, @NotNull AdropErrorCode errorCode) { }

    @Override
    public void onAdClicked(@NotNull AdropNativeAd ad) {
        Log.d("Adrop", "ネイティブクリック: " + ad.getCreativeId());
    }

    @Override
    public void onAdImpression(@NotNull AdropNativeAd ad) {
        Log.d("Adrop", "ネイティブインプレッション: " + ad.getCreativeId());
    }
});

リスナーコールバック

コールバック呼び出されるタイミング
onAdsReceived(ads)バッチ配信完了。すべての広告が完全にレンダリングされた状態で渡されます。
onAdsFailedToReceive(errorCode)リクエスト拒否、ネットワーク失敗、または表示可能な広告がなかった場合 (ERROR_CODE_AD_NO_FILL)。
onAdClicked / onAdImpression / onAdVideoStart / onAdVideoEnd単体load()と同様に、各広告ごとに呼ばれます。
単体onAdReceived / onAdFailedToReceiveコールバックはloads()経路では呼ばれません。バッチ結果は必ずonAdsReceived / onAdsFailedToReceiveで受け取ってください。

制約事項

  • 呼び出しあたり最大5個。 サーバーがそれ以上を返しても先頭の5個のみ配信されます。
  • バックフィルは適用されません。 ダイレクト広告が埋まらない場合、バックフィル設定に関わらずonAdsFailedToReceiveERROR_CODE_AD_NO_FILLで呼ばれます。
  • onAdsReceived内でdestroy()を呼ばないでください。 各広告をAdropNativeAdView.setNativeAd(...)でバインドするか、ライフサイクル用に保持し、親Activity.onDestroy()(または同等のタイミング)でdestroy()してください。
  • AdropBanner.loads()と異なり、ネイティブバッチはすべての広告のレンダリングが完了するまで待機してからonAdsReceivedを呼びます。配信時点で各インスタンスは完全にレンダリングされています。

バックフィル広告

バックフィル広告が有効な場合、ダイレクト広告がない時に自動的にバックフィル広告がロードされます。isBackfilledプロパティでバックフィル広告かどうかを確認できます。
nativeAd.listener = object : AdropNativeAdListener {
    override fun onAdReceived(ad: AdropNativeAd) {
        if (ad.isBackfilled) {
            println("バックフィル広告がロードされました")
        } else {
            println("ダイレクト広告がロードされました")
        }
    }

    override fun onAdFailedToReceive(ad: AdropNativeAd, errorCode: AdropErrorCode) {
        when (errorCode) {
            AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
                println("ダイレクト広告なし、バックフィル広告をリクエスト中...")
            }
            AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL -> {
                println("バックフィル広告も利用不可")
            }
            else -> {
                println("広告ロード失敗: $errorCode")
            }
        }
    }
}
nativeAd.setListener(new AdropNativeAdListener() {
    @Override
    public void onAdReceived(AdropNativeAd ad) {
        if (ad.isBackfilled()) {
            System.out.println("バックフィル広告がロードされました");
        } else {
            System.out.println("ダイレクト広告がロードされました");
        }
    }

    @Override
    public void onAdFailedToReceive(AdropNativeAd ad, AdropErrorCode errorCode) {
        if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
            System.out.println("ダイレクト広告なし、バックフィル広告をリクエスト中...");
        } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL) {
            System.out.println("バックフィル広告も利用不可");
        } else {
            System.out.println("広告ロード失敗: " + errorCode);
        }
    }
});

AdChoicesの位置調整

バックフィルネイティブ広告で、AdChoicesマークを表示するコーナーを指定できます。load()呼び出し前にAdropNativeAdインスタンスのpreferredAdChoicesPositionを設定してください。
import io.adrop.ads.nativeAd.AdropAdChoicesPosition
import io.adrop.ads.nativeAd.AdropNativeAd

val nativeAd = AdropNativeAd(this, "YOUR_UNIT_ID")
nativeAd.preferredAdChoicesPosition = AdropAdChoicesPosition.BOTTOM_RIGHT
nativeAd.load()
import io.adrop.ads.nativeAd.AdropAdChoicesPosition;
import io.adrop.ads.nativeAd.AdropNativeAd;

AdropNativeAd nativeAd = new AdropNativeAd(this, "YOUR_UNIT_ID");
nativeAd.setPreferredAdChoicesPosition(AdropAdChoicesPosition.BOTTOM_RIGHT);
nativeAd.load();
説明
AdropAdChoicesPosition.TOP_LEFT左上
AdropAdChoicesPosition.TOP_RIGHT右上(デフォルト)
AdropAdChoicesPosition.BOTTOM_LEFT左下
AdropAdChoicesPosition.BOTTOM_RIGHT右下
この設定はバックフィルネットワークに渡される希望位置のヒントで、バックフィルネイティブ広告にのみ適用されます — ダイレクト広告には影響しません。必ずload()呼び出し前に設定する必要があり、バックフィルネットワークがポリシー上別の位置に表示する場合があります。
バックフィル広告を使用するには、io.adrop:adrop-ads-backfill依存関係を追加する必要があります。はじめにを参照してください。

次のステップ

バナー広告

バナー広告を実装

インタースティシャル広告

インタースティシャル広告を実装

ターゲティング設定

ユーザー属性とコンテキストターゲティング

リファレンス

クラス、リスナー、エラーコード