fbpx
How to add MoPub Ads in your Android app using Kotlin

How to add MoPub Ads in your Android app using Kotlin

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.

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 questionsplease feel free to leave a comment below

Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Alap Patel

Please create the same post for step by step guide on Facebook Audience Network Ads integration in the app using Kotlin.