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

# Rewarded Ads

> Learn how to implement rewarded video ads in your Android app.

## Overview

Rewarded ads are full-screen video ads that provide users with rewards such as in-game currency, lives, or hints when they watch the ad to completion.

### Key Features

* Full-screen video ads
* Rewards provided only when users watch the entire ad
* User-initiated ad viewing (e.g., "Watch video to get lives" button)
* Configurable reward type and amount

<Note>
  Use the test unit ID for development: `PUBLIC_TEST_UNIT_ID_REWARDED`
</Note>

***

## Implementation Steps

Rewarded ads are implemented in the following steps:

1. **Create AdropRewardedAd Instance** - Create ad object with unit ID
2. **Set Listener** - Configure listener for ad events
3. **Load Ad** - Request ad with `load()` method
4. **Show Ad** - Display ad with `show()` method and handle rewards

***

## Basic Implementation

### Kotlin Example

```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. Create AdropRewardedAd instance
        rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")

        // 2. Set Listener
        rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
            // Required: Ad received successfully
            override fun onAdReceived(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad received")
                // Enable watch ad button, etc.
            }

            // Required: Ad failed to receive
            override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "Ad failed to receive: $errorCode")
                // Keep watch ad button disabled, etc.
            }

            // Optional: Ad impression
            override fun onAdImpression(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad impression")
            }

            // Optional: Ad clicked
            override fun onAdClicked(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad clicked")
            }

            // Optional: Before showing full screen
            override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad will present")
                // Pause background music, etc.
            }

            // Optional: After showing full screen
            override fun onAdDidPresentFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad did present")
            }

            // Optional: Before closing full screen
            override fun onAdWillDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad will dismiss")
            }

            // Optional: After closing full screen
            override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                Log.d(TAG, "Ad dismissed")
                // Resume background music, etc.

                // Preload next ad
                rewardedAd?.load()
            }

            // Optional: Failed to show
            override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                Log.d(TAG, "Ad failed to show: $errorCode")
            }
        }

        // 3. Load ad
        rewardedAd?.load()

        // Handle watch ad button click
        findViewById<Button>(R.id.btnShowRewardedAd).setOnClickListener {
            showRewardedAd()
        }
    }

    private fun showRewardedAd() {
        // Check if ad is loaded
        if (rewardedAd?.isLoaded != true) {
            Log.d(TAG, "Ad is not loaded yet")
            return
        }

        // 4. Show ad and handle reward
        rewardedAd?.show(this) { type, amount ->
            // Process reward
            Log.d(TAG, "Reward earned - type: $type, amount: $amount")
            grantReward(type, amount)
        }
    }

    private fun grantReward(type: Int, amount: Int) {
        // Grant reward to user
        // e.g., Add in-game currency, restore lives, etc.
    }

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

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

### Java Example

```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. Create AdropRewardedAd instance
        rewardedAd = new AdropRewardedAd(this, "YOUR_UNIT_ID");

        // 2. Set Listener
        rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
            // Required: Ad received successfully
            @Override
            public void onAdReceived(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad received");
                // Enable watch ad button, etc.
            }

            // Required: Ad failed to receive
            @Override
            public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                Log.d(TAG, "Ad failed to receive: " + errorCode);
                // Keep watch ad button disabled, etc.
            }

            // Optional: Ad impression
            @Override
            public void onAdImpression(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad impression");
            }

            // Optional: Ad clicked
            @Override
            public void onAdClicked(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad clicked");
            }

            // Optional: Before showing full screen
            @Override
            public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad will present");
                // Pause background music, etc.
            }

            // Optional: After showing full screen
            @Override
            public void onAdDidPresentFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad did present");
            }

            // Optional: Before closing full screen
            @Override
            public void onAdWillDismissFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad will dismiss");
            }

            // Optional: After closing full screen
            @Override
            public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                Log.d(TAG, "Ad dismissed");
                // Resume background music, etc.

                // Preload next ad
                rewardedAd.load();
            }

            // Optional: Failed to show
            @Override
            public void onAdFailedToShowFullScreen(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                Log.d(TAG, "Ad failed to show: " + errorCode);
            }
        });

        // 3. Load ad
        rewardedAd.load();

        // Handle watch ad button click
        findViewById(R.id.btnShowRewardedAd).setOnClickListener(v -> showRewardedAd());
    }

    private void showRewardedAd() {
        // Check if ad is loaded
        if (!rewardedAd.isLoaded()) {
            Log.d(TAG, "Ad is not loaded yet");
            return;
        }

        // 4. Show ad and handle reward
        rewardedAd.show(this, (type, amount) -> {
            // Process reward
            Log.d(TAG, "Reward earned - type: " + type + ", amount: " + amount);
            grantReward(type, amount);
        });
    }

    private void grantReward(int type, int amount) {
        // Grant reward to user
        // e.g., Add in-game currency, restore lives, etc.
    }

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

***

## AdropRewardedAd Class

### Constructor

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

<ParamField path="context" type="Context">
  Activity or Application Context
</ParamField>

<ParamField path="unitId" type="String">
  Ad unit ID issued from the Adrop console
</ParamField>

### Properties

<ParamField path="unitId" type="String">
  Ad unit ID (read-only)
</ParamField>

<ParamField path="isLoaded" type="Boolean">
  Whether the ad is loaded and ready to show (read-only)
</ParamField>

<ParamField path="creativeId" type="String">
  Creative ID of the loaded ad (read-only)
</ParamField>

<ParamField path="txId" type="String">
  Transaction ID of the ad (read-only)
</ParamField>

<ParamField path="campaignId" type="String">
  Campaign ID of the ad (read-only)
</ParamField>

<ParamField path="isBackfilled" type="Boolean">
  Whether this is a backfill ad (read-only)
</ParamField>

<ParamField path="rewardedAdListener" type="AdropRewardedAdListener?">
  Listener for receiving ad events
</ParamField>

### Methods

<ParamField path="load()" type="Unit">
  Request an ad. Results are delivered via `onAdReceived` or `onAdFailedToReceive` callbacks.
</ParamField>

<ParamField path="show(activity, userDidEarnRewardHandler)" type="Unit">
  Show the ad.

  * `activity`: Activity to display the ad
  * `userDidEarnRewardHandler`: Reward callback `(type: Int, amount: Int) -> Unit`
</ParamField>

<ParamField path="destroy()" type="Unit">
  Release ad resources. Must be called in Activity's `onDestroy()`.
</ParamField>

***

## AdropRewardedAdListener Interface

### Required Methods

<ParamField path="onAdReceived(ad: AdropRewardedAd)" type="void">
  Called when ad is successfully received. You can show the ad with `show()` from this point.
</ParamField>

<ParamField path="onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode)" type="void">
  Called when ad fails to load. Check the error code for the failure reason.
</ParamField>

### Optional Methods

<ParamField path="onAdImpression(ad: AdropRewardedAd)" type="void">
  Called when ad impression is recorded.
</ParamField>

<ParamField path="onAdClicked(ad: AdropRewardedAd)" type="void">
  Called when user clicks the ad.
</ParamField>

<ParamField path="onAdWillPresentFullScreen(ad: AdropRewardedAd)" type="void">
  Called just before the ad screen is displayed. Good time to pause background music.
</ParamField>

<ParamField path="onAdDidPresentFullScreen(ad: AdropRewardedAd)" type="void">
  Called after the ad screen is fully displayed.
</ParamField>

<ParamField path="onAdWillDismissFullScreen(ad: AdropRewardedAd)" type="void">
  Called just before the ad screen closes.
</ParamField>

<ParamField path="onAdDidDismissFullScreen(ad: AdropRewardedAd)" type="void">
  Called after the ad screen is fully closed. Good time to resume background music or preload next ad.
</ParamField>

<ParamField path="onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode)" type="void">
  Called when ad fails to show. Check the error code for the failure reason.
</ParamField>

***

## Reward Handling

### Reward Callback

Pass a reward callback as the `userDidEarnRewardHandler` parameter to the `show()` method.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  rewardedAd?.show(this) { type, amount ->
      // type: Reward type (Int)
      // amount: Reward amount (Int)
      Log.d(TAG, "Reward earned - type: $type, amount: $amount")
      grantReward(type, amount)
  }
  ```

  ```java Java theme={null}
  rewardedAd.show(this, (type, amount) -> {
      // type: Reward type (Int)
      // amount: Reward amount (Int)
      Log.d(TAG, "Reward earned - type: " + type + ", amount: " + amount);
      grantReward(type, amount);
  });
  ```
</CodeGroup>

### Reward Type and Amount

* **type**: Reward type configured in Adrop console (integer value)
* **amount**: Reward amount configured in Adrop console (integer value)

## Best Practices

### 1. Preload Ads

Preload ads for better user experience.

<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)

          // Preload ad on screen entry
          loadRewardedAd()
      }

      private fun loadRewardedAd() {
          rewardedAd = AdropRewardedAd(this, "YOUR_UNIT_ID")
          rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
              override fun onAdReceived(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad ready")
              }

              override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                  Log.d(TAG, "Ad load failed: $errorCode")
              }

              override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                  // Preload next ad after closing
                  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);

          // Preload ad on screen entry
          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, "Ad ready");
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.d(TAG, "Ad load failed: " + errorCode);
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                  // Preload next ad after closing
                  loadRewardedAd();
              }
          });
          rewardedAd.load();
      }

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

### 2. Check Ad Ready State

Check if ad is loaded and update UI accordingly.

<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) "Watch Video for Lives" else "Loading Ad..."
          }
      }

      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()

              // Load next ad
              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 ? "Watch Video for Lives" : "Loading Ad...");
      }

      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();

              // Load next ad
              rewardedAd.load();
          }
      };
  }
  ```
</CodeGroup>

### 3. Background Music Handling

Control background music appropriately before and after ad display.

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

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          // Required implementation
      }

      override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
          // Pause background music before showing ad
          AudioManager.pauseBackgroundMusic()
      }

      override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
          // Resume background music after ad closes
          AudioManager.resumeBackgroundMusic()
      }
  }
  ```

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

      @Override
      public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
          // Required implementation
      }

      @Override
      public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
          // Pause background music before showing ad
          AudioManager.pauseBackgroundMusic();
      }

      @Override
      public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
          // Resume background music after ad closes
          AudioManager.resumeBackgroundMusic();
      }
  };
  ```
</CodeGroup>

### 4. Error Handling

Implement retry logic when ad loading fails.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  private val adListener = object : AdropRewardedAdListener {
      override fun onAdReceived(ad: AdropRewardedAd) {
          Log.d(TAG, "Ad load success")
      }

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          Log.d(TAG, "Ad load failed: $errorCode")

          // Retry on network error
          if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
              Handler(Looper.getMainLooper()).postDelayed({
                  rewardedAd?.load()
              }, 3000)
          }
      }

      override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          Log.d(TAG, "Ad show failed: $errorCode")

          // Notify user
          Toast.makeText(
              this@GameActivity,
              "Cannot show ad. Please try again later.",
              Toast.LENGTH_SHORT
          ).show()
      }
  }
  ```

  ```java Java theme={null}
  private final AdropRewardedAdListener adListener = new AdropRewardedAdListener() {
      @Override
      public void onAdReceived(@NonNull AdropRewardedAd ad) {
          Log.d(TAG, "Ad load success");
      }

      @Override
      public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
          Log.d(TAG, "Ad load failed: " + errorCode);

          // Retry on network error
          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, "Ad show failed: " + errorCode);

          // Notify user
          Toast.makeText(
              GameActivity.this,
              "Cannot show ad. Please try again later.",
              Toast.LENGTH_SHORT
          ).show();
      }
  };
  ```
</CodeGroup>

### 5. Lifecycle Management

Clean up ad resources when Activity is destroyed.

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

***

## Complete Example

<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()
          }

          // Preload ad
          loadRewardedAd()
      }

      private fun loadRewardedAd() {
          rewardedAd = AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED")
          rewardedAd?.rewardedAdListener = object : AdropRewardedAdListener {
              override fun onAdReceived(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad received")
                  isAdReady = true
                  updateButtonState()
              }

              override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                  Log.d(TAG, "Ad failed to receive: $errorCode")
                  isAdReady = false
                  updateButtonState()

                  // Retry after 3 seconds on network error
                  if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
                      Handler(Looper.getMainLooper()).postDelayed({
                          rewardedAd?.load()
                      }, 3000)
                  }
              }

              override fun onAdImpression(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad impression")
              }

              override fun onAdClicked(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad clicked")
              }

              override fun onAdWillPresentFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad will present")
                  // Pause background music
                  pauseBackgroundMusic()
              }

              override fun onAdDidPresentFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad did present")
              }

              override fun onAdWillDismissFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad will dismiss")
              }

              override fun onAdDidDismissFullScreen(ad: AdropRewardedAd) {
                  Log.d(TAG, "Ad dismissed")
                  isAdReady = false
                  updateButtonState()

                  // Resume background music
                  resumeBackgroundMusic()

                  // Preload next ad
                  loadRewardedAd()
              }

              override fun onAdFailedToShowFullScreen(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
                  Log.d(TAG, "Ad failed to show: $errorCode")
                  Toast.makeText(
                      this@GameActivity,
                      "Cannot show ad. Please try again later.",
                      Toast.LENGTH_SHORT
                  ).show()
              }
          }
          rewardedAd?.load()
      }

      private fun showRewardedAd() {
          if (!isAdReady) {
              Toast.makeText(this, "Ad is not loaded yet", Toast.LENGTH_SHORT).show()
              return
          }

          rewardedAd?.show(this) { type, amount ->
              Log.d(TAG, "Reward earned - type: $type, amount: $amount")
              grantReward(type, amount)
          }
      }

      private fun grantReward(type: Int, amount: Int) {
          // Grant reward to user
          runOnUiThread {
              Toast.makeText(
                  this,
                  "Reward earned! Type: $type, Amount: $amount",
                  Toast.LENGTH_LONG
              ).show()
          }

          // Implement actual reward logic
          // e.g., Add in-game currency, restore lives, etc.
      }

      private fun updateButtonState() {
          btnWatchAd.isEnabled = isAdReady
          btnWatchAd.alpha = if (isAdReady) 1.0f else 0.5f
          btnWatchAd.text = if (isAdReady) "Watch Video for Lives" else "Loading Ad..."
      }

      private fun pauseBackgroundMusic() {
          // Pause background music logic
      }

      private fun resumeBackgroundMusic() {
          // Resume background music logic
      }

      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());

          // Preload ad
          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, "Ad received");
                  isAdReady = true;
                  updateButtonState();
              }

              @Override
              public void onAdFailedToReceive(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.d(TAG, "Ad failed to receive: " + errorCode);
                  isAdReady = false;
                  updateButtonState();

                  // Retry after 3 seconds on network error
                  if (errorCode == AdropErrorCode.ERROR_CODE_NETWORK) {
                      new Handler(Looper.getMainLooper()).postDelayed(() -> {
                          rewardedAd.load();
                      }, 3000);
                  }
              }

              @Override
              public void onAdImpression(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "Ad impression");
              }

              @Override
              public void onAdClicked(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "Ad clicked");
              }

              @Override
              public void onAdWillPresentFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "Ad will present");
                  // Pause background music
                  pauseBackgroundMusic();
              }

              @Override
              public void onAdDidPresentFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "Ad did present");
              }

              @Override
              public void onAdWillDismissFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "Ad will dismiss");
              }

              @Override
              public void onAdDidDismissFullScreen(@NonNull AdropRewardedAd ad) {
                  Log.d(TAG, "Ad dismissed");
                  isAdReady = false;
                  updateButtonState();

                  // Resume background music
                  resumeBackgroundMusic();

                  // Preload next ad
                  loadRewardedAd();
              }

              @Override
              public void onAdFailedToShowFullScreen(@NonNull AdropRewardedAd ad, @NonNull AdropErrorCode errorCode) {
                  Log.d(TAG, "Ad failed to show: " + errorCode);
                  Toast.makeText(
                      GameActivity.this,
                      "Cannot show ad. Please try again later.",
                      Toast.LENGTH_SHORT
                  ).show();
              }
          });
          rewardedAd.load();
      }

      private void showRewardedAd() {
          if (!isAdReady) {
              Toast.makeText(this, "Ad is not loaded yet", Toast.LENGTH_SHORT).show();
              return;
          }

          rewardedAd.show(this, (type, amount) -> {
              Log.d(TAG, "Reward earned - type: " + type + ", amount: " + amount);
              grantReward(type, amount);
          });
      }

      private void grantReward(int type, int amount) {
          // Grant reward to user
          runOnUiThread(() -> {
              Toast.makeText(
                  this,
                  "Reward earned! Type: " + type + ", Amount: " + amount,
                  Toast.LENGTH_LONG
              ).show();
          });

          // Implement actual reward logic
          // e.g., Add in-game currency, restore lives, etc.
      }

      private void updateButtonState() {
          btnWatchAd.setEnabled(isAdReady);
          btnWatchAd.setAlpha(isAdReady ? 1.0f : 0.5f);
          btnWatchAd.setText(isAdReady ? "Watch Video for Lives" : "Loading Ad...");
      }

      private void pauseBackgroundMusic() {
          // Pause background music logic
      }

      private void resumeBackgroundMusic() {
          // Resume background music logic
      }

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

***

## Testing

### Test Unit ID

Always use test unit IDs during development.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  // Development environment
  val rewardedAd = AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED")

  // Production environment
  val rewardedAd = AdropRewardedAd(this, "YOUR_PRODUCTION_UNIT_ID")
  ```

  ```java Java theme={null}
  // Development environment
  AdropRewardedAd rewardedAd = new AdropRewardedAd(this, "PUBLIC_TEST_UNIT_ID_REWARDED");

  // Production environment
  AdropRewardedAd rewardedAd = new AdropRewardedAd(this, "YOUR_PRODUCTION_UNIT_ID");
  ```
</CodeGroup>

<Warning>
  Testing with actual unit IDs may be considered invalid traffic and could result in account suspension. Always use test unit IDs.
</Warning>

### Environment-based Unit ID Management

Automatically switch unit IDs based on build type.

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

  // Usage
  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";
          }
      }
  }

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

***

## Backfill Ads

When backfill ads are enabled, backfill ads are automatically loaded when direct ads are unavailable. Use the `isBackfilled` property to check if the ad is a backfill ad.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  rewardedAd.rewardedAdListener = object : AdropRewardedAdListener {
      override fun onAdReceived(ad: AdropRewardedAd) {
          if (ad.isBackfilled) {
              println("Backfill ad loaded")
          } else {
              println("Direct ad loaded")
          }
      }

      override fun onAdFailedToReceive(ad: AdropRewardedAd, errorCode: AdropErrorCode) {
          when (errorCode) {
              AdropErrorCode.ERROR_CODE_AD_NO_FILL -> {
                  println("No direct ad, requesting backfill...")
              }
              AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL -> {
                  println("Backfill ad also not available")
              }
              else -> {
                  println("Ad load failed: $errorCode")
              }
          }
      }
  }
  ```

  ```java Java theme={null}
  rewardedAd.setRewardedAdListener(new AdropRewardedAdListener() {
      @Override
      public void onAdReceived(AdropRewardedAd ad) {
          if (ad.isBackfilled()) {
              System.out.println("Backfill ad loaded");
          } else {
              System.out.println("Direct ad loaded");
          }
      }

      @Override
      public void onAdFailedToReceive(AdropRewardedAd ad, AdropErrorCode errorCode) {
          if (errorCode == AdropErrorCode.ERROR_CODE_AD_NO_FILL) {
              System.out.println("No direct ad, requesting backfill...");
          } else if (errorCode == AdropErrorCode.ERROR_CODE_AD_BACKFILL_NO_FILL) {
              System.out.println("Backfill ad also not available");
          } else {
              System.out.println("Ad load failed: " + errorCode);
          }
      }
  });
  ```
</CodeGroup>

<Note>
  To use backfill ads, add the `io.adrop:adrop-ads-backfill` dependency. See [Getting Started](/sdk/android/overview).
</Note>

***

## Server-Side Verification

Server-side verification (SSV) allows you to verify reward grants on your server, preventing client-side manipulation. Use `ServerSideVerificationOptions` to pass user identification and custom data that will be included in the server-to-server callback.

<Note>
  To receive SSV callbacks on your server, register a callback URL in the console: **\[Management] > \[Integrations] > Reward Ad SSV**. The `userId` and `customData` set here are included in the encrypted payload sent to that URL. See the [Reward Ad SSV guide](/integrations/ssv) for payload decryption and setup.
</Note>

### Setting Up SSV

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

  // Set server-side verification options before loading the ad
  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");

  // Set server-side verification options before loading the ad
  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

| Property     | Type      | Description                                   |
| ------------ | --------- | --------------------------------------------- |
| `userId`     | `String?` | User identifier for server-side verification  |
| `customData` | `String?` | Custom data string to include in the callback |

<Note>
  Set `serverSideVerificationOptions` before calling `load()`. The `userId` and `customData` values are sent to your server callback URL when the user earns a reward.
</Note>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Interstitial Ads" href="/sdk/android/interstitial" icon="rectangle-ad">
    Interstitial ad implementation guide
  </Card>

  <Card title="Error Codes" href="/sdk/android/reference#error-codes" icon="triangle-exclamation">
    AdropErrorCode reference
  </Card>

  <Card title="Examples" href="/sdk/android/examples" icon="code">
    View complete example code
  </Card>
</CardGroup>
