# Android SDK ネイティブ広告
# はじめに
開発環境としてAndroid Studioを利用し、インストール後の各種設定は準備されていることを前提にした手順となります。
# 対応バージョン
- Android 5.0以降(API Level 21)
# 導入の流れ
- SDKをダウンロードします
↓ - プロジェクトにSDKを追加します
↓ - AndroidManifest.xmlの設定を行います
↓ - Google Play Servicesの設定を行います
↓ - 例を参考に広告表示の実装を行います
↓ - proguardの設定を行います
# 1. SDKをダウンロードする ~ 4. Google Play Servicesを設定する
Android SDK Getting Started / バナー広告からご確認ください。
# 5. 広告表示を実装する
start()を行う前に、ネイティブ広告オブジェクトをdelegateメソッドで取得するためのsetUsePartsResponse()の設定を行います。
ネイティブ広告オブジェクトが取得できた場合、Listenerメソッドの以下が呼び出されます。
:::: tabs
::: tab Kotlin
override fun onReceiveAd(nativeAd: Any)
:::
::: tab Java
public void onReceiveAd(Object nativeAd)
:::
::::
nativeAdからネイティブ広告オブジェクトが取得できます。
ネイティブ広告オブジェクトはcom.socdm.d.adgeneration.nativead.ADGNativeAdクラスです。
Object型からADGNativeAdへキャストし、クラス判定を行ってからアクセスしてください。
ADGNativeAdからネイティブ広告パーツを取得するメソッドは以下の通りです。
| 要素名 | メソッド |
|---|---|
| タイトル | ADGNativeAd.getTitle().getText() |
| メイン画像(長方形画像)URL | ADGNativeAd.getMainImage().getUrl() |
| アイコン画像(正方形画像)URL | ADGNativeAd.getIconImage().getUrl() |
| リード文 | ADGNativeAd.getDesc().getValue() |
| CTA(Call to action)のテキスト | ADGNativeAd.getCtatext().getValue() |
| 広告主 | ADGNativeAd.getSponsored().getValue() |
# 実装例
:::: tabs
::: tab Kotlin
class MainActivity : AppCompatActivity() {
private lateinit var adg: ADG
private lateinit var adContainer: FrameLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// デバッグログ出力設定。リリース時は[必ず]falseにしてください
ADGSettings.setDebugLogging(true)
adg = ADG(this).apply {
// 管理画面から払い出された広告枠ID
locationId = "48635"
// Listenerの設定
adListener = AdListener()
// リリース時は[必ず]falseにしてください
isTestModeEnabled = true
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
}
/**
* 枠サイズ
* AdFrameSize.SP:320x50, AdFrameSize.Large:320x100,
* AdFrameSize.Rect:300x250, AdFrameSize.Tablet:728x90,
* AdFrameSize.Free:自由設定
*/
adg.setAdFrameSize(ADG.AdFrameSize.FREE.setSize(300, 250))
// ネイティブ広告パーツ取得を有効
adg.setUsePartsResponse(true)
// インフォメーションアイコンのデフォルト表示
// デフォルト表示しない場合は必ずADGInformationIconViewの設置を実装してください
adg.setInformationIconViewDefault(false)
// HTMLテンプレートを使用したネイティブ広告を表示のためにはaddViewする必要があります
adContainer = findViewById<FrameLayout>(R.id.ad_container)
adContainer.addView(adg)
}
override fun onResume() {
super.onResume()
// 広告の表示
adg.start()
}
override fun onPause() {
// 広告の破棄
adg.stop()
super.onPause()
}
internal inner class AdListener : ADGListener() {
override fun onReceiveAd() {
}
override fun onReceiveAd(nativeAd: Any) {
if (nativeAd is ADGNativeAd) {
val nativeAdView = ADGNativeAdView(this@MainActivity)
nativeAdView.apply(nativeAd)
// ローテーション時に自動的にViewを削除します
adg.setAutomaticallyRemoveOnReload(mediationView)
adContainer.addView(mediationView, LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
)
}
}
override fun onFailedToReceiveAd(code: ADGConsts.ADGErrorCode) {
// ネットワーク不通/エラー多発/広告レスポンスなし 以外はリトライしてください
when (code) {
ADGConsts.ADGErrorCode.EXCEED_LIMIT,
ADGConsts.ADGErrorCode.NEED_CONNECTION,
ADGConsts.ADGErrorCode.NO_AD -> {}
else -> adg.start()
}
}
}
}
:::
::: tab Java
public class MainActivity extends AppCompatActivity {
private FrameLayout adContainer;
private ADG adg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// デバッグログ出力設定。リリース時は[必ず]falseにしてください
ADGSettings.setDebugLogging(true);
adg = new ADG(this);
// 管理画面から払い出された広告枠ID
adg.setLocationId("48635");
// Listenerの設定
adg.setAdListener(new AdListener());
// リリース時は[必ず]falseにしてください
adg.setTestModeEnabled(true);
adg.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
);
/**
* 枠サイズ
* AdFrameSize.SP:320x50, AdFrameSize.Large:320x100,
* AdFrameSize.Rect:300x250, AdFrameSize.Tablet:728x90,
* AdFrameSize.Free:自由設定
*/
adg.setAdFrameSize(ADG.AdFrameSize.FREE.setSize(300, 250));
// ネイティブ広告パーツ取得を有効
adg.setUsePartsResponse(true);
// インフォメーションアイコンのデフォルト表示
// デフォルト表示しない場合は必ずADGInformationIconViewの設置を実装してください
adg.setInformationIconViewDefault(false);
// HTMLテンプレートを使用したネイティブ広告を表示のためにはaddViewする必要があります
adContainer = (FrameLayout) findViewById(R.id.ad_container);
adContainer.addView(adg);
}
@Override
protected void onResume() {
super.onResume();
if (adg != null) {
// 広告の表示
adg.start();
}
}
@Override
protected void onPause() {
if (adg != null) {
// 広告の破棄
adg.stop();
}
super.onPause();
}
class AdListener extends ADGListener {
@Override
public void onReceiveAd() {
}
@Override
public void onReceiveAd(Object nativeAd) {
if (nativeAd instanceof ADGNativeAd) {
ADGNativeAdView nativeAdView = new ADGNativeAdView(MainActivity.this);
nativeAdView.apply((ADGNativeAd) nativeAd);
// ローテーション時に自動的にViewを削除します
adg.setAutomaticallyRemoveOnReload(nativeAdView);
adContainer.addView(nativeAdView, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
);
}
}
@Override
public void onFailedToReceiveAd(ADGConsts.ADGErrorCode code) {
// ネットワーク不通/エラー多発/広告レスポンスなし 以外はリトライしてください
switch (code) {
case EXCEED_LIMIT: // エラー多発
case NEED_CONNECTION: // ネットワーク不通
case NO_AD: // 広告レスポンスなし
break;
default:
if (adg != null) {
adg.start();
}
break;
}
}
}
}
:::
::::
ネイティブ広告デザイン例
- 作成される広告イメージ

- アプリに応じてカスタマイズください(画像ロード処理の非同期化など)。
- レイアウトファイルはサンプルを参照してください。 https://github.com/AdGeneration/ADG-Android-SDK/tree/master/Samples
:::: tabs
::: tab Kotlin
class ADGNativeAdView : RelativeLayout {
private var activity: Activity? = null
private lateinit var container: RelativeLayout
private lateinit var iconImageView: ImageView
private lateinit var titleLabel: TextView
private lateinit var descLabel: TextView
private lateinit var mediaViewContainer: FrameLayout
private lateinit var sponsoredLabel: TextView
private lateinit var CTALabel: TextView
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs, defStyleAttr, 0)
}
@TargetApi(21)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
init(context, attrs, defStyleAttr, defStyleRes)
}
private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
if (context is Activity) {
activity = context
}
val layout = LayoutInflater.from(context).inflate(R.layout.adg_nativead_view, this)
container = layout.findViewById(R.id.adg_nativead_view_container)
iconImageView = layout.findViewById(R.id.adg_nativead_view_icon)
titleLabel = layout.findViewById(R.id.adg_nativead_view_title)
titleLabel.text = ""
descLabel = layout.findViewById(R.id.adg_nativead_view_desc)
descLabel.text = ""
mediaViewContainer = layout.findViewById(R.id.adg_nativead_view_mediaview_container)
sponsoredLabel = layout.findViewById(R.id.adg_nativead_view_sponsored)
CTALabel = layout.findViewById(R.id.adg_nativead_view_cta)
CTALabel.text = ""
val borders = GradientDrawable().apply {
setColor(Color.WHITE)
cornerRadius = 10f
setStroke(3, CTALabel.textColors.defaultColor)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
CTALabel.background = borders
} else {
CTALabel.setBackgroundDrawable(borders)
}
}
fun apply(nativeAd: ADGNativeAd) {
nativeAd.iconImage?.url?.let {
DownloadImageAsync(iconImageView).execute(it)
}
nativeAd.title?.text?.let {
titleLabel.text = it
}
nativeAd.desc?.value?.let {
descLabel.text = it
}
if (nativeAd.canLoadMedia()) {
val mediaView = ADGMediaView(activity)
mediaView.setAdgNativeAd(nativeAd)
mediaViewContainer.addView(mediaView, LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
mediaView.load()
}
val infoIcon = ADGInformationIconView(context, nativeAd)
mediaViewContainer.addView(infoIcon)
sponsoredLabel.text = nativeAd.sponsored?.value ?: "sponsored"
CTALabel.text = nativeAd.ctatext?.value ?: "詳しくはこちら"
nativeAd.setClickEvent(context, container, null)
}
private inner class DownloadImageAsync(private val imageView: ImageView) : AsyncTask<String, Void, Bitmap?>() {
override fun doInBackground(vararg params: String): Bitmap? {
return try {
val imageUrl = params[0]
BitmapFactory.decodeStream(URL(imageUrl).openStream())
} catch (e: Exception) {
Log.e("Error", e.message.orEmpty())
e.printStackTrace()
null
}
}
override fun onPostExecute(bitmap: Bitmap?) {
imageView.setImageBitmap(bitmap)
}
}
}
:::
::: tab Java
public class ADGNativeAdView extends RelativeLayout {
private Activity mActivity;
private RelativeLayout mContainer;
private ImageView mIconImageView;
private TextView mTitleLabel;
private TextView mDescLabel;
private FrameLayout mMediaViewContainer;
private TextView mSponsoredLabel;
private TextView mCTALabel;
public ADGNativeAdView(Context context) {
this(context, null);
}
public ADGNativeAdView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ADGNativeAdView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
@TargetApi(21)
public ADGNativeAdView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, 0);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
if (context instanceof Activity) {
mActivity = (Activity)context;
}
View layout = LayoutInflater.from(context).inflate(R.layout.adg_nativead_view, this);
mContainer = (RelativeLayout) layout.findViewById(R.id.adg_nativead_view_container);
mIconImageView = (ImageView) layout.findViewById(R.id.adg_nativead_view_icon);
mTitleLabel = (TextView) layout.findViewById(R.id.adg_nativead_view_title);
mTitleLabel.setText("");
mDescLabel = (TextView) layout.findViewById(R.id.adg_nativead_view_desc);
mDescLabel.setText("");
mMediaViewContainer = (FrameLayout) layout.findViewById(R.id.adg_nativead_view_mediaview_container);
mSponsoredLabel = (TextView) layout.findViewById(R.id.adg_nativead_view_sponsored);
mCTALabel = (TextView) layout.findViewById(R.id.adg_nativead_view_cta);
mCTALabel.setText("");
GradientDrawable borders = new GradientDrawable();
borders.setColor(Color.WHITE);
borders.setCornerRadius(10);
borders.setStroke(3, mCTALabel.getTextColors().getDefaultColor());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mCTALabel.setBackground(borders);
} else {
mCTALabel.setBackgroundDrawable(borders);
}
}
public void apply(ADGNativeAd nativeAd) {
// アイコン画像
if (nativeAd.getIconImage() != null) {
String url = nativeAd.getIconImage().getUrl();
new DownloadImageAsync(mIconImageView).execute(url);
}
// タイトル
if (nativeAd.getTitle() != null) {
mTitleLabel.setText(nativeAd.getTitle().getText());
}
// リード文
if (nativeAd.getDesc() != null) {
String desc = nativeAd.getDesc().getValue();
mDescLabel.setText(desc);
}
// メイン画像・動画
if (nativeAd.canLoadMedia()) {
ADGMediaView mediaView = new ADGMediaView(mActivity);
mediaView.setAdgNativeAd(nativeAd);
mMediaViewContainer.addView(mediaView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mediaView.load();
}
// インフォメーションアイコン
ADGInformationIconView infoIcon = new ADGInformationIconView(getContext(), nativeAd);
mMediaViewContainer.addView(infoIcon);
// 広告主
if (nativeAd.getSponsored() != null) {
mSponsoredLabel.setText(nativeAd.getSponsored().getValue());
} else {
mSponsoredLabel.setText("sponsored");
}
// CTA
if (nativeAd.getCtatext() != null) {
mCTALabel.setText(nativeAd.getCtatext().getValue());
} else {
mCTALabel.setText("詳しくはこちら");
}
// クリックイベント
nativeAd.setClickEvent(getContext(), mContainer, null);
}
/**
* 画像をロードします(方法については任意で行ってください)
*/
private class DownloadImageAsync extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
public DownloadImageAsync(ImageView imageView) {
this.imageView = imageView;
}
@Override
protected Bitmap doInBackground(String... params) {
try {
String imageUrl = params[0];
return BitmapFactory.decodeStream(new URL(imageUrl).openStream());
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
this.imageView.setImageBitmap(bitmap);
}
}
}
:::
::::
# 注意事項
Activity#onResumeメソッドでADG#startメソッドを呼び、Activity#onPauseメソッドでADG#stopメソッドを呼んでください。- v2.26.2から
ADG#pauseメソッドは非推奨になりました。代わりにADG#stopメソッドを使用してください。 - v2.26.2から
ADG#resumeRefreshTimerメソッドは非推奨になりました。代わりにADG#startメソッドを使用してください。 - v2.26.2から
ADG#setEnableTestModeメソッドは非推奨になりました。代わりにテストモードを有効にするときはADG#setTestModeEnabledメソッドを使用してください。また、デバッグログを出力する場合はADGSettings.setDebugLoggingメソッドを使用してください。 - v2.26.2から
ADG#isEnableTestModeメソッドは非推奨になりました。代わりにADG#isTestModeEnabledメソッドを使用してください。 - v2.8.0から
ADG#delegateViewManagementは非推奨となりました。 - 代わりに
ADGNativeAd#setClickEvent(Context context, View view, ADGNativeAdOnClickListener listener)およびADG#setAutomaticallyRemoveOnReload(View view)を使用してください。 - stopを呼び出したタイミングにて、setAutomaticallyRemoveOnReloadにセットされたViewインスタンスは、親ViewからのremoveViewが呼ばれます。
- テストではタップの確認も行ってください。
- 画像のロードはアプリ側で実装する必要があります。
- ADGクラスは1つの広告枠に対して1つのインスタンスを生成してください。
- 広告枠の設定によっては各ネイティブ広告オブジェクトのパラメーターの値がnullになる場合があります。
たとえば、GunosyAdsではCTA取得できません。接続先アドネットワーク毎に違いがございますので、nullを考慮した実装をお願いいたします。画像の縦横サイズも含め、すべてがoptionalな値です。 - PR表記をつける等して広告であることを示してください。
- 画像は、アスペクト比を変えず、切れることのないようしてください。
(ImageViewのscaleTypeをFIT_CENTERに設定) - レスポンスにSponsoredがある場合はできる限り表示をしてください。(特定のアドネットワークではSponsoredの表示要望がございます)
# インフォメーションアイコン(オプトアウトリンク)について
※ 2016/12/8(v2.4.2)より必須項目となりました
v2.4.2より、ターゲティングを行っている広告の場合にはデフォルトでインフォメーションアイコン(オプトアウトリンク)が表示されるようになります(ターゲティングを行っていない広告の場合は表示されません)。
インフォメーションアイコンはタップすることで、DSP事業者が指定したオプトアウトWebサイトページへ遷移します。
オプトアウトリンクはユーザーが広告のターゲティングをオプトアウト(拒否)することにより、ユーザーに関する情報の関連付けを防ぐことを可能とし、設置することで配信できるDSP事業者が増加します。
表示される場所は、setClickEvent(Context context, View view, ADGNativeAdOnClickListener listener)で指定したViewの右上に設置されます。
デフォルトの表示位置から変更する場合は、ADG.setInformationIconViewDefault(boolean b)を設定し、ADGInformationIconViewを生成してください。
ターゲティングを行っていない広告の場合は、ADGInformationIconViewを生成してもアイコンは表示されません。
インフォメーションアイコンの表示確認は、テストID48635を使用してください。
# 動画広告の実装について(Android: v2.9.0~(adg-2.9.0.aar))
ADGMediaViewを利用することで、動画広告を配置できます。
:::: tabs
::: tab Java
// メイン画像または動画が利用できるかどうかをチェックします。
if (nativeAd.canLoadMedia()) {
// ADGMediaViewを生成します。
ADGMediaView mediaView = new ADGMediaView(mActivity);
// 必ずADGNativeAdの参照を追加してください。
mediaView.setAdgNativeAd(nativeAd);
// Viewを配置します。
mMediaViewContainer.addView(mediaView,
new LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
// メイン画像または動画のロードを開始します。
mediaView.load();
// 不要になったタイミングでdestroyを呼び、破棄処理をおこなってください。
// mediaView.destroy();
}
:::
::::
# ADGMediaView注意事項
- 動画を再生するにはコンストラクタの引数にActivityを渡してください。
- 動画と静止画が利用できる場合は、動画が優先されます。
- 動画や静止画は配信案件によるため、必ずしも配信されるわけではありません。
android:hardwareAcceleratedがfalseの場合はtrueにしてください。- とくに、複数の動画を配置する場合や、アプリ側でMediaPlayerを扱い、動画や音声を再生している場合、不要になったものから
destroyを呼びだし、適宜破棄を行う必要があります。
破棄されないままMediaPlayerの生成を繰り返すとクラッシュを引き起こす場合があります。
# テスト用ID
審査完了前に広告の掲載イメージをご確認頂く際は、以下のIDに置き換えご確認ください。
このIDをセットしたままアプリをリリースしないようご注意ください。
| テストID | 配信広告 |
|---|---|
| 48635 | テスト広告 |
# 6. proguardの設定をする
Android SDK Getting Started / バナー広告からご確認ください。