> ## 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.

# バナー広告

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

## 概要

バナー広告は、画面の一部領域に表示される長方形の広告です。UIKitとSwiftUIの両方で使用できます。

### 主な特徴

* 画面の上部、下部、または中央に固定配置可能
* 画像および動画広告に対応
* UIKitおよびSwiftUIの両方をサポート
* デリゲートによる広告イベント処理

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

***

## UIKit実装

UIKit環境では`AdropBanner`クラスを使用してバナー広告を実装します。

### 基本実装

```swift theme={null}
import UIKit
import AdropAds

class ViewController: UIViewController {
    private var banner: AdropBanner?

    override func viewDidLoad() {
        super.viewDidLoad()

        // 1. バナーインスタンスの生成
        banner = AdropBanner(unitId: "YOUR_UNIT_ID")

        // 2. デリゲートの設定
        banner?.delegate = self

        // 3. ビュー階層に追加
        if let bannerView = banner {
            view.addSubview(bannerView)

            // 4. Auto Layoutの設定
            bannerView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                bannerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                bannerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
                bannerView.widthAnchor.constraint(equalToConstant: 320),
                bannerView.heightAnchor.constraint(equalToConstant: 100)
            ])
        }

        // 5. 広告の読み込み
        banner?.load()
    }

    deinit {
        // 6. メモリ解放前にバナーを削除
        banner?.removeFromSuperview()
        banner = nil
    }
}

// MARK: - AdropBannerDelegate
extension ViewController: AdropBannerDelegate {
    func onAdReceived(_ banner: AdropBanner) {
        print("バナー広告受信成功")
    }

    func onAdFailedToReceive(_ banner: AdropBanner, _ errorCode: AdropErrorCode) {
        print("バナー広告受信失敗: \(errorCode)")
    }

    func onAdImpression(_ banner: AdropBanner) {
        print("バナー広告表示")
    }

    func onAdClicked(_ banner: AdropBanner) {
        print("バナー広告クリック")
    }
}
```

### AdropBannerの初期化

<ParamField body="unitId" type="String" required>
  Adropコンソールで作成したユニットID
</ParamField>

```swift theme={null}
let banner = AdropBanner(unitId: "YOUR_UNIT_ID")
```

### 広告の読み込み

バナーを画面に追加した後、`load()`メソッドを呼び出して広告をリクエストします。

```swift theme={null}
banner?.load()
```

<Warning>
  バナーが画面に表示されているタイミングで`load()`を呼び出してください。画面に表示されていない状態で読み込むと、インプレッションが正確に測定されない可能性があります。
</Warning>

### Context IDの設定

[コンテキストターゲティング](/ja/sdk/ios/targeting#コンテキストターゲティング)のためにContext IDを設定できます。

```swift theme={null}
// contextIdは読み取り専用 — 初期化時に設定
let banner = AdropBanner(unitId: "YOUR_UNIT_ID", contextId: "article_123")
```

***

## SwiftUI実装

SwiftUI環境では`AdropBannerRepresented`を使用してバナー広告を実装します。

### 基本実装

```swift theme={null}
import SwiftUI
import AdropAds

struct ContentView: View {
    @State private var represented = AdropBannerRepresented(unitId: "YOUR_UNIT_ID")

    var body: some View {
        VStack {
            Spacer()

            Text("メインコンテンツ")

            Spacer()

            // バナー広告
            represented
                .frame(width: 320, height: 100)
                .onAppear {
                    represented.banner.load()
                }
        }
    }
}
```

### デリゲート処理

デリゲートを通じて広告イベントを処理できます。

```swift theme={null}
import SwiftUI
import AdropAds

struct ContentView: View {
    @StateObject private var bannerDelegate = BannerDelegate()
    @State private var represented = AdropBannerRepresented(unitId: "YOUR_UNIT_ID")

    var body: some View {
        VStack {
            Spacer()

            if bannerDelegate.isLoaded {
                Text("広告読み込み完了")
            }

            represented
                .frame(width: 320, height: 100)
                .onAppear {
                    represented.delegate = bannerDelegate
                    represented.banner.load()
                }
        }
    }
}

// デリゲートの実装
class BannerDelegate: NSObject, ObservableObject, AdropBannerDelegate {
    @Published var isLoaded = false

    func onAdReceived(_ banner: AdropBanner) {
        print("バナー広告受信成功")
        isLoaded = true
    }

    func onAdFailedToReceive(_ banner: AdropBanner, _ errorCode: AdropErrorCode) {
        print("バナー広告受信失敗: \(errorCode)")
        isLoaded = false
    }

    func onAdImpression(_ banner: AdropBanner) {
        print("バナー広告表示")
    }

    func onAdClicked(_ banner: AdropBanner) {
        print("バナー広告クリック")
    }
}
```

### Context IDの設定

```swift theme={null}
AdropBannerRepresented(
    unitId: "YOUR_UNIT_ID",
    contextId: "article_123"
)
.frame(width: 320, height: 100)
```

***

## Objective-C実装

Objective-C環境でバナー広告を実装する方法です。

### 基本実装

```objc theme={null}
@import AdropAds;

@interface ViewController () <AdropBannerDelegate>
@property (nonatomic, strong) AdropBanner *banner;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 1. バナーインスタンスの生成
    self.banner = [[AdropBanner alloc] initWithUnitId:@"YOUR_UNIT_ID"];

    // 2. デリゲートの設定
    self.banner.delegate = self;

    // 3. ビュー階層に追加
    [self.view addSubview:self.banner];

    // 4. Auto Layoutの設定
    self.banner.translatesAutoresizingMaskIntoConstraints = NO;
    [NSLayoutConstraint activateConstraints:@[
        [self.banner.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [self.banner.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
        [self.banner.widthAnchor constraintEqualToConstant:320],
        [self.banner.heightAnchor constraintEqualToConstant:100]
    ]];

    // 5. 広告の読み込み
    [self.banner load];
}

- (void)dealloc {
    [self.banner removeFromSuperview];
    self.banner = nil;
}

#pragma mark - AdropBannerDelegate

- (void)onAdReceived:(AdropBanner *)banner {
    NSLog(@"バナー広告受信成功");
}

- (void)onAdFailedToReceive:(AdropBanner *)banner :(AdropErrorCode)errorCode {
    NSLog(@"バナー広告受信失敗: %ld", (long)errorCode);
}

- (void)onAdImpression:(AdropBanner *)banner {
    NSLog(@"バナー広告表示");
}

- (void)onAdClicked:(AdropBanner *)banner {
    NSLog(@"バナー広告クリック");
}

@end
```

### Context IDの設定

```objc theme={null}
// contextIdは読み取り専用 — 初期化時に設定
AdropBanner *banner = [[AdropBanner alloc] initWithUnitId:@"YOUR_UNIT_ID" contextId:@"article_123"];
```

***

## デリゲートメソッド

`AdropBannerDelegate`プロトコルは広告のライフサイクルイベントを処理します。

### onAdReceived (必須)

広告受信が成功したときに呼び出されます。

```swift theme={null}
func onAdReceived(_ banner: AdropBanner) {
    print("バナー広告受信成功")
    // 広告ローディングインジケータを非表示にするなどの処理
}
```

### onAdFailedToReceive (必須)

広告受信が失敗したときに呼び出されます。

```swift theme={null}
func onAdFailedToReceive(_ banner: AdropBanner, _ errorCode: AdropErrorCode) {
    print("バナー広告受信失敗: \(errorCode)")
    // エラー処理および代替コンテンツの表示
}
```

<ParamField body="errorCode" type="AdropErrorCode">
  エラータイプを示すコード。詳細は[リファレンス](/ja/sdk/ios/reference#エラーコード)を参照してください。
</ParamField>

### onAdImpression (オプション)

広告が画面に表示されたときに呼び出されます。

```swift theme={null}
func onAdImpression(_ banner: AdropBanner) {
    print("バナー広告表示")
    // インプレッション分析ロギングなどの処理
}
```

### onAdClicked (オプション)

ユーザーが広告をクリックしたときに呼び出されます。

```swift theme={null}
func onAdClicked(_ banner: AdropBanner) {
    print("バナー広告クリック")
    // クリック分析ロギングなどの処理
}
```

### onAdVideoStart (オプション)

動画広告の再生が開始されたときに呼び出されます。

```swift theme={null}
func onAdVideoStart(_ banner: AdropBanner) {
    print("バナー動画再生開始")
    // 動画開始の分析ロギングなどの処理
}
```

### onAdVideoEnd (オプション)

動画広告の再生が完了したときに呼び出されます。

```swift theme={null}
func onAdVideoEnd(_ banner: AdropBanner) {
    print("バナー動画再生完了")
    // 動画終了の分析ロギングなどの処理
}
```

***

## クロージャコールバック

デリゲートの代わりにクロージャベースのコールバックを使用できます。

```swift theme={null}
let banner = AdropBanner(unitId: "YOUR_UNIT_ID")

banner.onAdReceived = { banner in
    print("バナー広告受信成功")
}

banner.onAdFailedToReceive = { banner, errorCode in
    print("バナー広告受信失敗: \(errorCode)")
}

banner.onAdImpression = { banner in
    print("バナー広告表示")
}

banner.onAdClicked = { banner in
    print("バナー広告クリック")
}

banner.onAdVideoStart = { banner in
    print("バナー動画再生開始")
}

banner.onAdVideoEnd = { banner in
    print("バナー動画再生完了")
}
```

<Note>
  デリゲートとクロージャの両方を設定すると、両方が呼び出されます。
</Note>

***

## 広告サイズ

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

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

| サイズ       | 用途    |
| --------- | ----- |
| 320 x 50  | 小型バナー |
| 320 x 100 | 大型バナー |
| 16:9比率    | 動画バナー |

### UIKit

```swift theme={null}
bannerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    bannerView.widthAnchor.constraint(equalToConstant: 320),
    bannerView.heightAnchor.constraint(equalToConstant: 100)
])
```

### SwiftUI

```swift theme={null}
represented
    .frame(width: 320, height: 100)
    .onAppear {
        represented.banner.load()
    }
```

***

## ベストプラクティス

### 1. メモリ管理

ビューコントローラーが解放されるときにバナーも一緒に削除してください。

```swift theme={null}
deinit {
    banner?.removeFromSuperview()
    banner = nil
}
```

### 2. 画面の可視性

バナーが画面に表示されるときに広告を読み込んでください。

```swift theme={null}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    banner?.load()
}
```

### 3. 再利用

同じバナーインスタンスを再利用するには、`load()`を再度呼び出してください。

```swift theme={null}
func refreshAd() {
    banner?.load()
}
```

### 4. エラー処理

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

```swift theme={null}
func onAdFailedToReceive(_ banner: AdropBanner, _ errorCode: AdropErrorCode) {
    switch errorCode {
    case .ERROR_CODE_NETWORK:
        print("ネットワークエラー: 接続を確認してください")
    case .ERROR_CODE_AD_NO_FILL:
        print("表示可能な広告がありません")
    default:
        print("広告読み込み失敗: \(errorCode)")
    }

    // 広告領域を非表示にするか、代替コンテンツを表示
    bannerContainerView.isHidden = true

    // または自社プロモーションバナーを表示
    showPromotionBanner()
}
```

***

## テストユニットID

開発およびテスト時には以下のテストユニットIDを使用してください。

| 広告タイプ         | テストユニットID                               | サイズ       |
| ------------- | --------------------------------------- | --------- |
| バナー (320x50)  | `PUBLIC_TEST_UNIT_ID_320_50`            | 320 x 50  |
| バナー (320x100) | `PUBLIC_TEST_UNIT_ID_320_100`           | 320 x 100 |
| カルーセルバナー      | `PUBLIC_TEST_UNIT_ID_CAROUSEL`          | 可変        |
| バナービデオ (16:9) | `PUBLIC_TEST_UNIT_ID_BANNER_VIDEO_16_9` | 16:9比率    |
| バナービデオ (9:16) | `PUBLIC_TEST_UNIT_ID_BANNER_VIDEO_9_16` | 9:16比率    |

### 使用例

<CodeGroup>
  ```swift Swift theme={null}
  let banner = AdropBanner(unitId: AdropUnitId.PUBLIC_TEST_UNIT_ID_320_100)
  ```

  ```objc Objective-C theme={null}
  AdropBanner *banner = [[AdropBanner alloc] initWithUnitId:PUBLIC_TEST_UNIT_ID_320_100];
  ```
</CodeGroup>

***

## 動画再生制御

動画バナー広告の場合、`play()`と`pause()`を使用してビデオ再生を手動で制御できます。

### play()

動画の再生を再開します。ポップアップが閉じたり、アプリがバックグラウンドから復帰してバナーが再び表示されるときに呼び出してください。

<CodeGroup>
  ```swift Swift theme={null}
  banner?.play()
  ```

  ```objc Objective-C theme={null}
  [self.banner play];
  ```
</CodeGroup>

### pause()

動画の再生を一時停止します。バナーがポップアップで隠れたり、アプリがバックグラウンドに移行するときに呼び出してください。

<CodeGroup>
  ```swift Swift theme={null}
  banner?.pause()
  ```

  ```objc Objective-C theme={null}
  [self.banner pause];
  ```
</CodeGroup>

### 例：バックグラウンド/フォアグラウンドの処理

```swift theme={null}
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    banner?.play()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    banner?.pause()
}
```

<Note>
  `play()`と`pause()`は動画バナー広告にのみ影響します。画像バナーには効果がありません。
</Note>

***

## カスタムクリック処理

`useCustomClick`を使用して、広告クリック動作を直接制御できます。有効にすると、SDKはクリック時に自動的にデスティネーションURLを開かず、自分で処理できます。

### useCustomClick

```swift theme={null}
let banner = AdropBanner(unitId: "YOUR_UNIT_ID")
banner.useCustomClick = true
banner.delegate = self
banner.load()
```

`useCustomClick`が`true`の場合、広告クリック時にSDKが自動的にデスティネーションURLを開きません。`onAdClicked`デリゲートコールバックは引き続き呼び出され、`open()`メソッドを使用するか、ナビゲーションを自分で処理できます。

### open()

広告のデスティネーションURLを開きます。オプションでカスタムURLを渡すことができます。

```swift theme={null}
// 広告のデフォルトデスティネーションURLを開く
banner?.open()

// カスタムURLを開く
banner?.open("https://example.com")

// アプリ内ブラウザで開く
banner?.open(nil, useInAppBrowser: true)
```

***

## 一括ロード (loads)

`AdropBanner.loads(...)`を使用すると、1回の呼び出しで複数のバナー広告をまとめてリクエストできます。カルーセルやページネーション付きフィード、広告プールのプリフェッチなどに有用です。

### シグネチャ

<CodeGroup>
  ```swift Swift theme={null}
  AdropBanner.loads(
      unitId: String,
      contextId: String = "",
      delegate: AdropBannerDelegate
  )
  ```

  ```objc Objective-C theme={null}
  [AdropBanner loadsWithUnitId:@"YOUR_UNIT_ID"
                     contextId:@""
                      delegate:delegate];
  ```
</CodeGroup>

### 使用方法

<CodeGroup>
  ```swift Swift theme={null}
  class ViewController: UIViewController {
      private var banners: [AdropBanner] = []

      override func viewDidLoad() {
          super.viewDidLoad()
          AdropBanner.loads(unitId: "YOUR_UNIT_ID", delegate: self)
      }
  }

  extension ViewController: AdropBannerDelegate {
      // 単体用コールバック — バッチ経路では使用されません。
      func onAdReceived(_ banner: AdropBanner) { /* batch path */ }
      func onAdFailedToReceive(_ banner: AdropBanner, _ errorCode: AdropErrorCode) {}

      // バッチ成功 — 最大5個の準備済みバナーが渡されます。
      func onAdsReceived(_ banners: [AdropBanner]) {
          self.banners = banners
          banners.forEach { banner in
              // ビュー階層へ追加 (UIScrollView、UIPageViewControllerなど)
              stackView.addArrangedSubview(banner)
          }
      }

      // バッチ失敗
      func onAdsFailedToReceive(_ errorCode: AdropErrorCode) {
          print("バッチロード失敗: \(errorCode)")
      }

      // クリック/インプレッション/動画コールバックは各インスタンスで通常通り呼ばれます。
      func onAdClicked(_ banner: AdropBanner) {
          print("バナークリック")
      }

      func onAdImpression(_ banner: AdropBanner) {
          print("バナーインプレッション")
      }
  }
  ```

  ```objc Objective-C theme={null}
  @interface ViewController () <AdropBannerDelegate>
  @property (nonatomic, strong) NSArray<AdropBanner *> *banners;
  @end

  @implementation ViewController

  - (void)viewDidLoad {
      [super viewDidLoad];
      [AdropBanner loadsWithUnitId:@"YOUR_UNIT_ID" contextId:@"" delegate:self];
  }

  #pragma mark - AdropBannerDelegate

  - (void)onAdReceived:(AdropBanner *)banner { /* batch path */ }
  - (void)onAdFailedToReceive:(AdropBanner *)banner :(AdropErrorCode)errorCode {}

  - (void)onAdsReceived:(NSArray<AdropBanner *> *)banners {
      self.banners = banners;
      for (AdropBanner *banner in banners) {
          [self.stackView addArrangedSubview:banner];
      }
  }

  - (void)onAdsFailedToReceive:(AdropErrorCode)errorCode {
      NSLog(@"バッチロード失敗: %ld", (long)errorCode);
  }

  - (void)onAdClicked:(AdropBanner *)banner {
      NSLog(@"バナークリック");
  }

  - (void)onAdImpression:(AdropBanner *)banner {
      NSLog(@"バナーインプレッション");
  }

  @end
  ```
</CodeGroup>

### デリゲートメソッド

| メソッド                                                                 | 呼び出されるタイミング                                                   |
| -------------------------------------------------------------------- | ------------------------------------------------------------- |
| `onAdsReceived(_:)`                                                  | バッチ配信完了。各`AdropBanner`にはデリゲートがすでに付与され、広告データが適用されています。         |
| `onAdsFailedToReceive(_:)`                                           | リクエスト拒否、ネットワーク失敗、または表示可能な広告がなかった場合 (`ERROR_CODE_AD_NO_FILL`)。 |
| `onAdClicked` / `onAdImpression` / `onAdVideoStart` / `onAdVideoEnd` | 単体`load()`と同様に、各バナーごとに呼ばれます。                                  |

<Warning>
  単体`onAdReceived(_:)` / `onAdFailedToReceive(_:_:)`コールバックは`loads`経路では**呼ばれません**。バッチ結果は必ず`onAdsReceived(_:)` / `onAdsFailedToReceive(_:)`で受け取ってください。
</Warning>

### 定数

<ParamField body="AdropBanner.maxLoadsBatch" type="Int" default="5">
  1回の`loads(...)`呼び出しで返却される広告の最大数。
</ParamField>

### 制約事項

* **呼び出しあたり最大5個。** サーバーがそれ以上を返しても先頭の5個のみ配信されます。
* **バックフィルは適用されません。** ダイレクト広告が埋まらない場合、バックフィル設定に関わらず`onAdsFailedToReceive`が`ERROR_CODE_AD_NO_FILL`で呼ばれます。
* `onAdsReceived`は広告データが適用され次第発火し、単体`load()`と同じ動作です — ビューに追加後にクリエイティブが描画されます。
* 返却されたバナーへの強参照を保持してください(例: ビューコントローラーに保存)。ビュー階層に追加される前に解放されると黙って破棄されます。

***

## バックフィル広告

バックフィル広告が有効な場合、ダイレクト広告がない時に自動的にバックフィル広告がロードされます。`isBackfilled`プロパティでバックフィル広告かどうかを確認できます。

<CodeGroup>
  ```swift Swift theme={null}
  class ViewController: UIViewController, AdropBannerDelegate {
      private var banner: AdropBanner?

      func onAdReceived(_ banner: AdropBanner) {
          if banner.isBackfilled {
              print("バックフィル広告がロードされました")
          } else {
              print("ダイレクト広告がロードされました")
          }
      }

      func onAdFailedToReceive(_ banner: AdropBanner, _ errorCode: AdropErrorCode) {
          switch errorCode {
          case .ERROR_CODE_AD_NO_FILL:
              print("ダイレクト広告なし、バックフィル広告をリクエスト中...")
          case .ERROR_CODE_AD_BACKFILL_NO_FILL:
              print("バックフィル広告もありません")
              // 広告領域を非表示にする
              banner.isHidden = true
          default:
              print("広告ロード失敗: \(errorCode)")
          }
      }
  }
  ```

  ```objc Objective-C theme={null}
  @interface ViewController () <AdropBannerDelegate>
  @property (nonatomic, strong) AdropBanner *banner;
  @end

  @implementation ViewController

  - (void)onAdReceived:(AdropBanner *)banner {
      if (banner.isBackfilled) {
          NSLog(@"バックフィル広告がロードされました");
      } else {
          NSLog(@"ダイレクト広告がロードされました");
      }
  }

  - (void)onAdFailedToReceive:(AdropBanner *)banner :(AdropErrorCode)errorCode {
      if (errorCode == AdropErrorCodeAdNoFill) {
          NSLog(@"ダイレクト広告なし、バックフィル広告をリクエスト中...");
      } else if (errorCode == AdropErrorCodeBackfillNoFill) {
          NSLog(@"バックフィル広告もありません");
          // 広告領域を非表示にする
          banner.hidden = YES;
      } else {
          NSLog(@"広告ロード失敗: %ld", (long)errorCode);
      }
  }

  @end
  ```
</CodeGroup>

<Note>
  バックフィル広告を使用するには、`AdropAds-Backfill`依存性を追加する必要があります。[はじめに](/ja/sdk/ios/overview)を参照してください。
</Note>

***

## 次のステップ

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

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

  <Card title="ターゲティング設定" href="/ja/sdk/ios/targeting">
    ユーザー属性とコンテキストターゲティングの設定
  </Card>

  <Card title="リファレンス" href="/ja/sdk/ios/reference">
    クラス、デリゲート、エラーコードの参照
  </Card>
</CardGroup>
