Android Admob RewardedVideoAd: Complete Guide with Error Handling

August 29, 2019

Setup AdMob for Android With Firebase

Initialize the SDK

Only need to be done once, probably at Application.

class LuaApp: Application() {

    override fun onCreate() {
        super.onCreate()

        MobileAds.initialize(this, "[ADMOB_APP_ID]")
    }
}

Create Ad Unit

Goto https://apps.admob.com/, click Apps -> Your App -> Add Ad Unit.

  • Select ad format: Rewarded
  • Name
  • Reward settings: e.g. reward amount = 1, reward item = ExtraLive (just a amount and string which shall be returned in a callback upon successful watching on an ad video)
  • Create ad Unit
  • Copy Ad Unit ID

Load Ad

I am using a DialogFragment.

class GiftDialog : DialogFragment() {
    companion object {
        private const val FRAGMENT_TAG = "gift_dialog"

        fun newInstance() = GiftDialog()

        fun show(fragmentManager: FragmentManager): GiftDialog {
            val dialog = newInstance()
            // dialog.isCancelable = false
            dialog.show(fragmentManager, FRAGMENT_TAG)
            return dialog
        }
    }


    private lateinit var ad: RewardedVideoAd

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // full screen like an activity
        setStyle(STYLE_NORMAL, android.R.style.Theme_DeviceDefault_Light_NoActionBar)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        // return super.onCreateView(inflater, container, savedInstanceState)
        return activity!!.layoutInflater.inflate(R.layout.gift, container)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)


        ad = MobileAds.getRewardedVideoAdInstance(context)
        ad.rewardedVideoAdListener = object : RewardedVideoAdListener {
            override fun onRewardedVideoAdClosed() {
                // if need to re-use to load more than 1 ad
                // loadAd()
            }

            override fun onRewardedVideoAdLeftApplication() {

            }

            override fun onRewardedVideoAdLoaded() {

            }

            override fun onRewardedVideoAdOpened() {

            }

            override fun onRewardedVideoCompleted() {

            }

            override fun onRewarded(reward: RewardItem) {
                // handle reward
                Toast.makeText(context, "reward=${reward.type} x ${reward.amount}", Toast.LENGTH_LONG).show()
            }

            override fun onRewardedVideoStarted() {

            }

            override fun onRewardedVideoAdFailedToLoad(errorCode: Int) {

                // don't show error here, only when user click show ad button

                /*
                // https://developers.google.com/android/reference/com/google/android/gms/ads/AdListener
                val message = when (errorCode) {
                    AdRequest.ERROR_CODE_NETWORK_ERROR -> "Make sure you have network for Ads to be loaded"
                    AdRequest.ERROR_CODE_NO_FILL -> "No Ads available"
                    else -> "Load Ads Failed ($errorCode)"
                }

                Toast.makeText(context, message, Toast.LENGTH_LONG).show()
                 */

                // use customData to store error code
                ad.customData = errorCode.toString()
            }
        }

        // preload ad
        loadAd()

        showAdButton.setOnClickListener {
            if (ad.isLoaded) {
                ad.show()
            }
            else {
                val message = if (ad.customData == null) {
                    "Ads is not loaded, try again later"
                }
                else {
                    val errorCode = ad.customData.toInt()
                    when (errorCode) {
                        AdRequest.ERROR_CODE_NETWORK_ERROR -> "Make sure you have network for Ads to be loaded"
                        AdRequest.ERROR_CODE_NO_FILL -> "No Ads available"
                        else -> "Load Ads failed ($errorCode)"
                    }
                }

                // Toast.makeText(context, message, Toast.LENGTH_LONG).show()

                AlertDialog.Builder(context)
                    .setMessage("$message\nTry again?")
                    .setPositiveButton(android.R.string.ok) { _, _ ->
                        // might not be the best solution as the user might need to click a few times
                        // listen to network connected event perhaps?
                        loadAd()
                    }
                    .setNegativeButton(android.R.string.cancel, null)
                    .show()
            }
        }
    }

    override fun onPause() {
        super.onPause()
        ad.pause(context)
    }

    override fun onResume() {
        super.onResume()
        ad.resume(context)
    }

    override fun onDestroy() {
        super.onDestroy()
        ad.destroy(context)
    }

    fun loadAd() {
        // reset customData
        ad.customData = null
        // load debug ad during DEBUG
        val adUnitId = if (BuildConfig.DEBUG) "ca-app-pub-3940256099942544/5224354917" else "ca-app-pub-8122************/**********"
        ad.loadAd(adUnitId, AdRequest.Builder().build())
    }
}
This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.