> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adrop.io/llms.txt
> Use this file to discover all available pages before exploring further.

# バナー広告

> Flutterアプリでバナー広告を実装する方法をご案内します。

## 概要

バナー広告は画面の一部領域に表示される長方形の広告です。`AdropBannerView`ウィジェットを使用して簡単に実装できます。

### 主な特徴

* 画面上部、下部、または中央に固定配置可能
* 画像および動画広告をサポート
* コールバックによる広告イベント処理
* 広告メタデータを提供（クリエイティブID、キャンペーンIDなど）

<Note>
  開発環境ではテストユニットIDを使用してください：`PUBLIC_TEST_UNIT_ID_320_100`
</Note>

***

## AdropBannerView

### コンストラクタ

```dart theme={null}
AdropBannerView({
  required String unitId,
  AdropBannerListener? listener,
})
```

**パラメータ**

| パラメータ      | タイプ                   | 必須 | 説明                         |
| ---------- | --------------------- | -- | -------------------------- |
| `unitId`   | `String`              | Y  | Ad Controlコンソールで作成したユニットID |
| `listener` | `AdropBannerListener` | N  | 広告イベントリスナー                 |

### プロパティ

| プロパティ          | タイプ             | 説明           |
| -------------- | --------------- | ------------ |
| `creativeSize` | `CreativeSize?` | 広告クリエイティブサイズ |
| `adSize`       | `Size?`         | バナービューのサイズ設定 |

### メソッド

| メソッド        | 戻り値の型          | 説明         |
| ----------- | -------------- | ---------- |
| `load()`    | `Future<void>` | 広告をロードします  |
| `dispose()` | `Future<void>` | リソースを解放します |

***

## 基本的な使い方

```dart theme={null}
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

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

  @override
  State<BannerExample> createState() => _BannerExampleState();
}

class _BannerExampleState extends State<BannerExample> {
  bool isLoaded = false;
  late AdropBannerView bannerView;

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

    bannerView = AdropBannerView(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          debugPrint('バナー広告受信成功: $unitId');
          setState(() {
            isLoaded = true;
          });
        },
        onAdClicked: (unitId, metadata) {
          debugPrint('バナー広告クリック: $unitId');
        },
        onAdImpression: (unitId, metadata) {
          debugPrint('バナー広告表示: $unitId');
        },
        onAdFailedToReceive: (unitId, errorCode) {
          debugPrint('バナー広告受信失敗: $unitId, $errorCode');
          setState(() {
            isLoaded = false;
          });
        },
      ),
    );

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

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('バナー広告の例')),
      body: Column(
        children: [
          // メインコンテンツ
          Expanded(
            child: Center(
              child: const Text('メインコンテンツ'),
            ),
          ),
          // バナー広告
          if (isLoaded)
            SizedBox(
              width: MediaQuery.of(context).size.width,
              height: 80,
              child: bannerView,
            ),
        ],
      ),
    );
  }
}
```

***

## AdropBannerListener

バナー広告イベントを処理するリスナーです。

### コールバック関数

```dart theme={null}
AdropBannerListener(
  onAdReceived: (String unitId, Map<String, dynamic>? metadata) {
    // 広告受信成功
  },
  onAdClicked: (String unitId, Map<String, dynamic>? metadata) {
    // 広告クリック
  },
  onAdImpression: (String unitId, Map<String, dynamic>? metadata) {
    // 広告表示
  },
  onAdFailedToReceive: (String unitId, AdropErrorCode errorCode) {
    // 広告受信失敗
  },
  onAdVideoStart: (String unitId) {
    // 動画広告の再生開始
  },
  onAdVideoEnd: (String unitId) {
    // 動画広告の再生終了
  },
)
```

### コールバックの説明

| コールバック                | 説明              |
| --------------------- | --------------- |
| `onAdReceived`        | 広告受信成功時に呼び出し    |
| `onAdClicked`         | 広告クリック時に呼び出し    |
| `onAdImpression`      | 広告表示時に呼び出し      |
| `onAdFailedToReceive` | 広告受信失敗時に呼び出し    |
| `onAdVideoStart`      | 動画広告の再生開始時に呼び出し |
| `onAdVideoEnd`        | 動画広告の再生終了時に呼び出し |

### メタデータ

`onAdReceived`、`onAdClicked`、`onAdImpression`コールバックでメタデータを受け取ることができます。

```dart theme={null}
onAdReceived: (unitId, metadata) {
  debugPrint('クリエイティブID: ${metadata?['creativeId']}');
  debugPrint('トランザクションID: ${metadata?['txId']}');
  debugPrint('キャンペーンID: ${metadata?['campaignId']}');
  debugPrint('遷移先URL: ${metadata?['destinationURL']}');
  debugPrint('ブラウザターゲット: ${metadata?['browserTarget']}');
}
```

| フィールド            | タイプ      | 説明                               |
| ---------------- | -------- | -------------------------------- |
| `creativeId`     | `String` | クリエイティブID                        |
| `txId`           | `String` | トランザクションID                       |
| `campaignId`     | `String` | キャンペーンID                         |
| `destinationURL` | `String` | 遷移先URL                           |
| `browserTarget`  | `int?`   | ブラウザターゲット（0: 外部ブラウザ、1: アプリ内ブラウザ） |

<Note>
  クリエイティブサイズはメタデータではなく、`bannerView.creativeSize?.width`および`bannerView.creativeSize?.height`からアクセスします。
</Note>

***

## 広告サイズ

バナー広告はユニットに設定したサイズに合わせてコンテナサイズを指定する必要があります。

### 一般的なバナーサイズ

| サイズ       | テストユニットID                     | 用途    |
| --------- | ----------------------------- | ----- |
| 320 x 50  | `PUBLIC_TEST_UNIT_ID_320_50`  | 小型バナー |
| 320 x 100 | `PUBLIC_TEST_UNIT_ID_320_100` | 中型バナー |

### 固定サイズの使用

```dart theme={null}
SizedBox(
  width: 320,
  height: 100,
  child: bannerView,
)
```

### 画面幅に合わせる

```dart theme={null}
SizedBox(
  width: MediaQuery.of(context).size.width,
  height: 80,
  child: bannerView,
)
```

### サイズ設定

`adSize`プロパティを使用してバナービューのサイズを明示的に設定できます。

```dart theme={null}
@override
void initState() {
  super.initState();

  bannerView = AdropBannerView(
    unitId: 'YOUR_UNIT_ID',
    listener: AdropBannerListener(
      onAdReceived: (unitId, metadata) {
        setState(() {
          isLoaded = true;
        });
      },
    ),
  );

  // コンテキストが準備された後にサイズを設定
  WidgetsBinding.instance.addPostFrameCallback((_) {
    bannerView.adSize = Size(
      MediaQuery.of(context).size.width,
      80,
    );
  });
}
```

***

## エラー処理

広告ロード失敗時に適切なエラー処理を実装してください。

```dart theme={null}
class _BannerExampleState extends State<BannerExample> {
  bool isLoaded = false;
  AdropErrorCode? errorCode;
  late AdropBannerView bannerView;

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

    bannerView = AdropBannerView(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          setState(() {
            isLoaded = true;
            errorCode = null;
          });
        },
        onAdFailedToReceive: (unitId, error) {
          setState(() {
            isLoaded = false;
            errorCode = error;
          });
        },
      ),
    );

    bannerView.load();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        if (isLoaded)
          SizedBox(
            width: MediaQuery.of(context).size.width,
            height: 80,
            child: bannerView,
          )
        else if (errorCode != null)
          Text('広告ロード失敗: ${errorCode?.code}'),
      ],
    );
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }
}
```

***

## ベストプラクティス

### 1. リソースの解放

バナービューが不要になったら必ず`dispose()`を呼び出してください。

```dart theme={null}
@override
void dispose() {
  bannerView.dispose();
  super.dispose();
}
```

### 2. 広告の更新

必要に応じて広告を更新できます。

```dart theme={null}
void refreshAd() {
  setState(() {
    isLoaded = false;
  });
  bannerView.load();
}
```

### 3. 条件付きレンダリング

広告がロードされるまでバナー領域を非表示にするか、プレースホルダーを表示してください。

```dart theme={null}
Widget buildBanner() {
  if (isLoaded) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      height: 80,
      child: bannerView,
    );
  } else if (isLoading) {
    return const SizedBox(
      height: 80,
      child: Center(child: CircularProgressIndicator()),
    );
  } else {
    return const SizedBox.shrink();
  }
}
```

### 4. 複数バナーの管理

複数のバナーを使用する場合は、それぞれの状態を管理してください。

```dart theme={null}
class _MultiBannerState extends State<MultiBanner> {
  late AdropBannerView topBanner;
  late AdropBannerView bottomBanner;
  bool isTopLoaded = false;
  bool isBottomLoaded = false;

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

    topBanner = AdropBannerView(
      unitId: 'TOP_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (_, __) => setState(() => isTopLoaded = true),
      ),
    );

    bottomBanner = AdropBannerView(
      unitId: 'BOTTOM_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (_, __) => setState(() => isBottomLoaded = true),
      ),
    );

    topBanner.load();
    bottomBanner.load();
  }

  @override
  void dispose() {
    topBanner.dispose();
    bottomBanner.dispose();
    super.dispose();
  }

  // ...
}
```

***

## 完全な例

```dart theme={null}
import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

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

  @override
  State<BannerAdPage> createState() => _BannerAdPageState();
}

class _BannerAdPageState extends State<BannerAdPage> {
  static const double bannerHeight = 80;
  bool isLoaded = false;
  bool isLoading = false;
  AdropErrorCode? errorCode;
  late AdropBannerView bannerView;

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

    bannerView = AdropBannerView(
      unitId: 'PUBLIC_TEST_UNIT_ID_320_100', // テストユニットID
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          debugPrint('広告受信成功');
          debugPrint('クリエイティブID: ${metadata?['creativeId']}');
          debugPrint('キャンペーンID: ${metadata?['campaignId']}');
          debugPrint('クリエイティブサイズ: ${bannerView.creativeSize?.width}x${bannerView.creativeSize?.height}');
          setState(() {
            isLoaded = true;
            isLoading = false;
            errorCode = null;
          });
        },
        onAdClicked: (unitId, metadata) {
          debugPrint('広告クリック: ${metadata?['destinationURL']}');
        },
        onAdImpression: (unitId, metadata) {
          debugPrint('広告表示: ${metadata?['creativeId']}');
        },
        onAdFailedToReceive: (unitId, error) {
          debugPrint('広告受信失敗: $error');
          setState(() {
            isLoaded = false;
            isLoading = false;
            errorCode = error;
          });
        },
      ),
    );

    WidgetsBinding.instance.addPostFrameCallback((_) {
      bannerView.adSize = Size(
        MediaQuery.of(context).size.width,
        bannerHeight,
      );
    });
  }

  void loadAd() {
    setState(() {
      isLoading = true;
      errorCode = null;
    });
    bannerView.load();
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('バナー広告の例'),
      ),
      body: SafeArea(
        child: Column(
          children: [
            // ロードボタン
            Padding(
              padding: const EdgeInsets.all(16),
              child: ElevatedButton(
                onPressed: isLoading ? null : loadAd,
                child: Text(isLoading ? 'ロード中...' : 'バナー広告をロード'),
              ),
            ),

            // 状態表示
            if (errorCode != null)
              Padding(
                padding: const EdgeInsets.all(16),
                child: Text(
                  'エラー: ${errorCode?.code}',
                  style: const TextStyle(color: Colors.red),
                ),
              ),

            // メインコンテンツ
            const Expanded(
              child: Center(
                child: Text('メインコンテンツ領域'),
              ),
            ),

            // バナー広告
            Container(
              width: MediaQuery.of(context).size.width,
              height: bannerHeight,
              color: Colors.grey[200],
              child: isLoaded
                  ? bannerView
                  : isLoading
                      ? const Center(child: CircularProgressIndicator())
                      : const Center(child: Text('広告領域')),
            ),
          ],
        ),
      ),
    );
  }
}
```

***

## バックフィル広告

バックフィル広告が有効な場合、ダイレクト広告がない時に自動的にバックフィル広告がロードされます。バックフィル広告のロードはSDKが自動的に処理します。`backfillNoFill`エラーコードを使用してバックフィル関連のエラーを処理できます。

```dart theme={null}
bannerView = AdropBannerView(
  unitId: 'YOUR_UNIT_ID',
  listener: AdropBannerListener(
    onAdReceived: (unitId, metadata) {
      debugPrint('広告ロード完了');
      setState(() {
        isLoaded = true;
      });
    },
    onAdFailedToReceive: (unitId, errorCode) {
      switch (errorCode) {
        case AdropErrorCode.adNoFill:
          debugPrint('ダイレクト広告なし');
          break;
        case AdropErrorCode.backfillNoFill:
          debugPrint('バックフィル広告もありません');
          // 広告領域を非表示にする
          break;
        default:
          debugPrint('広告ロード失敗: ${errorCode.code}');
      }
    },
  ),
);
```

<Note>
  バナー広告のメタデータには`creativeId`、`txId`、`campaignId`、`destinationURL`、`browserTarget`フィールドのみが含まれます。バックフィル広告はメタデータでは区別できません。`backfillNoFill`エラーコードを使用してバックフィル広告の失敗を検知できます。
</Note>

<Note>
  バックフィル広告を使用するには、ネイティブプラットフォームにバックフィル依存性を追加する必要があります。[はじめに](/ja/sdk/flutter/overview)を参照してください。
</Note>

***

## 次のステップ

<CardGroup cols={2}>
  <Card title="ネイティブ広告" href="/ja/sdk/flutter/native">
    UIに合わせてカスタマイズ可能なネイティブ広告を実装する
  </Card>

  <Card title="インタースティシャル広告" href="/ja/sdk/flutter/interstitial">
    全画面を覆うインタースティシャル広告を実装する
  </Card>

  <Card title="ポップアップ広告" href="/ja/sdk/flutter/popup">
    ポップアップ形式の広告を実装する
  </Card>

  <Card title="リファレンス" href="/ja/sdk/flutter/reference">
    タイプ、メソッド、エラーコードを参照する
  </Card>
</CardGroup>
