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

概要

バックフィル広告は、直接広告がない場合に代替広告を自動的に表示し、収益を最大化する機能です。AdropはAdMob、Pangleなどの主要な広告ネットワークをバックフィル広告としてサポートしています。
バックフィル広告を使用するには、ネイティブプラットフォームごとに追加設定が必要です。

Android設定

1. Gradle設定

settings.gradle.kts

Pangle広告ネットワークリポジトリを追加します:
settings.gradle.kts
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://artifact.bytedance.com/repository/pangle") }
    }
}

build.gradle.kts

バックフィル広告の依存関係を追加します:
dependencies {
    implementation("io.adrop:adrop-ads:1.7.2")
    implementation("io.adrop:adrop-ads-backfill:1.7.2")
}

2. AndroidManifest.xml設定

AdMobをバックフィル広告として使用する場合、AdMob App IDをAndroidManifest.xmlに追加します:
AndroidManifest.xml
<manifest>
    <application>
        <!-- AdMob App ID -->
        <meta-data
            android:name="com.google.android.gms.ads.APPLICATION_ID"
            android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
    </application>
</manifest>
ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyyを実際のAdMob App IDに置き換える必要があります。

3. ProGuard設定

ProGuardを使用する場合、次のルールを追加します:
proguard-rules.pro
-keep class io.adrop.** { *; }
-dontwarn io.adrop.**

iOS設定

1. Podfileの変更

バックフィル広告の依存関係をPodfileに追加します:
Podfile
target 'Runner' do
  use_frameworks!
  use_modular_headers!

  # Adrop SDK
  pod 'adrop-ads'

  # バックフィル広告SDK
  pod 'adrop-ads-backfill'

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
依存関係を追加した後、次のコマンドを実行します:
cd ios && pod install --repo-update && cd ..

2. Info.plist設定

AdMobをバックフィル広告として使用する場合、AdMob App IDをInfo.plistに追加します:
Info.plist
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy</string>
ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyyを実際のAdMob App IDに置き換える必要があります。

コンソール設定

Adropコンソールでバックフィル広告を有効にします:
  1. AdControlコンソールにログイン
  2. 広告ユニットメニューに移動
  3. バックフィル広告を使用する広告ユニットを選択
  4. バックフィル設定セクションでバックフィル広告を有効化
  5. 使用するバックフィル広告ネットワークを選択 (AdMob、Pangleなど)
  6. 広告ネットワーク別の設定を入力 (例: AdMob Ad Unit ID)

Flutterでの使用

バックフィル広告の確認

広告がバックフィル広告かどうかを確認するには、isBackfilledプロパティを使用します。

ネイティブ広告

ネイティブ広告の場合、バックフィル広告かどうかによってメディアビューを異なる方法でレンダリングする必要があります。
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';
import 'package:webview_flutter/webview_flutter.dart';

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

  @override
  State<NativeAdWithBackfill> createState() => _NativeAdWithBackfillState();
}

class _NativeAdWithBackfillState extends State<NativeAdWithBackfill> {
  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) {
          debugPrint('広告受信: ${ad.isBackfilled ? "バックフィル" : "直接広告"}');

          // 直接広告の場合、WebViewにHTMLクリエイティブをロード
          if (!ad.isBackfilled && ad.properties.creative != null) {
            webViewController.loadHtmlString(ad.properties.creative!);
          }

          setState(() {
            isLoaded = true;
          });
        },
        onAdFailedToReceive: (ad, errorCode) {
          if (errorCode == AdropErrorCode.backfillNoFill) {
            debugPrint('バックフィル広告もありません');
          } else {
            debugPrint('広告ロード失敗: $errorCode');
          }
        },
      ),
    );

    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: [
            // ヘッドライン
            if (nativeAd?.properties.headline != null)
              Text(
                nativeAd!.properties.headline!,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
            const SizedBox(height: 8),

            // メディアビュー - バックフィルかどうかによって異なるレンダリング
            _buildMediaView(),

            // CTAボタン
            if (nativeAd?.properties.callToAction != null)
              Padding(
                padding: const EdgeInsets.only(top: 8),
                child: ElevatedButton(
                  onPressed: () {},
                  child: Text(nativeAd!.properties.callToAction!),
                ),
              ),
          ],
        ),
      ),
    );
  }

  Widget _buildMediaView() {
    if (nativeAd?.isBackfilled == true) {
      // バックフィル広告: 画像アセットを使用
      return Image.network(
        nativeAd?.properties.asset ?? '',
        width: double.infinity,
        height: 200,
        fit: BoxFit.cover,
        loadingBuilder: (context, child, loadingProgress) {
          if (loadingProgress == null) return child;
          return const SizedBox(
            height: 200,
            child: Center(child: CircularProgressIndicator()),
          );
        },
        errorBuilder: (context, error, stackTrace) {
          return const SizedBox(
            height: 200,
            child: Center(child: Icon(Icons.error)),
          );
        },
      );
    } else if (nativeAd?.properties.creative != null) {
      // 直接広告: WebViewでHTMLクリエイティブをレンダリング
      return SizedBox(
        width: double.infinity,
        height: 300,
        child: WebViewWidget(controller: webViewController),
      );
    } else {
      return const SizedBox.shrink();
    }
  }
}
ネイティブ広告でバックフィル広告でない場合、動画広告はWebViewを使用して直接レンダリングする必要があります。

バナー広告

バナー広告では、メタデータを通じてバックフィルかどうかを確認できます。
bannerView = AdropBannerView(
  unitId: 'YOUR_UNIT_ID',
  listener: AdropBannerListener(
    onAdReceived: (unitId, metadata) {
      final isBackfilled = metadata?['isBackfilled'] ?? false;
      if (isBackfilled == true) {
        debugPrint('バックフィル広告がロードされました');
      } else {
        debugPrint('直接広告がロードされました');
      }
    },
    onAdFailedToReceive: (unitId, errorCode) {
      if (errorCode == AdropErrorCode.backfillNoFill) {
        debugPrint('バックフィル広告もありません');
      }
    },
  ),
);

インタースティシャル/リワード/ポップアップ広告

インタースティシャル、リワード、ポップアップ広告でも同様にバックフィルかどうかを確認できます。
interstitialAd = AdropInterstitialAd(
  unitId: 'YOUR_UNIT_ID',
  listener: AdropInterstitialListener(
    onAdReceived: (ad) {
      debugPrint('広告ロード完了');
      // インタースティシャル広告の場合、別途isBackfilledプロパティはありませんが、
      // コンソールでバックフィル設定がされていれば自動的にバックフィル広告がロードされます
    },
    onAdFailedToReceive: (ad, errorCode) {
      if (errorCode == AdropErrorCode.backfillNoFill) {
        debugPrint('直接広告とバックフィル広告の両方がありません');
      }
    },
  ),
);

広告表示フロー

バックフィル広告は次の順序で表示されます:

エラーコード

バックフィル広告関連のエラーコードです。
エラーコード説明
adNoFill直接広告を受け取れません (バックフィル広告を試行)
backfillNoFillバックフィル広告も受け取れません
onAdFailedToReceive: (ad, errorCode) {
  switch (errorCode) {
    case AdropErrorCode.adNoFill:
      debugPrint('直接広告がありません。バックフィル広告を試行します。');
      break;
    case AdropErrorCode.backfillNoFill:
      debugPrint('バックフィル広告もありません。');
      break;
    default:
      debugPrint('広告ロード失敗: ${errorCode.code}');
  }
}

サポート広告形式

バックフィル広告は次の形式をサポートしています:
広告形式サポート説明
バナー (Banner)サポート固定サイズのバナー広告
ネイティブ (Native)サポートカスタマイズ可能なネイティブ広告
インタースティシャル (Interstitial)サポート全画面広告
リワード (Rewarded)サポート報酬型広告
ポップアップ (Popup)サポートポップアップ形式の広告

ベストプラクティス

バックフィル広告を有効化

すべての広告ユニットでバックフィル広告を有効化し、広告表示率と収益を最大化してください。

適切なタイムアウト設定

直接広告とバックフィル広告の適切なタイムアウトを設定し、ユーザーエクスペリエンスを向上させてください。

バックフィル広告の分析

isBackfilledプロパティを使用して、直接広告とバックフィル広告の比率を追跡し分析してください。

ネイティブ広告メディアの処理

ネイティブ広告では、バックフィルかどうかによってImage.networkまたはWebViewを適切に使用してください。

注意事項

  • Android: バックフィル広告を使用するには、必ずio.adrop:adrop-ads-backfill:1.7.2の依存関係を追加する必要があります。
  • iOS: バックフィル広告を使用するには、必ずpod 'adrop-ads-backfill'をPodfileに追加する必要があります。
  • AdMobを使用する場合、各プラットフォームのマニフェストファイルにAdMob App IDを必ず追加する必要があります。
  • ネイティブ広告でバックフィル広告でない場合、WebViewでメディアをレンダリングする必要があります。
  • バックフィル広告ネットワークのポリシーを遵守する必要があります。

次のステップ