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

概要

ネイティブ広告は、アプリのコンテンツと自然に調和するようにカスタマイズできる広告です。AdropNativeAdAdropNativeAdViewを使用して、アプリのUIに合わせて広告を構成できます。

主な機能

  • アプリデザインに合わせたカスタムレイアウト構成が可能
  • ヘッドライン、本文、CTAボタン、プロフィールなど様々な要素を提供
  • 画像およびHTMLクリエイティブをサポート
  • カスタムクリック処理をサポート
  • バックフィル広告をサポート
開発環境ではテストユニットIDを使用してください: PUBLIC_TEST_UNIT_ID_NATIVE

AdropNativeAd

コンストラクタ

AdropNativeAd({
  required String unitId,
  bool useCustomClick = false,
  AdropNativeListener? listener,
})
パラメータ
パラメータタイプ必須説明
unitIdStringYアドコントロールコンソールで作成したユニットID
useCustomClickboolNカスタムクリック処理を使用するかどうか(デフォルト: false
listenerAdropNativeListenerN広告イベントリスナー

プロパティ

プロパティタイプ説明
isLoadedbool広告のロード完了状態
unitIdString広告ユニットID
creativeIdStringクリエイティブID
txIdStringトランザクションID
campaignIdStringキャンペーンID
destinationURLString遷移先URL
propertiesAdropNativePropertiesネイティブ広告プロパティ
creativeSizeCreativeSizeクリエイティブサイズ
isBackfilledboolバックフィル広告かどうか

メソッド

メソッド戻り値タイプ説明
load()Future<void>広告をロードします

AdropNativeAdView

ネイティブ広告を画面に表示するウィジェットです。

コンストラクタ

AdropNativeAdView({
  required AdropNativeAd? ad,
  required Widget child,
})
パラメータ
パラメータタイプ必須説明
adAdropNativeAd?Yロードされたネイティブ広告オブジェクト
childWidgetY広告コンテンツを表示する子ウィジェット

AdropNativeProperties

ネイティブ広告のコンテンツプロパティです。

プロパティ

プロパティタイプ説明
headlineString?広告タイトル
bodyString?広告本文
creativeString?HTMLクリエイティブコンテンツ
assetString?画像アセットURL
destinationURLString?クリック時の遷移先URL
callToActionString?CTAボタンテキスト
profileAdropNativeProfile?広告主プロフィール情報
extraMap<String, String>追加のカスタムフィールド
isBackfilledboolバックフィル広告かどうか

AdropNativeProfile

プロパティタイプ説明
displayNameString?広告主名
displayLogoString?広告主ロゴ画像URL

基本的な使用方法

import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class NativeAdExample extends StatefulWidget {
  const NativeAdExample({super.key});

  @override
  State<NativeAdExample> createState() => _NativeAdExampleState();
}

class _NativeAdExampleState extends State<NativeAdExample> {
  bool isLoaded = false;
  AdropNativeAd? nativeAd;

  @override
  void initState() {
    super.initState();
    _createNativeAd();
  }

  void _createNativeAd() {
    nativeAd = AdropNativeAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropNativeListener(
        onAdReceived: (ad) {
          debugPrint('ネイティブ広告受信成功: ${ad.creativeId}');
          setState(() {
            isLoaded = true;
          });
        },
        onAdClicked: (ad) {
          debugPrint('ネイティブ広告クリック: ${ad.creativeId}');
        },
        onAdImpression: (ad) {
          debugPrint('ネイティブ広告表示: ${ad.creativeId}');
        },
        onAdFailedToReceive: (ad, errorCode) {
          debugPrint('ネイティブ広告受信失敗: $errorCode');
          setState(() {
            isLoaded = false;
          });
        },
      ),
    );

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ネイティブ広告サンプル')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            // メインコンテンツ
            const Padding(
              padding: EdgeInsets.all(16),
              child: Text('メインコンテンツ'),
            ),
            // ネイティブ広告
            if (isLoaded) _buildNativeAdView(),
          ],
        ),
      ),
    );
  }

  Widget _buildNativeAdView() {
    return AdropNativeAdView(
      ad: nativeAd,
      child: Container(
        padding: const EdgeInsets.all(16),
        margin: const EdgeInsets.all(16),
        decoration: BoxDecoration(
          border: Border.all(color: Colors.grey),
          borderRadius: BorderRadius.circular(8),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 広告主プロフィール
            if (nativeAd?.properties.profile != null)
              Row(
                children: [
                  if (nativeAd?.properties.profile?.displayLogo != null)
                    Image.network(
                      nativeAd!.properties.profile!.displayLogo!,
                      width: 24,
                      height: 24,
                    ),
                  const SizedBox(width: 8),
                  Text(nativeAd?.properties.profile?.displayName ?? ''),
                ],
              ),
            const SizedBox(height: 8),
            // ヘッドライン
            if (nativeAd?.properties.headline != null)
              Text(
                nativeAd!.properties.headline!,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
            const SizedBox(height: 4),
            // 本文
            if (nativeAd?.properties.body != null)
              Text(nativeAd!.properties.body!),
            const SizedBox(height: 8),
            // 画像アセット
            if (nativeAd?.properties.asset != null)
              Image.network(
                nativeAd!.properties.asset!,
                width: double.infinity,
                fit: BoxFit.cover,
              ),
            const SizedBox(height: 8),
            // CTAボタン
            if (nativeAd?.properties.callToAction != null)
              ElevatedButton(
                onPressed: () {},
                child: Text(nativeAd!.properties.callToAction!),
              ),
          ],
        ),
      ),
    );
  }
}

AdropNativeListener

ネイティブ広告イベントを処理するリスナーです。

コールバック関数

AdropNativeListener(
  onAdReceived: (AdropNativeAd ad) {
    // 広告受信成功
  },
  onAdClicked: (AdropNativeAd ad) {
    // 広告クリック
  },
  onAdImpression: (AdropNativeAd ad) {
    // 広告表示
  },
  onAdFailedToReceive: (AdropNativeAd ad, AdropErrorCode errorCode) {
    // 広告受信失敗
  },
)

コールバックの説明

コールバック説明
onAdReceived広告受信成功時に呼び出される
onAdClicked広告クリック時に呼び出される
onAdImpression広告表示時に呼び出される
onAdFailedToReceive広告受信失敗時に呼び出される

カスタムクリック処理

動画クリエイティブやカスタムクリック動作が必要な場合はuseCustomClickを使用します。
nativeAd = AdropNativeAd(
  unitId: 'YOUR_UNIT_ID',
  useCustomClick: true, // カスタムクリックを有効化
  listener: AdropNativeListener(
    onAdReceived: (ad) {
      setState(() {
        isLoaded = true;
      });
    },
    onAdClicked: (ad) {
      // カスタムクリック動作を処理
      debugPrint('広告クリック: ${ad.destinationURL}');
    },
  ),
);
useCustomClicktrueの場合、子ウィジェットのクリックイベントが広告クリックとして処理されます。

HTMLクリエイティブの表示

ネイティブ広告にHTMLクリエイティブが含まれている場合、WebViewを使用して表示できます。
import 'package:webview_flutter/webview_flutter.dart';

class NativeWithWebView extends StatefulWidget {
  const NativeWithWebView({super.key});

  @override
  State<NativeWithWebView> createState() => _NativeWithWebViewState();
}

class _NativeWithWebViewState extends State<NativeWithWebView> {
  bool isLoaded = false;
  AdropNativeAd? nativeAd;
  late final WebViewController webViewController;

  @override
  void initState() {
    super.initState();

    // WebViewコントローラーの初期化
    webViewController = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted);

    _createNativeAd();
  }

  void _createNativeAd() {
    nativeAd = AdropNativeAd(
      unitId: 'YOUR_UNIT_ID',
      useCustomClick: true,
      listener: AdropNativeListener(
        onAdReceived: (ad) {
          // HTMLクリエイティブをロード
          if (ad.properties.creative != null) {
            webViewController.loadHtmlString(ad.properties.creative!);
          }
          setState(() {
            isLoaded = true;
          });
        },
      ),
    );

    nativeAd?.load();
  }

  @override
  Widget build(BuildContext context) {
    if (!isLoaded) return const SizedBox.shrink();

    return AdropNativeAdView(
      ad: nativeAd,
      child: Container(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // プロフィール
            Row(
              children: [
                if (nativeAd?.properties.profile?.displayLogo != null)
                  Image.network(
                    nativeAd!.properties.profile!.displayLogo!,
                    width: 24,
                    height: 24,
                  ),
                const SizedBox(width: 8),
                Text(nativeAd?.properties.profile?.displayName ?? ''),
              ],
            ),
            const SizedBox(height: 8),
            // ヘッドライン
            if (nativeAd?.properties.headline != null)
              Text(
                nativeAd!.properties.headline!,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
            const SizedBox(height: 8),
            // HTMLクリエイティブ
            SizedBox(
              width: MediaQuery.of(context).size.width,
              height: 300,
              child: WebViewWidget(controller: webViewController),
            ),
            // CTAボタン
            if (nativeAd?.properties.callToAction != null)
              Padding(
                padding: const EdgeInsets.only(top: 8),
                child: ElevatedButton(
                  onPressed: () {},
                  child: Text(nativeAd!.properties.callToAction!),
                ),
              ),
          ],
        ),
      ),
    );
  }
}
HTMLクリエイティブを使用するには、webview_flutterパッケージを追加する必要があります。
flutter pub add webview_flutter

バックフィル広告の処理

ネイティブ広告がバックフィル広告の場合、isBackfilledプロパティで確認して処理できます。
Widget _buildCreativeView() {
  if (nativeAd?.isBackfilled == true) {
    // バックフィル広告: 画像アセットを使用
    return Image.network(
      nativeAd?.properties.asset ?? '',
      width: double.infinity,
      fit: BoxFit.cover,
      loadingBuilder: (context, child, loadingProgress) {
        if (loadingProgress == null) return child;
        return const Center(child: CircularProgressIndicator());
      },
      errorBuilder: (context, error, stackTrace) {
        return const Icon(Icons.error);
      },
    );
  } else if (nativeAd?.properties.creative != null) {
    // 通常広告: HTMLクリエイティブを使用
    return SizedBox(
      width: double.infinity,
      height: 300,
      child: WebViewWidget(controller: webViewController),
    );
  } else {
    return const SizedBox.shrink();
  }
}

追加フィールドの使用

媒体社が定義した追加フィールドはextraマップからアクセスできます。
onAdReceived: (ad) {
  // 追加フィールドにアクセス
  final customField = ad.properties.extra['customFieldKey'];
  if (customField != null) {
    debugPrint('カスタムフィールド: $customField');
  }

  setState(() {
    isLoaded = true;
  });
}

エラー処理

class _NativeAdState extends State<NativeAdWidget> {
  bool isLoaded = false;
  AdropErrorCode? errorCode;
  AdropNativeAd? nativeAd;

  @override
  void initState() {
    super.initState();

    nativeAd = AdropNativeAd(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropNativeListener(
        onAdReceived: (ad) {
          setState(() {
            isLoaded = true;
            errorCode = null;
          });
        },
        onAdFailedToReceive: (ad, error) {
          setState(() {
            isLoaded = false;
            errorCode = error;
          });
        },
      ),
    );

    nativeAd?.load();
  }

  @override
  Widget build(BuildContext context) {
    if (isLoaded) {
      return _buildNativeAdView();
    } else if (errorCode != null) {
      return Text('広告ロード失敗: ${errorCode?.code}');
    } else {
      return const SizedBox.shrink();
    }
  }

  Widget _buildNativeAdView() {
    // ネイティブ広告UIの構成
    return AdropNativeAdView(
      ad: nativeAd,
      child: Container(
        // ...
      ),
    );
  }
}

ベストプラクティス

1. 広告の再生成

新しい広告をロードするには、新しいAdropNativeAdインスタンスを生成します。
void resetAd() {
  setState(() {
    isLoaded = false;
  });

  nativeAd = AdropNativeAd(
    unitId: 'YOUR_UNIT_ID',
    listener: AdropNativeListener(
      onAdReceived: (ad) {
        setState(() {
          isLoaded = true;
        });
      },
    ),
  );

  nativeAd?.load();
}

2. 条件付きレンダリング

広告がロードされるまで適切なプレースホルダーを表示します。
Widget buildNativeAd() {
  if (isLoaded && nativeAd != null) {
    return _buildNativeAdView();
  } else if (isLoading) {
    return const SizedBox(
      height: 200,
      child: Center(child: CircularProgressIndicator()),
    );
  } else {
    return const SizedBox.shrink();
  }
}

3. レスポンシブレイアウト

様々な画面サイズに対応できるようにレイアウトを構成します。
Widget _buildNativeAdView() {
  return AdropNativeAdView(
    ad: nativeAd,
    child: LayoutBuilder(
      builder: (context, constraints) {
        return Container(
          width: constraints.maxWidth,
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 広告コンテンツ
            ],
          ),
        );
      },
    ),
  );
}

4. 広告プロパティのnullチェック

ネイティブ広告プロパティはnullの可能性があるため、常に確認します。
Widget _buildHeadline() {
  final headline = nativeAd?.properties.headline;
  if (headline == null || headline.isEmpty) {
    return const SizedBox.shrink();
  }
  return Text(
    headline,
    style: const TextStyle(
      fontSize: 18,
      fontWeight: FontWeight.bold,
    ),
  );
}

次のステップ