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

# リワード広告

> Androidアプリでリワード動画広告を実装する方法をご案内します。

## 概要

リワード広告は、ユーザーが動画広告を最後まで視聴するとゲーム内通貨やライフ、ヒントなどの報酬を提供する全画面動画広告です。

### 主な特徴

* 全画面を占める動画広告
* ユーザーが広告を完全に視聴した場合のみ報酬を提供
* ユーザーが自ら広告視聴を選択（例：「動画を見てライフをゲット」ボタン）
* 報酬タイプと数量を設定可能

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

***

## 実装方法

リワード広告は以下のステップで実装します：

1. **AdropRewardedAdインスタンスを作成** - ユニットIDで広告オブジェクトを作成
2. **Listenerを設定** - 広告イベント処理のためのリスナーを指定
3. **広告をロード** - `load()`メソッドで広告をリクエスト
4. **広告を表示** - `show()`メソッドで広告を表示し、報酬を処理

***

## 基本実装

### Kotlinの例

```kotlin theme={null}
import io.adrop.ads.rewardedAd.AdropRewardedAd
import io.adrop.ads.rewardedAd.AdropRewardedAdListener
import io.adrop.ads.model.AdropErrorCode

class RewardedActivity : AppCompatActivity() {
    private var rewardedAd: AdropRewardedAd? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rewarded)

        // 1. AdropRewardedAdインスタンスを作成
        rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")

        // 2. Listenerを設定
        rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
            // 必須：広告受信成功
            override fun onAdReceived(ad: AdropRewardedAd) {
                Log.d(TAG, "広告受信完了")
                // 広告視聴ボタンを有効化など
            }

            // 必須：広告受信失敗
            override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "広告受信失敗: $errorCode")
                // 広告視聴ボタンを無効のままにするなど
            }

            // オプション：広告インプレッション
            override fun onAdImpression(ad: AdropRewardedAd) {
                Log.d(TAG, "広告インプレッション")
            }

            // オプション：広告クリック
            override fun onAdClicked(ad: AdropRewardedAd) {
                Log.d(TAG, "広告クリック")
            }

            // オプション：広告画面表示直前
            override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "広告画面表示直前")
                // BGMを一時停止など
            }

            // オプション：広告画面表示完了
            override fun onAdDidPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "広告画面表示完了")
            }

            // オプション：広告画面終了直前
            override fun onAdWillDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "広告画面終了直前")
            }

            // オプション：広告画面終了完了
            override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "広告画面終了")
                // BGMを再開など

                // 次の広告を事前ロード
                rewardedAd?.load()
            }

            // オプション：広告表示失敗
            override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "広告表示失敗: $errorCode")
            }
        }

        // 3. 広告をロード
        rewardedAd?.load()

        // 広告視聴ボタンのクリック処理
        findViewById<Button>(R.id.btnShowRewardedAd).setOnClickListener {
            showRewardedAd()
        }
    }

    private fun showRewardedAd() {
        // 広告がロードされているか確認
        if (rewardedAd?.isLoaded != true) {
            Log.d(TAG, "広告がまだロードされていません")
            return
        }

        // 4. 広告を表示し報酬を処理
        rewardedAd?.show(this) { type, amount ->
            // 報酬付与処理
            Log.d(TAG, "報酬獲得 - タイプ: $type, 数量: $amount")
            grantReward(type, amount)
        }
    }

    private fun grantReward(type: Int, amount: Int) {
        // ユーザーに報酬を付与
        // 例：ゲーム内通貨の追加、ライフの回復など

        // 重要：サーバー側での検証を推奨します
        // クライアントのみでの報酬処理は不正行為の対象となる可能性があります
    }

    override fun onDestroy() {
        super.onDestroy()
        rewardedAd?.destroy()
        rewardedAd = null
    }

    companion object {
        private const val TAG = "RewardedActivity"
    }
}
```

### Javaの例

```java theme={null}
import io.adrop.ads.rewardedAd.AdropRewardedAd;
import io.adrop.ads.rewardedAd.AdropRewardedAdListener;
import io.adrop.ads.model.AdropErrorCode;

public class RewardedActivity extends AppCompatActivity {
    private static final String TAG = "RewardedActivity";
    private AdropRewardedAd rewardedAd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rewarded);

        // 1. AdropRewardedAdインスタンスを作成
        rewardedAd = new AdropRewardedAd(this, "YOUR_UNIT_ID");

        // 2. Listenerを設定
        rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
            // 必須：広告受信成功
            @Override
            public void onAdReceived(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告受信完了");
                // 広告視聴ボタンを有効化など
            }

            // 必須：広告受信失敗
            @Override
            public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                Log.d(TAG, "広告受信失敗: " + errorCode);
                // 広告視聴ボタンを無効のままにするなど
            }

            // オプション：広告インプレッション
            @Override
            public void onAdImpression(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告インプレッション");
            }

            // オプション：広告クリック
            @Override
            public void onAdClicked(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告クリック");
            }

            // オプション：広告画面表示直前
            @Override
            public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告画面表示直前");
                // BGMを一時停止など
            }

            // オプション：広告画面表示完了
            @Override
            public void onAdDidPresentFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告画面表示完了");
            }

            // オプション：広告画面終了直前
            @Override
            public void onAdWillDismissFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告画面終了直前");
            }

            // オプション：広告画面終了完了
            @Override
            public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "広告画面終了");
                // BGMを再開など

                // 次の広告を事前ロード
                rewardedAd.load();
            }

            // オプション：広告表示失敗
            @Override
            public void onAdFailedToShowFullScreen(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                Log.d(TAG, "広告表示失敗: " + errorCode);
            }
        });

        // 3. 広告をロード
        rewardedAd.load();

        // 広告視聴ボタンのクリック処理
        findViewById(R.id.btnShowRewardedAd).setOnClickListener(v -> showRewardedAd());
    }

    private void showRewardedAd() {
        // 広告がロードされているか確認
        if (!rewardedAd.isLoaded()) {
            Log.d(TAG, "広告がまだロードされていません");
            return;
        }

        // 4. 広告を表示し報酬を処理
        rewardedAd.show(this, (type, amount) -> {
            // 報酬付与処理
            Log.d(TAG, "報酬獲得 - タイプ: " + type + ", 数量: " + amount);
            grantReward(type, amount);
        });
    }

    private void grantReward(int type, int amount) {
        // ユーザーに報酬を付与
        // 例：ゲーム内通貨の追加、ライフの回復など

        // 重要：サーバー側での検証を推奨します
        // クライアントのみでの報酬処理は不正行為の対象となる可能性があります
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (rewardedAd != null) {
            rewardedAd.destroy();
            rewardedAd = null;
        }
    }
}
```

***

## AdropRewardedAdクラス

### コンストラクタ

```kotlin theme={null}
AdropRewardedAd(context: Context, unitId: String)
```

<ParamField path="context" type="Context">
  ActivityまたはApplicationのContext
</ParamField>

<ParamField path="unitId" type="String">
  Adropコンソールで発行された広告ユニットID
</ParamField>

### プロパティ

<ParamField path="unitId" type="String">
  広告ユニットID（読み取り専用）
</ParamField>

<ParamField path="isLoaded" type="Boolean">
  広告がロードされて表示可能な状態かどうか（読み取り専用）
</ParamField>

<ParamField path="creativeId" type="String">
  ロードされた広告のクリエイティブID（読み取り専用）
</ParamField>

<ParamField path="txId" type="String">
  広告トランザクションID（読み取り専用）
</ParamField>

<ParamField path="campaignId" type="String">
  広告キャンペーンID（読み取り専用）
</ParamField>

<ParamField path="isBackfilled" type="Boolean">
  バックフィル広告かどうか（読み取り専用）
</ParamField>

<ParamField path="rewardedAdListener" type="AdropRewardedAdListener?">
  広告イベントを受信するリスナー
</ParamField>

### メソッド

<ParamField path="load()" type="Unit">
  広告をリクエストします。広告ロード結果はリスナーの`onAdReceived`または`onAdFailedToReceive`で受け取ります。
</ParamField>

<ParamField path="show(activity, userDidEarnRewardHandler)" type="Unit">
  広告を表示します。

  * `activity`：広告を表示するActivity
  * `userDidEarnRewardHandler`：報酬付与コールバック `(type: Int, amount: Int) -> Unit`
</ParamField>

<ParamField path="destroy()" type="Unit">
  広告リソースを解放します。Activityの`onDestroy()`で呼び出す必要があります。
</ParamField>

***

## AdropRewardedAdListenerインターフェース

### 必須メソッド

<ParamField path="onAdReceived(ad: AdropRewardedAd)" type="void">
  広告受信に成功した時に呼び出されます。この時点から`show()`メソッドで広告を表示できます。
</ParamField>

<ParamField path="onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode)" type="void">
  広告受信に失敗した時に呼び出されます。エラーコードで失敗原因を確認できます。
</ParamField>

### オプションメソッド

<ParamField path="onAdImpression(ad: AdropRewardedAd)" type="void">
  広告がインプレッションされた時に呼び出されます。
</ParamField>

<ParamField path="onAdClicked(ad: AdropRewardedAd)" type="void">
  ユーザーが広告をクリックした時に呼び出されます。
</ParamField>

<ParamField path="onAdWillPresentFullScreen(ad: AdropRewardedAd)" type="void">
  広告画面が表示される直前に呼び出されます。BGMを一時停止するなどの処理ができます。
</ParamField>

<ParamField path="onAdDidPresentFullScreen(ad: AdropRewardedAd)" type="void">
  広告画面が完全に表示された後に呼び出されます。
</ParamField>

<ParamField path="onAdWillDismissFullScreen(ad: AdropRewardedAd)" type="void">
  広告画面が閉じる直前に呼び出されます。
</ParamField>

<ParamField path="onAdDidDismissFullScreen(ad: AdropRewardedAd)" type="void">
  広告画面が完全に閉じた後に呼び出されます。BGMを再開したり、次の広告を事前ロードできます。
</ParamField>

<ParamField path="onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode)" type="void">
  広告表示に失敗した時に呼び出されます。エラーコードで失敗原因を確認できます。
</ParamField>

***

## 報酬処理

### 報酬コールバック

`show()`メソッドの`userDidEarnRewardHandler`パラメータで報酬コールバックを渡します。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  rewardedAd?.show(this) { type, amount ->
      // type：報酬タイプ（Int）
      // amount：報酬数量（Int）
      Log.d(TAG, "報酬獲得 - タイプ: $type, 数量: $amount")
      grantReward(type, amount)
  }
  ```

  ```java Java theme={null}
  rewardedAd.show(this, (type, amount) -> {
      // type：報酬タイプ（Int）
      // amount：報酬数量（Int）
      Log.d(TAG, "報酬獲得 - タイプ: " + type + ", 数量: " + amount);
      grantReward(type, amount);
  });
  ```
</CodeGroup>

### 報酬タイプと数量

* **type**：Adropコンソールで設定した報酬タイプ（整数値）
* **amount**：Adropコンソールで設定した報酬数量（整数値）

## ベストプラクティス

### 1. 広告を事前ロード

ユーザー体験のために広告を事前にロードしておくことをお勧めします。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  class GameActivity : AppCompatActivity() {
      private var rewardedAd: AdropRewardedAd? = null

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_game)

          // 画面進入時に広告を事前ロード
          loadRewardedAd()
      }

      private fun loadRewardedAd() {
          rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")
          rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
              override fun onAdReceived(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告準備完了")
              }

              override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                  Log.d(TAG, "広告ロード失敗: $errorCode")
              }

              override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                  // 広告終了後に次の広告を事前ロード
                  loadRewardedAd()
              }
          }
          rewardedAd?.load()
      }

      private fun showRewardedAd() {
          rewardedAd?.show(this) { type, amount ->
              grantReward(type, amount)
          }
      }
  }
  ```

  ```java Java theme={null}
  public class GameActivity extends AppCompatActivity {
      private AdropRewardedAd rewardedAd;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_game);

          // 画面進入時に広告を事前ロード
          loadRewardedAd();
      }

      private void loadRewardedAd() {
          rewardedAd = new AdropRewardedAd(this, "YOUR_UNIT_ID");
          rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
              @Override
              public void onAdReceived(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告準備完了");
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.d(TAG, "広告ロード失敗: " + errorCode);
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                  // 広告終了後に次の広告を事前ロード
                  loadRewardedAd();
              }
          });
          rewardedAd.load();
      }

      private void showRewardedAd() {
          rewardedAd.show(this, (type, amount) -> {
              grantReward(type, amount);
          });
      }
  }
  ```
</CodeGroup>

### 2. 広告準備状態の確認

広告がロードされているか確認し、UIを更新します。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  class GameActivity : AppCompatActivity() {
      private var rewardedAd: AdropRewardedAd? = null
      private var isAdReady = false

      private fun updateButtonState() {
          findViewById<Button>(R.id.btnWatchAd).apply {
              isEnabled = isAdReady
              alpha = if (isAdReady) 1.0f else 0.5f
              text = if (isAdReady) "動画を見てライフをゲット" else "広告ロード中..."
          }
      }

      private val adListener = object : AdropRewardedAdListener {
          override fun onAdReceived(ad: AdropRewardedAd) {
              isAdReady = true
              updateButtonState()
          }

          override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
              isAdReady = false
              updateButtonState()
          }

          override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
              isAdReady = false
              updateButtonState()

              // 次の広告をロード
              rewardedAd?.load()
          }
      }
  }
  ```

  ```java Java theme={null}
  public class GameActivity extends AppCompatActivity {
      private AdropRewardedAd rewardedAd;
      private boolean isAdReady = false;

      private void updateButtonState() {
          Button btnWatchAd = findViewById(R.id.btnWatchAd);
          btnWatchAd.setEnabled(isAdReady);
          btnWatchAd.setAlpha(isAdReady ? 1.0f : 0.5f);
          btnWatchAd.setText(isAdReady ? "動画を見てライフをゲット" : "広告ロード中...");
      }

      private final AdropRewardedAdListener adListener = new AdropRewardedAdListener() {
          @Override
          public void onAdReceived(@NonNull AdropRewardedAd ad) {
              isAdReady = true;
              updateButtonState();
          }

          @Override
          public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
              isAdReady = false;
              updateButtonState();
          }

          @Override
          public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
              isAdReady = false;
              updateButtonState();

              // 次の広告をロード
              rewardedAd.load();
          }
      };
  }
  ```
</CodeGroup>

### 3. BGM処理

広告表示前後で適切にBGMを制御します。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  private val adListener = object : AdropRewardedAdListener {
      override fun onAdReceived(ad: AdropRewardedAd) {
          // 必須実装
      }

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          // 必須実装
      }

      override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
          // 広告表示直前にBGMを一時停止
          AudioManager.pauseBackgroundMusic()
      }

      override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
          // 広告終了後にBGMを再開
          AudioManager.resumeBackgroundMusic()
      }
  }
  ```

  ```java Java theme={null}
  private final AdropRewardedAdListener adListener = new AdropRewardedAdListener() {
      @Override
      public void onAdReceived(@NonNull AdropRewardedAd ad) {
          // 必須実装
      }

      @Override
      public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
          // 必須実装
      }

      @Override
      public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
          // 広告表示直前にBGMを一時停止
          AudioManager.pauseBackgroundMusic();
      }

      @Override
      public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
          // 広告終了後にBGMを再開
          AudioManager.resumeBackgroundMusic();
      }
  };
  ```
</CodeGroup>

### 4. エラー処理

広告ロード失敗時にリトライロジックを実装します。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  private val adListener = object : AdropRewardedAdListener {
      override fun onAdReceived(ad: AdropRewardedAd) {
          Log.d(TAG, "広告ロード成功")
      }

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          Log.d(TAG, "広告ロード失敗: $errorCode")

          // ネットワークエラーの場合リトライ
          if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
              Handler(Looper.getMainLooper()).postDelayed({
                  rewardedAd?.load()
              }, 3000)
          }
      }

      override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          Log.d(TAG, "広告表示失敗: $errorCode")

          // ユーザーに通知
          Toast.makeText(
              this@GameActivity,
              "広告を表示できません。後でもう一度お試しください。",
              Toast.LENGTH_SHORT
          ).show()
      }
  }
  ```

  ```java Java theme={null}
  private final AdropRewardedAdListener adListener = new AdropRewardedAdListener() {
      @Override
      public void onAdReceived(@NonNull AdropRewardedAd ad) {
          Log.d(TAG, "広告ロード成功");
      }

      @Override
      public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
          Log.d(TAG, "広告ロード失敗: " + errorCode);

          // ネットワークエラーの場合リトライ
          if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
              new Handler(Looper.getMainLooper()).postDelayed(() -> {
                  rewardedAd.load();
              }, 3000);
          }
      }

      @Override
      public void onAdFailedToShowFullScreen(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
          Log.d(TAG, "広告表示失敗: " + errorCode);

          // ユーザーに通知
          Toast.makeText(
              GameActivity.this,
              "広告を表示できません。後でもう一度お試しください。",
              Toast.LENGTH_SHORT
          ).show();
      }
  };
  ```
</CodeGroup>

### 5. ライフサイクル管理

Activity終了時に広告リソースを整理します。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  class GameActivity : AppCompatActivity() {
      private var rewardedAd: AdropRewardedAd? = null

      override fun onDestroy() {
          super.onDestroy()
          rewardedAd?.destroy()
          rewardedAd = null
      }
  }
  ```

  ```java Java theme={null}
  public class GameActivity extends AppCompatActivity {
      private AdropRewardedAd rewardedAd;

      @Override
      protected void onDestroy() {
          super.onDestroy();
          if (rewardedAd != null) {
              rewardedAd.destroy();
              rewardedAd = null;
          }
      }
  }
  ```
</CodeGroup>

***

## 完全な例

<CodeGroup>
  ```kotlin Kotlin theme={null}
  import android.os.Bundle
  import android.os.Handler
  import android.os.Looper
  import android.util.Log
  import android.widget.Button
  import android.widget.Toast
  import androidx.appcompat.app.AppCompatActivity
  import io.adrop.ads.rewardedAd.AdropRewardedAd
  import io.adrop.ads.rewardedAd.AdropRewardedAdListener
  import io.adrop.ads.model.AdropErrorCode

  class GameActivity : AppCompatActivity() {
      private var rewardedAd: AdropRewardedAd? = null
      private var isAdReady = false
      private lateinit var btnWatchAd: Button

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_game)

          btnWatchAd = findViewById(R.id.btnWatchAd)
          btnWatchAd.setOnClickListener {
              showRewardedAd()
          }

          // 広告を事前ロード
          loadRewardedAd()
      }

      private fun loadRewardedAd() {
          rewardedAd = AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED")
          rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
              override fun onAdReceived(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告受信完了")
                  isAdReady = true
                  updateButtonState()
              }

              override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                  Log.d(TAG, "広告受信失敗: $errorCode")
                  isAdReady = false
                  updateButtonState()

                  // ネットワークエラーの場合3秒後にリトライ
                  if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
                      Handler(Looper.getMainLooper()).postDelayed({
                          rewardedAd?.load()
                      }, 3000)
                  }
              }

              override fun onAdImpression(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告インプレッション")
              }

              override fun onAdClicked(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告クリック")
              }

              override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告画面表示直前")
                  // BGMを一時停止
                  pauseBackgroundMusic()
              }

              override fun onAdDidPresentFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告画面表示完了")
              }

              override fun onAdWillDismissFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告画面終了直前")
              }

              override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "広告画面終了")
                  isAdReady = false
                  updateButtonState()

                  // BGMを再開
                  resumeBackgroundMusic()

                  // 次の広告を事前ロード
                  loadRewardedAd()
              }

              override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                  Log.d(TAG, "広告表示失敗: $errorCode")
                  Toast.makeText(
                      this@GameActivity,
                      "広告を表示できません。後でもう一度お試しください。",
                      Toast.LENGTH_SHORT
                  ).show()
              }
          }
          rewardedAd?.load()
      }

      private fun showRewardedAd() {
          if (!isAdReady) {
              Toast.makeText(this, "広告がまだロードされていません", Toast.LENGTH_SHORT).show()
              return
          }

          rewardedAd?.show(this) { type, amount ->
              Log.d(TAG, "報酬獲得 - タイプ: $type, 数量: $amount")
              grantReward(type, amount)
          }
      }

      private fun grantReward(type: Int, amount: Int) {
          // ユーザーに報酬を付与
          runOnUiThread {
              Toast.makeText(
                  this,
                  "報酬獲得！タイプ: $type, 数量: $amount",
                  Toast.LENGTH_LONG
              ).show()
          }

          // 実際の報酬付与ロジックを実装
          // 例：ゲーム内通貨の追加、ライフの回復など
      }

      private fun updateButtonState() {
          btnWatchAd.isEnabled = isAdReady
          btnWatchAd.alpha = if (isAdReady) 1.0f else 0.5f
          btnWatchAd.text = if (isAdReady) "動画を見てライフをゲット" else "広告ロード中..."
      }

      private fun pauseBackgroundMusic() {
          // BGM一時停止ロジック
      }

      private fun resumeBackgroundMusic() {
          // BGM再開ロジック
      }

      override fun onDestroy() {
          super.onDestroy()
          rewardedAd?.destroy()
          rewardedAd = null
      }

      companion object {
          private const val TAG = "GameActivity"
      }
  }
  ```

  ```java Java theme={null}
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Looper;
  import android.util.Log;
  import android.widget.Button;
  import android.widget.Toast;
  import androidx.annotation.NonNull;
  import androidx.appcompat.app.AppCompatActivity;
  import io.adrop.ads.rewardedAd.AdropRewardedAd;
  import io.adrop.ads.rewardedAd.AdropRewardedAdListener;
  import io.adrop.ads.model.AdropErrorCode;

  public class GameActivity extends AppCompatActivity {
      private static final String TAG = "GameActivity";
      private AdropRewardedAd rewardedAd;
      private boolean isAdReady = false;
      private Button btnWatchAd;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_game);

          btnWatchAd = findViewById(R.id.btnWatchAd);
          btnWatchAd.setOnClickListener(v -> showRewardedAd());

          // 広告を事前ロード
          loadRewardedAd();
      }

      private void loadRewardedAd() {
          rewardedAd = new AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED");
          rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
              @Override
              public void onAdReceived(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告受信完了");
                  isAdReady = true;
                  updateButtonState();
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.d(TAG, "広告受信失敗: " + errorCode);
                  isAdReady = false;
                  updateButtonState();

                  // ネットワークエラーの場合3秒後にリトライ
                  if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
                      new Handler(Looper.getMainLooper()).postDelayed(() -> {
                          rewardedAd.load();
                      }, 3000);
                  }
              }

              @Override
              public void onAdImpression(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告インプレッション");
              }

              @Override
              public void onAdClicked(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告クリック");
              }

              @Override
              public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告画面表示直前");
                  // BGMを一時停止
                  pauseBackgroundMusic();
              }

              @Override
              public void onAdDidPresentFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告画面表示完了");
              }

              @Override
              public void onAdWillDismissFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告画面終了直前");
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "広告画面終了");
                  isAdReady = false;
                  updateButtonState();

                  // BGMを再開
                  resumeBackgroundMusic();

                  // 次の広告を事前ロード
                  loadRewardedAd();
              }

              @Override
              public void onAdFailedToShowFullScreen(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.d(TAG, "広告表示失敗: " + errorCode);
                  Toast.makeText(
                      GameActivity.this,
                      "広告を表示できません。後でもう一度お試しください。",
                      Toast.LENGTH_SHORT
                  ).show();
              }
          });
          rewardedAd.load();
      }

      private void showRewardedAd() {
          if (!isAdReady) {
              Toast.makeText(this, "広告がまだロードされていません", Toast.LENGTH_SHORT).show();
              return;
          }

          rewardedAd.show(this, (type, amount) -> {
              Log.d(TAG, "報酬獲得 - タイプ: " + type + ", 数量: " + amount);
              grantReward(type, amount);
          });
      }

      private void grantReward(int type, int amount) {
          // ユーザーに報酬を付与
          runOnUiThread(() -> {
              Toast.makeText(
                  this,
                  "報酬獲得！タイプ: " + type + ", 数量: " + amount,
                  Toast.LENGTH_LONG
              ).show();
          });

          // 実際の報酬付与ロジックを実装
          // 例：ゲーム内通貨の追加、ライフの回復など
      }

      private void updateButtonState() {
          btnWatchAd.setEnabled(isAdReady);
          btnWatchAd.setAlpha(isAdReady ? 1.0f : 0.5f);
          btnWatchAd.setText(isAdReady ? "動画を見てライフをゲット" : "広告ロード中...");
      }

      private void pauseBackgroundMusic() {
          // BGM一時停止ロジック
      }

      private void resumeBackgroundMusic() {
          // BGM再開ロジック
      }

      @Override
      protected void onDestroy() {
          super.onDestroy();
          if (rewardedAd != null) {
              rewardedAd.destroy();
              rewardedAd = null;
          }
      }
  }
  ```
</CodeGroup>

***

## テスト

### テストユニットID

開発中は必ずテストユニットIDを使用してください。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // 開発環境
  val rewardedAd = AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED")

  // 本番環境
  val rewardedAd = AdropRewardedAd(this, "YOUR_PRODUCTION_UNIT_ID")
  ```

  ```java Java theme={null}
  // 開発環境
  AdropRewardedAd rewardedAd = new AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED");

  // 本番環境
  AdropRewardedAd rewardedAd = new AdropRewardedAd(this, "YOUR_PRODUCTION_UNIT_ID");
  ```
</CodeGroup>

<Warning>
  実際のユニットIDでテストすると無効トラフィックとみなされ、アカウントが停止される可能性があります。必ずテストユニットIDを使用してください。
</Warning>

### 環境別ユニットID管理

ビルドタイプに応じて自動的にユニットIDを切り替える方法です。

<CodeGroup>
  ```kotlin Kotlin theme={null}
  object AdUnitID {
      val REWARDED: String
          get() = if (BuildConfig.DEBUG) {
              "PUBLIC_TEST_UNIT_ID_REWARDED"
          } else {
              "YOUR_PRODUCTION_UNIT_ID"
          }
  }

  // 使用
  val rewardedAd = AdropRewardedAd(this, AdUnitID.REWARDED)
  ```

  ```java Java theme={null}
  public class AdUnitID {
      public static String getREWARDED() {
          if (BuildConfig.DEBUG) {
              return "PUBLIC_TEST_UNIT_ID_REWARDED";
          } else {
              return "YOUR_PRODUCTION_UNIT_ID";
          }
      }
  }

  // 使用
  AdropRewardedAd rewardedAd = new AdropRewardedAd(this, AdUnitID.getREWARDED());
  ```
</CodeGroup>

***

## バックフィル広告

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

<CodeGroup>
  ```kotlin Kotlin theme={null}
  rewardedAd.rewardedAdListener = object : AdropRewardedAdListener {
      override fun onAdReceived(ad: AdropRewardedAd) {
          if (ad.isBackfilled) {
              println("バックフィル広告がロードされました")
          } else {
              println("ダイレクト広告がロードされました")
          }
      }

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          when (errorCode) {
              AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
                  println("ダイレクト広告なし、バックフィル広告をリクエスト中...")
              }
              AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL -> {
                  println("バックフィル広告も利用不可")
              }
              else -> {
                  println("広告ロード失敗: $errorCode")
              }
          }
      }
  }
  ```

  ```java Java theme={null}
  rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
      @Override
      public void onAdReceived(AdropRewardedAd ad) {
          if (ad.isBackfilled()) {
              System.out.println("バックフィル広告がロードされました");
          } else {
              System.out.println("ダイレクト広告がロードされました");
          }
      }

      @Override
      public void onAdFailedToReceive(AdropRewardedAd ad, AdropErrorCode errorCode) {
          if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
              System.out.println("ダイレクト広告なし、バックフィル広告をリクエスト中...");
          } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL) {
              System.out.println("バックフィル広告も利用不可");
          } else {
              System.out.println("広告ロード失敗: " + errorCode);
          }
      }
  });
  ```
</CodeGroup>

<Note>
  バックフィル広告を使用するには、`io.adrop:adrop-ads-backfill`依存関係を追加する必要があります。[はじめに](/ja/sdk/android/overview)を参照してください。
</Note>

***

## サーバーサイド検証

サーバーサイド検証（SSV）を使用すると、リワード付与をサーバーで安全に検証できます。`ServerSideVerificationOptions`を使用して、ユーザー識別情報とカスタムデータをサーバーコールバックに含めることができます。

<Note>
  サーバーでSSVコールバックを受信するには、コンソールの\*\*\[管理] > \[連携] > リワード広告SSV\*\*でコールバックURLを登録してください。ここで設定した`userId`と`customData`は、そのURLへ送信される暗号化ペイロードに含まれます。ペイロードの復号と設定方法は[リワード広告SSVガイド](/ja/integrations/ssv)をご参照ください。
</Note>

### SSV設定

<CodeGroup>
  ```kotlin Kotlin theme={null}
  val rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")

  // 広告ロード前にSSVオプションを設定
  rewardedAd.serverSideVerificationOptions = ServerSideVerificationOptions(
      userId = "user_12345",
      customData = "extra_info"
  )

  rewardedAd.rewardedAdListener = object : AdropRewardedAdListener {
      override fun onAdReceived(ad: AdropRewardedAd) {
          ad.show(this@MainActivity) { type, amount ->
              Log.d("Reward", "Type: $type, Amount: $amount")
          }
      }

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          // Handle error
      }
  }

  rewardedAd.load()
  ```

  ```java Java theme={null}
  AdropRewardedAd rewardedAd = new AdropRewardedAd(this, "YOUR_UNIT_ID");

  // 広告ロード前にSSVオプションを設定
  rewardedAd.setServerSideVerificationOptions(
      new ServerSideVerificationOptions("user_12345", "extra_info")
  );

  rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
      @Override
      public void onAdReceived(AdropRewardedAd ad) {
          ad.show(this, (type, amount) -> {
              Log.d("Reward", "Type: " + type + ", Amount: " + amount);
          });
      }
  });

  rewardedAd.load();
  ```
</CodeGroup>

### ServerSideVerificationOptions

| プロパティ        | 型         | 説明                        |
| ------------ | --------- | ------------------------- |
| `userId`     | `String?` | サーバーサイド検証に使用するユーザー識別子     |
| `customData` | `String?` | サーバーコールバックに送信するカスタムデータ文字列 |

<Note>
  `serverSideVerificationOptions`は`load()`呼び出し前に設定する必要があります。`userId`と`customData`の値は、ユーザーがリワードを獲得した時にサーバーコールバックURLに送信されます。
</Note>

***

## 関連ドキュメント

<CardGroup cols={2}>
  <Card title="インタースティシャル広告" href="/ja/sdk/android/interstitial" icon="rectangle-ad">
    インタースティシャル広告実装ガイド
  </Card>

  <Card title="エラーコード" href="/ja/sdk/android/reference#エラーコード" icon="triangle-exclamation">
    AdropErrorCodeリファレンス
  </Card>

  <Card title="サンプルプロジェクト" href="/ja/sdk/android/examples" icon="code">
    完全なサンプルコードを見る
  </Card>
</CardGroup>
