UPDATE [August 22nd, 2020]: Change tutorial’s code to be compatible with the latest MoPub version

If you don’t have a MoPub account yet, check out the tutorial How to Create an Account on MoPub where I cover step by step how to make one, and get approved from Marketplace.

In this tutorial, I will show you how to add MoPub Ads in your Android app. We’ll cover all ad formats (Banner, Interstitial, Native, Native Video and Rewarded), we’re also going to implement Native ads inside a Recyclerview and Viewpager.

I highly recommend using MoPub Test Ad Units when you implement the following methods.

If you’re using ad units created from your MoPub account they might not work all the time in the beginning, because when you start, the filling rate is low, so it’s better to start with the test ad units, and when your app/update is production-ready, switch to your own ad units.

Setting up MoPub

First, go to the root-level build.gradle and paste:

allprojects { repositories { // ... google() jcenter() maven { url "https://s3.amazonaws.com/moat-sdk-builds" } } }

Then, in the app-level build.gradle add MoPub’s dependency:

allprojects { repositories { // ... google() jcenter() maven { url "https://s3.amazonaws.com/moat-sdk-builds" } } }

If you want to use only a specific ad format, let’s say Native Ads, you can choose the dependency only for that format, to decrease the size of the SDK:

dependencies { // ... other project dependencies // For banners implementation('com.mopub:mopub-sdk-banner:[email protected]') { transitive = true } // For interstitials implementation('com.mopub:mopub-sdk-interstitial:[email protected]') { transitive = true } // For rewarded videos. This will automatically also include interstitials implementation('com.mopub:mopub-sdk-rewardedvideo:[email protected]') { transitive = true } // For native static (images). implementation('com.mopub:mopub-sdk-native-static:[email protected]') { transitive = true } // For native video. This will automatically also include native static implementation('com.mopub:mopub-sdk-native-video:[email protected]') { transitive = true } }

Now let’s jump into our AndroidManifest.xml file and add the following permissions for our ads:

<!-- Required permissions --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- Optional permissions. Will pass Lat/Lon values when available. Choose either Coarse or Fine --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <!-- Optional permissions. Used for MRAID 2.0 storePicture ads --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

..also in the same file we add the MoPub Activities (choose the Activity for your ad format):

<!-- MoPub's consent dialog --> <activity android:name="com.mopub.common.privacy.ConsentDialogActivity" android:configChanges="keyboardHidden|orientation|screenSize"/> <!-- All ad formats --> <activity android:name="com.mopub.common.MoPubBrowser" android:configChanges="keyboardHidden|orientation|screenSize"/> <!-- Interstitials --> <activity android:name="com.mopub.mobileads.MoPubActivity" android:configChanges="keyboardHidden|orientation|screenSize"/> <activity android:name="com.mopub.mobileads.MraidActivity" android:configChanges="keyboardHidden|orientation|screenSize"/> <!-- Rewarded Video and Rewarded Playables --> <activity android:name="com.mopub.mobileads.RewardedMraidActivity" android:configChanges="keyboardHidden|orientation|screenSize"/> <activity android:name="com.mopub.mobileads.MraidVideoPlayerActivity" android:configChanges="keyboardHidden|orientation|screenSize"/>

..and lastly, we have to add the following tag for the Google Play Services:

// ... mopub activies <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> // ... main activity

Now let’s go back to our build.gradle file of the app and add the dependency for the Google Play Services:

// ... mopub activies <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> // ... main activity

NOTE: If you use an ad format that includes video, MoPub recommends adding the following compileOptions in the build.gradle file of the app to prevent compilation errors with ExoPlayer 2.9.5 and later:

android { // ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_8 } }

Android 9.0 (API 28) blocks all the connections without HTTPS protocol.

To make our ads work properly, we need to create a xml file (network_security_config.xml) under the xml folder of our project.

Right-click on the res folder of our project and choose New>Folder>XML Resources Folder and Finish.

Then right-click on the xml folder and choose New>XML resource file.

Give the name network_security_config and press OK.

Now paste the following code inside:

android { // ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_8 } }

…next, we have to add this file in our AndroidManifest.xml inside the <application> tag:

For more details about that, look at Step 4. Add a Network Security Configuration File in MoPub Documentation.

Initializing MoPub

MoPub recommends that we need to initialize the SDK before requesting an ad in our app.

So I made a class (MyMoPub) where we initialize MoPub SDK and check if the country is covered by GDPR.

Check out the tutorial How to create a Custom MoPub GDPR Consent Dialog in Android using Kotlin to create a custom dialog for the GDPR consent

If the user is living in a GDPR country, then we show the consent dialog to ask them for their permission to display personalized ads.

class MyMoPub { private lateinit var mPersonalInfoManager: PersonalInfoManager private lateinit var mContext: Context fun init(context: Context, adunit: String) { mContext = context val sdkConfiguration = SdkConfiguration.Builder(adunit) .withLogLevel(MoPubLog.LogLevel.DEBUG) .withLegitimateInterestAllowed(false) .build() MoPub.initializeSdk(mContext, sdkConfiguration, initSdkListener()) } private fun initSdkListener(): SdkInitializationListener { return SdkInitializationListener { /* MoPub SDK initialized. Check if you should show the consent dialog here, and make your ad requests. */ Log.d("MoPub", "MoPub SDK Initilized") GDPRConsent() } } private fun GDPRConsent() { mPersonalInfoManager = MoPub.getPersonalInformationManager()!! Log.d("MoPub", "This country covered by GDPR? ${mPersonalInfoManager.gdprApplies()}") if (mPersonalInfoManager.shouldShowConsentDialog()) { mPersonalInfoManager.loadConsentDialog(initDialogLoadListener()) } } private fun initDialogLoadListener(): ConsentDialogListener { return object : ConsentDialogListener { override fun onConsentDialogLoaded() { mPersonalInfoManager.showConsentDialog() } override fun onConsentDialogLoadFailed(@NonNull moPubErrorCode: MoPubErrorCode) { Log.d("MoPub", "Consent dialog failed to load.") } } } }

If you have multiple ad formats (e.g. Native and Banner ads) on the same screen, just give as a parameter one of the adunits.

Banner Ads (Banner/Medium Rectangle)

Go to the MoPub Dashboard and create a new Banner ad unit (or Medium Rectangle) and press Save.

Now that we have created the ad unit id, we are ready to add the Banner/Medium Rectangle (MoPubView) view at the bottom of the layout, like that:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimary" android:orientation="vertical" tools:context=".BannerAds.BannerAdActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <!-- Content of your Activity/Fragment --> <com.mopub.mobileads.MoPubView android:id="@+id/banner_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_gravity="center_horizontal" app:moPubAdSize="match_view" /> </RelativeLayout> </LinearLayout>

… and in our Activity/Fragment class:

class BannerAdActivity : AppCompatActivity() { private lateinit var moPubBanner: MoPubView private lateinit var moPubViewBannerAdListener: MoPubView.BannerAdListener private var isMediumRectangleAd = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_banner_ad) MyMoPub().init(this, "AD_UNIT_ID") Handler(Looper.getMainLooper()).postDelayed({ initAds() }, 200) } private fun initAds() { moPubBanner = findViewById(R.id.banner_view) moPubBanner.setAdUnitId("AD_UNIT_ID") moPubBanner.loadAd() Log.d("MoPub","Banner ad is loading.") moPubViewBannerAdListener = object : MoPubView.BannerAdListener { override fun onBannerExpanded(banner: MoPubView) { Log.d("MoPub","Banner ad has expanded.") } override fun onBannerLoaded(banner: MoPubView) { Log.d("MoPub","Banner ad has loaded.") } override fun onBannerCollapsed(banner: MoPubView) { Log.d("MoPub","Banner ad has collapsed.") } override fun onBannerFailed(banner: MoPubView, errorCode: MoPubErrorCode) { Log.d("MoPub","Banner ad failed to load with error:$errorCode") } override fun onBannerClicked(banner: MoPubView) { Log.d("Banner ad was clicked.") } } moPubBanner.bannerAdListener = moPubViewBannerAdListener } override fun onDestroy() { // You must call this or the banner view may cause a memory leak. moPubBanner.destroy() super.onDestroy() } }

First, we initialize the SDK, next we create the Banner View and we request an ad and lastly, we create a listener that can inform us for every event.

Interstitial Ads

Let’s go to the MoPub Dashboard and create a new Interstitial ad unit.

Give it a name, choose Full Screen and press Save.

Interstitial ads are very simple to integrate; you only need to add the following code to your Activity/Fragment:

class InterstitialAdActivity : AppCompatActivity() { private lateinit var moPubInterstitial: MoPubInterstitial private lateinit var moPubInterstitialInterstitialAdListener: MoPubInterstitial.InterstitialAdListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_interstitial_ad) MyMoPub().init(this, "AD_UNIT_ID") Handler(Looper.getMainLooper()).postDelayed({ initAds() }, 200) } private fun initAds() { moPubInterstitial = MoPubInterstitial(this, "AD_UNIT_ID") Log.d("MoPub", "Interstitial ad is loading.") moPubInterstitial.load() moPubInterstitialInterstitialAdListener = object : MoPubInterstitial.InterstitialAdListener { override fun onInterstitialLoaded(interstitial: MoPubInterstitial?) { //Do something when insterstitial is loaded Log.d("MoPub", "Interstitial ad is loaded.") //Show the Ad if the Interstitial is loaded yourAppsShowInterstitialMethod() } override fun onInterstitialShown(interstitial: MoPubInterstitial?) { //Do something when insterstitial is shown Log.d("MoPub", "Interstitial ad has show.") } override fun onInterstitialFailed(interstitial: MoPubInterstitial?,errorCode: MoPubErrorCode?) { //Do something when insterstitial is failed Log.d("MoPub", "Interstitial ad failed to load with error: $errorCode") } override fun onInterstitialDismissed(interstitial: MoPubInterstitial?) { //Do something when insterstitial is dismissed Log.d("MoPub", "Interstitial ad has dismissed.") } override fun onInterstitialClicked(interstitial: MoPubInterstitial?) { //Do something when insterstitial is clicked Log.d("MoPub", "Interstitial ad clicked.") } } moPubInterstitial.interstitialAdListener = moPubInterstitialInterstitialAdListener } private fun yourAppsShowInterstitialMethod() { if (moPubInterstitial.isReady) { moPubInterstitial.show() } else { // Caching is likely already in progress if `isReady()` is false. // Avoid calling `load()` here and instead rely on the callbacks on moPubInterstitialInterstitialAdListener } } override fun onDestroy() { moPubInterstitial.destroy() super.onDestroy() } }

As you see above, we initialize the SDK, create the Interstitial view, and prepare the ad to be ready to show on the user. Last, we add a listener to check when it’s loaded.

In this example we call yourAppsShowInterstitialMethod() after we load the Interstitial ad, but in a real app, call this method when you want to show the ad to the user, for example, in a game when a round ends.

Native Ads

First, in the MoPub Dashboard, we create a new ad unit for our Native ads.

Then, we create the layout for our Native Ad.

Right-click on the layout folder and New>Layout resource file.

… and give it the name ‘mopub_native_ad_view’ and press OK.

Then, paste the following inside:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="match_parent" android:background="@color/colorPrimary" android:layout_height="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mopub_native_ad_layout"> <ImageView android:id="@+id/mopub_native_ad_privacy" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginTop="-5dp" android:layout_marginEnd="-5dp" android:layout_alignParentEnd="true" android:layout_alignParentTop="true" android:tint="@android:color/white" android:contentDescription="Privacy Information Icon image" android:padding="10dp" android:layout_marginRight="-5dp" android:layout_alignParentRight="true" /> <ImageView android:id="@+id/mopub_native_ad_icon" android:background="@null" android:scaleType="centerInside" android:layout_width="50dp" android:layout_height="50dp" android:layout_marginTop="10dp" android:layout_marginStart="10dp" android:layout_alignParentStart="true" android:layout_marginLeft="10dp" android:layout_alignParentLeft="true" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/mopub_native_ad_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toEndOf="@id/mopub_native_ad_icon" android:layout_marginStart="10dp" android:layout_toStartOf="@id/mopub_native_ad_privacy" android:textColor="@android:color/white" android:textStyle="bold" android:textSize="16sp" android:text="Lorem ipsum dolor sit amet, consectetur" android:layout_marginEnd="10dp" android:layout_alignTop="@id/mopub_native_ad_icon" android:layout_toRightOf="@id/mopub_native_ad_icon" android:layout_toLeftOf="@id/mopub_native_ad_privacy" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/mopub_native_ad_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/mopub_native_ad_title" android:layout_marginStart="12dp" android:layout_marginTop="3dp" android:layout_marginEnd="3dp" android:layout_marginBottom="2dp" android:layout_toStartOf="@+id/mopub_native_ad_privacy" android:layout_toEndOf="@id/mopub_native_ad_icon" android:lines="2" android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua" android:textColor="@android:color/white" android:textSize="14sp" android:layout_marginLeft="12dp" android:layout_marginRight="3dp" android:layout_toLeftOf="@+id/mopub_native_ad_privacy" android:layout_toRightOf="@id/mopub_native_ad_icon" /> <ImageView android:id="@+id/mopub_native_ad_main_imageview" android:layout_below="@id/mopub_native_ad_text" android:layout_margin="10dp" android:layout_width="match_parent" android:layout_height="@dimen/native_main_image_height" /> <Button android:id="@+id/mopub_native_ad_cta" android:layout_width="match_parent" android:layout_height="@dimen/button_height" android:layout_marginLeft="10dp" android:layout_below="@id/mopub_native_ad_main_imageview" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" android:layout_marginTop="10dp" android:layout_marginRight="10dp" android:layout_marginBottom="10dp" android:textAllCaps="false" android:focusable="true" android:background="@color/colorPrimaryDark" android:text="Free to play" android:textSize="@dimen/button_text_size" android:minWidth="0dp" android:minHeight="0dp" android:textColor="@android:color/white" android:textStyle="bold" /> </RelativeLayout>

For different device sizes, we need a different height for the main ImageView of our Native Ad.

Let’s do that and create a file called dimen.xml by right-clicking on the values folder and choose New>Values resource file …

… and type the name dimens and press OK.

Now, let’s do the same thing again for other screen sizes, but this time we will choose Smallest Screen Width from the list, press the >> button and give the value 400, 600, and 800.

And paste the following code in the dimens.xml:

<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="button_text_size">13sp</dimen> <dimen name="native_main_image_height">200dp</dimen> <dimen name="button_height">36dp</dimen> </resources>

.. the dimens.xml (sw400dp):

<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="native_main_image_height">200dp</dimen> <dimen name="button_text_size">15sp</dimen> </resources>

dimens.xml (sw600dp):

<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="native_main_image_height">300dp</dimen> <dimen name="button_text_size">17sp</dimen> </resources>

… and in the dimens.xml (sw800dp):

<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="native_main_image_height">300dp</dimen> <dimen name="button_text_size">17sp</dimen> </resources>

After we finished, our project looks like this:

Native Ads (Single View)

To integrate a Native Ad as a single view, we have to create a FrameLayout inside our Activity/Fragment.

This FrameLayout will contain the Native Ad layout we created earlier.

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimary" tools:context=".NativeVideoAds.nativeVideoAd.NativeVideoAdSingleView"> <!-- Content of our Activity/Fragment --> <FrameLayout android:id="@+id/native_ad_frame" android:layout_width="match_parent" android:layout_centerInParent="true" android:layout_height="wrap_content" /> <!-- Content of our Activity/Fragment --> </RelativeLayout>

Next, in our Activity/Fragment Kotlin class we add:

class NativeAdSingleView : AppCompatActivity() { private lateinit var moPubNativeNetworkListener: MoPubNative.MoPubNativeNetworkListener private lateinit var moPubNativeEventListener: NativeAd.MoPubNativeEventListener private lateinit var moPubNative: MoPubNative private lateinit var adapterHelper: AdapterHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_native_ad_single_view) MyMoPub().init(this, "AD_UNIT_ID") Handler(Looper.getMainLooper()).postDelayed({ initAds() }, 200) } private fun initAds() { moPubNativeEventListener = object : NativeAd.MoPubNativeEventListener{ override fun onClick(view: View?) { // Click tracking. Log.d("MoPub", "Native ad recorded a click.") } override fun onImpression(view: View?) { // Impress is recorded - do what is needed AFTER the ad is visibly shown here. Log.d("MoPub", "Native ad recorded an impression.") } } moPubNativeNetworkListener = object : MoPubNative.MoPubNativeNetworkListener { override fun onNativeLoad(nativeAd: NativeAd?) { adapterHelper = AdapterHelper([email protected], 0, 3) val v = adapterHelper.getAdView(null, native_ad_frame,nativeAd,ViewBinder.Builder(0).build()) nativeAd!!.setMoPubNativeEventListener(moPubNativeEventListener) native_ad_frame.addView(v) Log.d("MoPub", "Native ad has loaded.") } override fun onNativeFail(errorCode: NativeErrorCode) { Log.d("MoPub", "Native ad failed to load with error: $errorCode") } } moPubNative = MoPubNative(this, "AD_UNIT_ID", moPubNativeNetworkListener) val viewBinder = ViewBinder.Builder(R.layout.mopub_native_ad_view) .titleId(R.id.mopub_native_ad_title) .textId(R.id.mopub_native_ad_text) .mainImageId(R.id.mopub_native_ad_main_imageview) .iconImageId(R.id.mopub_native_ad_icon) .callToActionId(R.id.mopub_native_ad_cta) .privacyInformationIconImageId(R.id.mopub_native_ad_privacy) .build() val adRenderer = MoPubStaticNativeAdRenderer(viewBinder) moPubNative.registerAdRenderer(adRenderer) moPubNative.makeRequest() Log.d("MoPub", "Native ad is loading.") } override fun onDestroy() { // You must call this or the native view may cause a memory leak. moPubNative.destroy() super.onDestroy() } }

Here, we initialize the MoPub SDK, then we create an event listener where we check if the Native ad got an impression or clicked, a network listener which we add the Native ad view in the FrameLayout of our Activity/Fragment, and at the end, we create the ViewBinder for our Native ad layout, and we send a request to get an ad from MoPub

And that’s it!

Native Ads (RecyclerView)

Let’s say that we have a RecyclerView already filled with data, and we want to put ads in it, an easy method is to use MoPub‘s adapter, MoPubRecyclerAdapter, which calculates the amount of cells with the ads automatically.

To do that, we use the MoPubRecyclerAdapter after the normal RecyclerView.Adapter of our RecyclerView:

class NativeAdRecyclerView : AppCompatActivity() { private lateinit var itemsCells: ArrayList<String?> private lateinit var adapter: NativeAd_RVAdapter private lateinit var moPubAdapter: MoPubRecyclerAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_native_ad_recycler_view) //Initialize MoPub SDK MyMoPub().init(this, "AD_UNIT_ID") //** Set the data for our ArrayList setItemsData() //** Set the adapter of the RecyclerView setAdapter() //** Set the Layout Manager of the RecyclerView setRVLayoutManager() } private fun setItemsData() { itemsCells = ArrayList() for (i in 0..40) { itemsCells.add("Item $i") } } private fun setAdapter() { adapter = NativeAd_RVAdapter(itemsCells) native_ad_rv.adapter = adapter Handler(Looper.getMainLooper()).postDelayed({ initNativeAds() }, 200) adapter.notifyDataSetChanged() } private fun setRVLayoutManager() { val mLayoutManager = LinearLayoutManager(native_ad_rv.context) native_ad_rv.layoutManager = mLayoutManager native_ad_rv.setHasFixedSize(true) } private fun initNativeAds() { moPubAdapter = MoPubRecyclerAdapter(this, adapter) val myViewBinder = ViewBinder.Builder(R.layout.mopub_native_ad_view) .titleId(R.id.mopub_native_ad_title) .textId(R.id.mopub_native_ad_text) .mainImageId(R.id.mopub_native_ad_main_imageview) .iconImageId(R.id.mopub_native_ad_icon) .callToActionId(R.id.mopub_native_ad_cta) .privacyInformationIconImageId(R.id.mopub_native_ad_privacy) .build() val myRenderer = MoPubStaticNativeAdRenderer(myViewBinder) moPubAdapter.registerAdRenderer(myRenderer) native_ad_rv.adapter = moPubAdapter moPubAdapter.loadAds("AD_UNIT_ID") } override fun onDestroy() { // You must call this or the ad adapter may cause a memory leak. moPubAdapter.destroy() super.onDestroy() } }

Here, we initialize the MoPub SDK, then we add the native ads into our RecyclerView after we pass the normal adapter.

When we add the native ads, we pass as a parameter the normal RecyclerView.Adapter to create the right amount of rows.

And done! Easy, huh?

Native Ads (ViewPager)

We already have an Activity/Fragment with a ViewPager in it, filled with data, and we want to have ads every 8 pages.

To do that, first, we need to edit our Activity/Fragment and create the Native Ads, then we add the adplacer (MoPubStreamAdPlacer), to insert the ads, into the ViewPager through the adapter

class NativeAdViewPager : AppCompatActivity() { lateinit var mPagerAdapter: CustomPagerAdapter lateinit var moPubNativeAdLoadedListener: MoPubNativeAdLoadedListener lateinit var adPlacer: MoPubStreamAdPlacer override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_native_ad_view_pager) MyMoPub().init(this, "AD_UNIT_ID") initAds() //** Set the adapter of the ViewPager setAdapter() } private fun initAds() { moPubNativeAdLoadedListener = object : MoPubNativeAdLoadedListener { override fun onAdRemoved(position: Int) { native_ad_pager.invalidate() mPagerAdapter.notifyDataSetChanged() Log.d("MoPub","Native ad has been removed") } override fun onAdLoaded(position: Int) { native_ad_pager.invalidate() mPagerAdapter.notifyDataSetChanged() Log.d("MoPub","Native ad has been loaded") } } // Set up a renderer for a static native ad. val moPubStaticNativeAdRenderer = MoPubStaticNativeAdRenderer(ViewBinder.Builder(R.layout.mopub_native_ad_view) .titleId(R.id.mopub_native_ad_title) .textId(R.id.mopub_native_ad_text) .mainImageId(R.id.mopub_native_ad_main_imageview) .iconImageId(R.id.mopub_native_ad_icon) .callToActionId(R.id.mopub_native_ad_cta) .privacyInformationIconImageId(R.id.mopub_native_ad_privacy) .build() ) // This ad placer is used to automatically insert ads into the ViewPager. adPlacer = MoPubStreamAdPlacer(this) // The first renderer that can handle a particular native ad gets used. adPlacer.registerAdRenderer(moPubStaticNativeAdRenderer) adPlacer.setAdLoadedListener(moPubNativeAdLoadedListener) } private fun setAdapter() { mPagerAdapter = CustomPagerAdapter(supportFragmentManager, adPlacer) native_ad_pager.adapter = mPagerAdapter Handler().postDelayed({ adPlacer.loadAds("AD_UNIT_ID") Log.d("MoPub","Native ad is loading.") },200) } override fun onDestroy() { // You must call this or the ad adapter may cause a memory leak. adPlacer.destroy() super.onDestroy() } override fun onResume() { // MoPub recommends to reload ads when the user returns to a view. adPlacer.loadAds("AD_UNIT_ID") super.onResume() } }

and the adapter of our ViewPager, in this example CustomPagerAdapter:

class CustomPagerAdapter(fm: FragmentManager,streamAdPlacer: MoPubStreamAdPlacer): FragmentStatePagerAdapter(fm) { private val mStreamAdPlacer: MoPubStreamAdPlacer = streamAdPlacer private val ITEM_COUNT = 30 init{ streamAdPlacer.setItemCount(ITEM_COUNT) } override fun getItemPosition(`object`:Any):Int { // This forces all items to be recreated when invalidate() is called on the ViewPager. return POSITION_NONE } override fun getCount(): Int { return mStreamAdPlacer.getAdjustedCount(ITEM_COUNT) } override fun getItem(position: Int): Fragment { mStreamAdPlacer.placeAdsInRange(position - 5, position + 5) if (mStreamAdPlacer.isAd(position)) { return AdFragment.newInstance(position, mStreamAdPlacer) } else { return ContentFragment.newInstance(mStreamAdPlacer.getOriginalPosition(position)) } } override fun getPageTitle(position:Int):CharSequence { if (mStreamAdPlacer.isAd(position)){ return "Advertisement" }else{ return "Content Item " + mStreamAdPlacer.getOriginalPosition(position) } } }

Next, we create the Fragment that contains the ad:

class CustomPagerAdapter(fm: FragmentManager,streamAdPlacer: MoPubStreamAdPlacer): FragmentStatePagerAdapter(fm) { private val mStreamAdPlacer: MoPubStreamAdPlacer = streamAdPlacer private val ITEM_COUNT = 30 init{ streamAdPlacer.setItemCount(ITEM_COUNT) } override fun getItemPosition(`object`:Any):Int { // This forces all items to be recreated when invalidate() is called on the ViewPager. return POSITION_NONE } override fun getCount(): Int { return mStreamAdPlacer.getAdjustedCount(ITEM_COUNT) } override fun getItem(position: Int): Fragment { mStreamAdPlacer.placeAdsInRange(position - 5, position + 5) if (mStreamAdPlacer.isAd(position)) { return AdFragment.newInstance(position, mStreamAdPlacer) } else { return ContentFragment.newInstance(mStreamAdPlacer.getOriginalPosition(position)) } } override fun getPageTitle(position:Int):CharSequence { if (mStreamAdPlacer.isAd(position)){ return "Advertisement" }else{ return "Content Item " + mStreamAdPlacer.getOriginalPosition(position) } } }

..and last we create the Fragment for our content:

class CustomPagerAdapter(fm: FragmentManager,streamAdPlacer: MoPubStreamAdPlacer): FragmentStatePagerAdapter(fm) { private val mStreamAdPlacer: MoPubStreamAdPlacer = streamAdPlacer private val ITEM_COUNT = 30 init{ streamAdPlacer.setItemCount(ITEM_COUNT) } override fun getItemPosition(`object`:Any):Int { // This forces all items to be recreated when invalidate() is called on the ViewPager. return POSITION_NONE } override fun getCount(): Int { return mStreamAdPlacer.getAdjustedCount(ITEM_COUNT) } override fun getItem(position: Int): Fragment { mStreamAdPlacer.placeAdsInRange(position - 5, position + 5) if (mStreamAdPlacer.isAd(position)) { return AdFragment.newInstance(position, mStreamAdPlacer) } else { return ContentFragment.newInstance(mStreamAdPlacer.getOriginalPosition(position)) } } override fun getPageTitle(position:Int):CharSequence { if (mStreamAdPlacer.isAd(position)){ return "Advertisement" }else{ return "Content Item " + mStreamAdPlacer.getOriginalPosition(position) } } }

Native Video Ads

NOTE: MoPub doesn’t seem to allow you anymore to create ad units for Native Video ads, in their platform, but you can implement the following integrations using the MoPub Test Ad Unit: ‘02a2d288d2674ad09f3241d46a44356e‘

Native Video Ads use a different layout from the Native Ads. Instead of ImageView, they use a custom view called MediaLayout.

Right-click on the layout folder and New>Layout resource file.

… and give it the name ‘mopub_native_video_ad_view’ and press OK.

… and paste:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="match_parent" android:background="@color/colorPrimary" android:layout_height="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mopub_native_video_ad_layout"> <ImageView android:id="@+id/mopub_native_video_ad_privacy" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginTop="-5dp" android:layout_marginEnd="-5dp" android:layout_alignParentEnd="true" android:layout_alignParentTop="true" android:tint="@android:color/white" android:contentDescription="Privacy Information Icon image" android:padding="10dp" android:layout_marginRight="-5dp" android:layout_alignParentRight="true" /> <ImageView android:id="@+id/mopub_native_video_ad_icon" android:background="@null" android:scaleType="centerInside" android:layout_width="50dp" android:layout_height="50dp" android:layout_marginTop="10dp" android:layout_marginStart="10dp" android:layout_alignParentStart="true" android:layout_marginLeft="10dp" android:layout_alignParentLeft="true" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/mopub_native_video_ad_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toEndOf="@id/mopub_native_video_ad_icon" android:layout_marginStart="10dp" android:layout_toStartOf="@id/mopub_native_video_ad_privacy" android:textColor="@android:color/white" android:textStyle="bold" android:textSize="16sp" android:text="Lorem ipsum dolor sit amet, consectetur" android:layout_marginEnd="10dp" android:layout_alignTop="@id/mopub_native_video_ad_icon" android:layout_toRightOf="@id/mopub_native_video_ad_icon" android:layout_toLeftOf="@id/mopub_native_video_ad_privacy" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/mopub_native_video_ad_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/mopub_native_video_ad_title" android:layout_marginStart="12dp" android:layout_marginTop="3dp" android:layout_marginEnd="3dp" android:layout_marginBottom="2dp" android:layout_toStartOf="@+id/mopub_native_video_ad_privacy" android:layout_toEndOf="@id/mopub_native_video_ad_icon" android:lines="2" android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua" android:textColor="@android:color/white" android:textSize="14sp" android:layout_marginLeft="12dp" android:layout_marginRight="3dp" android:layout_toLeftOf="@+id/mopub_native_video_ad_privacy" android:layout_toRightOf="@id/mopub_native_video_ad_icon" /> <com.mopub.nativeads.MediaLayout android:id="@+id/mopub_native_video_ad_media_layout" android:layout_below="@id/mopub_native_video_ad_text" android:layout_margin="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>

Native Video Ads (Single View)

The only difference from the Native Ad integration is that, here, we use a ViewBinder called MediaViewBinder to serve the video inside the ad.

First, we create a FrameLayout inside our Activity/Fragment:

This FrameLayout will contain the Native Video Ad layout we created before.

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:background="@color/colorPrimary" tools:context=".NativeVideoAds.nativeVideoAd.NativeVideoAdSingleView"> <!-- Content of our Activity/Fragment --> <FrameLayout android:id="@+id/native_video_ad_frame" android:layout_width="match_parent" android:layout_height="wrap_content"/> <!-- Content of our Activity/Fragment --> </RelativeLayout>

.. and in our Kotlin class we add the following.

class NativeVideoAdSingleView : AppCompatActivity() { private lateinit var moPubNativeVideoNetworkListener: MoPubNative.MoPubNativeNetworkListener private lateinit var moPubNativeVideoEventListener: NativeAd.MoPubNativeEventListener private lateinit var moPubNativeVideo: MoPubNative private lateinit var adapterHelper: AdapterHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_native_video_ad_single_view) MyMoPub().init(this, "AD_UNIT_ID") Handler().postDelayed({ initAds() }, 200) } private fun initAds() { moPubNativeVideoEventListener = object : NativeAd.MoPubNativeEventListener{ override fun onClick(view: View?) { // Click tracking. native_video_ad_status.text = "Native video ad recorded a click." } override fun onImpression(view: View?) { // Impress is recorded - do what is needed AFTER the ad is visibly shown here. native_video_ad_status.text = "Native video ad recorded an impression." } } moPubNativeVideoNetworkListener = object : MoPubNative.MoPubNativeNetworkListener { override fun onNativeLoad(nativeAd: NativeAd?) { adapterHelper = AdapterHelper([email protected], 0, 3) val v = adapterHelper.getAdView(null, native_video_ad_frame,nativeAd,ViewBinder.Builder(0).build()) nativeAd!!.setMoPubNativeEventListener(moPubNativeVideoEventListener) native_video_ad_frame.addView(v) native_video_ad_status.text = "Native video ad has loaded." } override fun onNativeFail(errorCode: NativeErrorCode) { native_video_ad_status.text = "Native video ad failed to load with error: $errorCode" } } moPubNativeVideo = MoPubNative(this, "AD_UNIT_ID", moPubNativeVideoNetworkListener) val mediaViewBinder = MediaViewBinder.Builder(R.layout.mopub_native_video_ad_view) .mediaLayoutId(R.id.mopub_native_video_ad_media_layout) .iconImageId(R.id.mopub_native_video_ad_icon) .titleId(R.id.mopub_native_video_ad_title) .textId(R.id.mopub_native_video_ad_text) .privacyInformationIconImageId(R.id.mopub_native_video_ad_privacy) .build() val moPubVideoNativeAdRenderer = MoPubVideoNativeAdRenderer(mediaViewBinder) moPubNativeVideo.registerAdRenderer(moPubVideoNativeAdRenderer) moPubNativeVideo.makeRequest() native_video_ad_status.text = "Native video ad is loading." } override fun onDestroy() { // You must call this or the native video view may cause a memory leak. moPubNativeVideo.destroy() super.onDestroy() } }

Here, we initialize the MoPub SDK, next we create an event listener where we check if the Native Video ad got an impression or clicked, a network listener which we add the Native Video ad view in the FrameLayout of our Activity/Fragment, and at the end, we create the MediaViewBinder for our Native Video ad layout, and we send a request to get an ad from MoPub

Native Video Ads (RecyclerView)

To add Native Video Ads in a RecyclerView it’s very easy; We use exactly the same method as we did with Native Ads, we just add one more ViewBinder to support videos. MoPub also provides an adapter called MoPubRecyclerAdapter that calculates the right number of cells that we need with the ads in it.

To do that, we use the MoPubRecyclerAdapter after the normal RecyclerView.Adapter of our RecyclerView:

class NativeVideoAdRecyclerView : AppCompatActivity() { lateinit var itemsCells: ArrayList<String?> lateinit var adapter: NativeVideoAd_RVAdapter private lateinit var moPubAdapter: MoPubRecyclerAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_native_video_ad_recycler_view) MyMoPub().init(this, "AD_UNIT_ID") //** Set the data for our ArrayList setItemsData() //** Set the adapter of the RecyclerView setAdapter() //** Set the Layout Manager of the RecyclerView setRVLayoutManager() } private fun setItemsData() { itemsCells = ArrayList() for (i in 0..40) { itemsCells.add("Item $i") } } private fun setAdapter() { adapter = NativeVideoAd_RVAdapter(itemsCells) native_video_ad_rv.adapter = adapter initAds() adapter.notifyDataSetChanged() } private fun setRVLayoutManager() { val mLayoutManager = LinearLayoutManager(native_video_ad_rv.context) native_video_ad_rv.layoutManager = mLayoutManager native_video_ad_rv.setHasFixedSize(true) } private fun initAds() { moPubAdapter = MoPubRecyclerAdapter(this, adapter) val mediaViewBinder = MediaViewBinder.Builder(R.layout.mopub_native_video_ad_view) .mediaLayoutId(R.id.mopub_native_video_ad_media_layout) .iconImageId(R.id.mopub_native_video_ad_icon) .titleId(R.id.mopub_native_video_ad_title) .textId(R.id.mopub_native_video_ad_text) .privacyInformationIconImageId(R.id.mopub_native_video_ad_privacy) .build() val moPubVideoNativeAdRenderer = MoPubVideoNativeAdRenderer(mediaViewBinder) // You should still register a renderer for static native ads as well. val staticViewBinder = ViewBinder.Builder(R.layout.mopub_native_ad_view) .titleId(R.id.mopub_native_ad_title) .textId(R.id.mopub_native_ad_text) .mainImageId(R.id.mopub_native_ad_main_imageview) .iconImageId(R.id.mopub_native_ad_icon) .callToActionId(R.id.mopub_native_ad_cta) .privacyInformationIconImageId(R.id.mopub_native_ad_privacy) .build() val moPubStaticNativeAdRenderer = MoPubStaticNativeAdRenderer(staticViewBinder) moPubAdapter.registerAdRenderer(moPubStaticNativeAdRenderer) moPubAdapter.registerAdRenderer(moPubVideoNativeAdRenderer) native_video_ad_rv.adapter = moPubAdapter moPubAdapter.loadAds("AD_UNIT_ID") } override fun onDestroy() { // You must call this or the ad adapter may cause a memory leak. moPubAdapter.destroy() super.onDestroy() } }

First, we initialize the MoPub SDK, then we add the native video ads into our RecyclerView after we pass the normal adapter.

Rewarded Ads

Rewarded Ads works like the Interstital Ads, but you reward the user after having seen the video.

There’re two methods we can handle the reward, by client-side, having the app responsible to inform the user for the reward, and the server-side, where MoPub sends a callback to our server as the user completes seeing the video.

Client-side method is easier to implement because you don’t need to set up and run a callback server.

If you app is very complex, it’s recommended to use the server-side method, which is safer.

In this example, we’ll implement the client-side method. So, let’s dive into it!

First, let’s get the ad unit id from the MoPub Dashboard.

Now, let’s paste the following code in our Activity/Fragment:

class RewardedVideoAdActivity : AppCompatActivity() { private lateinit var moPubRewardedVideoListener : MoPubRewardedVideoListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_rewarded_video_ad) MyMoPub().init(this, "AD_UNIT_ID") moPubRewardedVideoListener = object : MoPubRewardedVideoListener { override fun onRewardedVideoClosed(adUnitId: String) { Log.d("MoPub","Rewarded ad has closed") } override fun onRewardedVideoCompleted(adUnitIds: MutableSet<String>, reward: MoPubReward) { //When the video ends, it triggers this callback in the background(before you press the close button) Log.d("MoPub","Rewarded ad completed and the reward is: ${reward.amount}") } override fun onRewardedVideoPlaybackError(adUnitId: String, errorCode: MoPubErrorCode) { Log.d("MoPub","Rewarded ad video playback error: $errorCode") } override fun onRewardedVideoLoadFailure(adUnitId: String, errorCode: MoPubErrorCode) { Log.d("MoPub","Rewarded ad load failed: $errorCode") } override fun onRewardedVideoClicked(adUnitId: String) { Log.d("MoPub","Rewarded ad clicked") } override fun onRewardedVideoStarted(adUnitId: String) { Log.d("MoPub","Rewarded ad has started") } override fun onRewardedVideoLoadSuccess(adUnitId: String) { Log.d("MoPub","Rewarded ad has loaded") } } MoPubRewardedVideos.setRewardedVideoListener(moPubRewardedVideoListener) load_rewarded_btn.setOnClickListener { //Start loading the Rewarded Ad MoPubRewardedVideos.loadRewardedVideo("AD_UNIT_ID") Log.d("MoPub","Rewarded ad is loading") } check_rewarded_btn.setOnClickListener { //Check if the Rewarded Ad is loaded val isAvailable = MoPubRewardedVideos.hasRewardedVideo("AD_UNIT_ID") Log.d("MoPub","Rewarded ad is available? $isAvailable") } show_rewarded_btn.setOnClickListener { //Show the Rewarded Ad MoPubRewardedVideos.showRewardedVideo("AD_UNIT_ID") } } override fun onDestroy() { MoPubRewardedVideos.setRewardedVideoListener(null) super.onDestroy() } }

We initialize the MoPub SDK, as we do every time before we display an ad on Activity/Fragment), then we create and set the listener MoPubRewardedVideoListener to listen to events, like when the rewarded ad dismissed, or when it’s completed and it’s time to reward the user.

You can find the final project here

If you have any questions, please feel free to leave a comment below