Android SDK Integration

Android SDK for in-app advertising with Motionspots SSP

This is a free Software Development Kit for the Android application developers and publishers to monetize digital mobile inventory faster than the blink of an eye. Motionspots integrates with Motionspots SSP, one single source of offerings tailored to publishers' needs.

Table of contents

Supported Ad formats

Banner and rich media ads:

Size, DPI Type MotionspotsSDK Size Constant
320x50 Standard Banner kMotionspotsSizeBanner
320x100 Large Banner kMotionspotsSizeLargeBanner
300x250 IAB Medium Rectangle kMotionspotsSizeIABMediumRectangle
468x60 IAB Full-Size Banner kMotionspotsSizeIABFullSizeBanner
728x90 IAB Leaderboard kMotionspotsSizeIABLeaderBoard

Video ads:

Orientation: Landscape or Portrait

Native ads:

Recommended to use ListView and RecylerView

Interstitial ads:

Size, DPI Type
Custom size Full screen

Getting Started

Just a few steps to start:

  1. Register your account on Motionspots Supply Side Platform.

  2. Confirm your registration by following the confirmation link sent via email

  3. Create your first mobile inventory, it should be reviewed and approved.

  4. After this, you will be granted access to create placements for your inventory, Add Placement button should become clickable.

  5. Click on Add Placement, add the targeting options, floor price and size of your placement, then save your changes.

  6. Please note the Placement ID(e.g., ID#1234) below it's title. It will be used later in your code to initialize the ad container.

Requirements

  • Android 4.0+ (Jelly Bean, API 16) and higher. MRAID ads require API 19 and higher. Older Android versions will work, but are not officially supported. Recommended API version - 26.

  • Google Play Services - for users ad tracking preferences. For more information, please see Google's Playstore support regarding Google Advertising ID (ADID)

  • Recommended Google Play Services 11.4.0

  • android-support-v4.jar, r26

  • android-support-annotations.jar, r26

  • android-support-v7-recyclerview.jar, r26

  • Android SDK:

  • Package Minimum Version
    Android SDK Tools 23
    Android SDK Platform-tools/Build-tools 23
    Android SDK For Android modules, you need to install Android SDK 6.0.x (API 23) and SDK 6.0.0+.

Installation

  • Provide Maven dependency into your Project gradle.build:
allprojects { 
    repositories {
        jcenter()
        google()
        // Motionspots Maven dependepcies
        mavenCentral()
        mavenLocal()
        flatDir {
            dirs '../libs'
        }
        maven { url "https://jitpack.io" }
        maven { url "https://s3.amazonaws.com/moat-sdk-builds" }
        maven { url "https://dl.bintray.com/wls/motionspots/" }
    }
}
  • Include sdk dependency into your Module gradle.build:
implementation('com.motionspots:ad-container:1.0.1') {
    transitive = true
}
  • Synchronize project with Gradle files (Gradle sync)

* Important!

Enable Multidex for your app.

  • Example Multidex
    apply plugin: 'com.android.application'
    apply plugin: 'me.tatarka.retrolambda'
    android {
        compileSdkVersion 28
        buildToolsVersion "28.0.3"
        defaultConfig {
            applicationId "com.motionspots.testapplication"
            minSdkVersion 16
            targetSdkVersion 28
            versionCode 11
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            multiDexEnabled true
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    
            }
        }
        compileOptions {
            targetCompatibility JavaVersion.VERSION_1_8
            sourceCompatibility JavaVersion.VERSION_1_8
        }
        dependencies {
            compile fileTree(include: ['*.jar'], dir: 'libs')
            androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
                exclude group: 'com.android.support', module: 'support-annotations'
            })
    
            compile 'com.android.support:appcompat-v7:26.+'
            compile 'com.android.support:design:26.+'
            compile 'com.android.support:cardview-v7:26.+'
    
            testCompile 'junit:junit:4.12'
            compile 'com.android.support:multidex:1.0.3'
    
            compile('com.motionspots:ad-container:1.0.1') {
                transitive = true
            }
        }
    }

Semple Test App

You can download the application and test your creatives in it: Test App

Setup App Permissions (optional)

Edit your Android manifest to include the following (optional but recommended) permissions:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.motionspots.sampleapp">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  <!-- Grants the SDK permission to access a more accurate location based on GPS -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Grants the SDK permission to access approximate location based on cell tower -->

    <!-- your app description -->
</manifest>

Motionspots SDK already has the following normal permissions required by the SDK:

  • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>;
  • <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  • <uses-permission android:name="android.permission.INTERNET" />
  • Example AndroidManifest.xml
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.motionspots.testapplication">
    
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        <!-- required for video ads -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
        <application
            android:name="android.support.multidex.MultiDexApplication" // for MultiDex
            android:allowBackup="true"
            android:icon="@mipmap/pw_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity android:name=".AdActivity"></activity>
        </application>
    </manifest/>

Working with Android 6.0 Runtime Permissions

If your app's target SDK is 23 or higher and the user's device is running Android 6.0 or higher, you are responsible for supporting  runtime permissions , one of the  changes  introduced in Android 6.0 (API level 23). In addition to listing any dangerous permissions your app needs in the manifest, your app also has to explicitly request the dangerous permission(s) during runtime by calling method requestPermissions() in the  ActivityCompat  class.

  • Dangerous permission  ACCESS_COARSE_LOCATION is needed to pass network location data to MoPub.

  • Dangerous permission  ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION is needed to pass GPS location data to MoPub. Granting ACCESS_FINE_LOCATION also allows network location data to be passed to PW without the need to also grant ACCESS_COARSE_LOCATION.

  • Dangerous permission  WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE is optional and only required for MRAID 2.0 storePicture ads.

  • Note: The user can deny granting any dangerous permissions during runtime, so please make sure your app can handle this properly.

  • Note: The user can revoke any permissions granted previously by going to your app's Settings screen, so please make sure your app can handle this properly.

Setting up required parameters in strings.xml

Set the app distribution type(required by SDK) in your strings.xml file:

<integer name="distribution_type">{0|1}</integer>

Where:

  • 0 - app is free
  • 1 - the app is a paid version

Now, add the banner_placement_id to strings.xml

<string name="banner_placement_id">{your_banner_placement_id_here}</string>

Important!

Do not forget to replace the your_banner_placement_id_here with the placement ID from the Platform

<string name="banner_placement_id">{1234}</string>

Initializing Motionspots SDK

Call com.motionspots.Ads#init(Context) method as shown below:

Recommend to invoke this initialization routine at least 10-15 seconds before you intend to load your first ad.

Ads.init(getApplicationContext());
Ads.init(baseContext)

Setting GDPR (Requirement)

To make your Android SDK GDPR compliant please set one of the following options:

- SdkConfig.GDPRconsentflag(boolean flag) - set a new value for GDPR user consent. GDPR user consent is a boolean value, where true = user consent given & false = user consent denied or no information provided.

- SdkConfig.getGdprConsentFlag() - get current GDPR value.

SdkConfig.GDPRconsentflag(true);
boolean currentGdprFlag = SdkConfig.getGdprConsentFlag();
SdkConfig.GDPRconsentflag(true)
val currentGdprFlag  = SdkConfig.getGdprConsentFlag();

Show Banners

You can configure your banner ad view using XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:motionspots="http://schemas.android.com/apk/res-auto">

   <com.motionspots.adcontainer.BannerContainer
        android:id="@+id/banner_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        motionspots:adContainerId="@string/banner_id"
        motionspots:banner_width="300dp"
        motionspots:banner_height="250dp"
        motionspots:refreshTime="20"
        />

</LinearLayout>

Where

  • motionspots:adContainerId="@string/banner_id" - the placement ID you received
  • motionspots:banner_width="300dp" - placement width
  • motionspots:banner_height="250dp" - placement height
  • motionspots:refreshTime="20" - Optional. Time in seconds after which the banner will expire and will be reloaded automatically. By default 20 sec.

Make sure that xmlns:motionspots="http://schemas.android.com/apk/res-auto" was added to your root layout

Finally, call BannerContainer#loadAd()

There is an alternative method BannerContainer#loadAd(BannerOnLoadListener) that would be useful if you want to create request parameters programmatically.

Show Interstitial

To show interstitial you just need to initialize ad container and call InterstitialAdContainer#loadAd(BannerOnLoadListener) method as shown in example below

private InterstitialAdContainer interstitial;

interstitial = new InterstitialAdContainer(this, getString(R.string.interstitial_placement_id));
interstitial.loadAd(new InterstitialListener() {
    @Override
    public void onSuccess() {
        Log.e("YOUR_TAG", "Ad loaded");
    }

    @Override
    public void onFailure(Exception e) {
        Log.e("YOUR_TAG", "Cannot load interstitial, reason: " + e.getMessage());
    }

    @Override
    public void onClosed() {
        Log.d("YOUR_TAG", "Interstitial closed");
    }
});
lateinit var interstitialAdContainer: InterstitialAdContainer	

interstitialAdContainer = InterstitialAdContainer(this,  getString(R.string.interstitial_placement_id))

interstitialAdContainer.loadAd(object : InterstitialListener {
    override fun onClosed() {
        Log.d("TAG", "interstitialAdContainer : Closed")
    }
    
    override fun onSuccess() {
        Log.d("TAG", "interstitialAdContainer : onSuccess")
    }
    
    override fun onFailure(p0: Exception?) {
        p0?.printStackTrace()
        Log.d("TAG", "interstitialAdContainer : onFailure " + p0)
    }
})

Show Vast(Video ad)

Update your AndroidManifest.xml with new permission WRITE_EXTERNAL_STORAGE

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.motionspots.sampleapp">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Required. Allows an application to write to external storage. -->

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  <!-- Optional. Grants the SDK permission to access a more accurate location based on GPS -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Optional. Grants the SDK permission to access approximate location based on cell tower -->

    <!-- your app description -->
</manifest>

The usage of VideoContainer exactly the same as the usage of InterstitialAdContainer):

private VideoContainer videoContainer;
videoContainer = new VideoContainer(this, getString(R.string.video_placement_id));
videoContainer.loadAd(new InterstitialListener() {
    @Override
    public void onSuccess() {
        Log.e("YOUR_TAG", "Ad loaded");
    }

    @Override
    public void onFailure(Exception e) {
        Log.e("YOUR_TAG", "Cannot load video, reason: " + e.getMessage());
    }

    @Override
    public void onClosed() {
        Log.d("YOUR_TAG", "Video closed");
    }
});
lateinit var videoContainer: VideoContainer

videoContainer = VideoContainer(this, getString(R.string.video_placement_id))

videoContainer.loadAd(object : InterstitialListener {
    override fun onClosed() {
	Log.d("TAG", "videoContainer : Closed")
    }

    override fun onSuccess() {
	Log.d("TAG", "videoContainer : onSuccess")
    }

    override fun onFailure(p0: Exception?) {
	p0?.printStackTrace()
	Log.d("TAG", "videoContainer : onFailure " + p0)
    }
})

Show Native

To show native you just need to initialize ad container through Builder and call NativeAdContainer#loadAd(loadListener) method as shown in example below. You should give to a Builder all fields that you specified while creating native placement on Motionspots Supply Side Platform.

NativeAdContainer native = NativeAdContainer.Builder(getContext(),
  getContext().getString(R.string.native_placement_id))
  .setTitleView(myTitleView)
  .setDescriptionView(myDescriptionView)
  .setSponsoredTextView(mySponsoredTextView)
  .setPriceView(myPriceView)
  .setImageView(myImageView)
  .setCtaView(myActionButton)
  // Another specified fields
  .build();
  
native.loadAd(new NativeOnLoadListener() {
  @Override public void onSuccess() {
    switchLoadingState(false);
    showResult("success");
  }

  @Override public void onFailure(Exception e) {
    switchLoadingState(false);
    showResult("Failure: " + e.getMessage());
  }
});
lateinit var nativeAdContainer: NativeAdContainer
nativeAdContainer = NativeAdContainer.Builder(nativeAdContainer)
  .setTitleView(myTitleView)
  .setDescriptionView(myDescriptionView)
  .setSponsoredTextView(mySponsoredTextView)
  .setPriceView(myPriceView)
  .setImageView(myImageView)
  .setCtaView(myActionButton)
  // Another specified fields
  .build();

nativeAdContainer.loadAd(object : NativeOnLoadListener{
    override fun onSuccess() {
        Log.d("TAG", "nativeAdContainer : onSuccess")
    }

    override fun onFailure(p0: Exception?) {
        Log.d("TAG", "nativeAdContainer : onFailure: " + p0)
    }

})

where R.string.native_placement_id - your native placement id(see #important)

Adding targeting params

Targeting params are data that are provided for the SDK that will improve ad targeting. The params are not required and can be provided if your application has such data. There are three targeting parameters types:

  • Gender: male, female, other - user gender
  • Year of birth - year of a user birthday
  • Keywords - user interests or intents

Usage:

UserKeywords userKeywords = new UserKeywords()
                .addKeywords("interest 1", "interest 2")
                .addKeywords(Collections.singletonList("interest 3"));

interstitialAdContainer.addTargetingData(Gender.MALE)
        .addTargetingData(new YearOfBirth(1990))
        .addTargetingData(userKeywords);
val userKeywords = UserKeywords()
        .addKeywords("interest 1", "interest 2")
        .addKeywords(Collections.singletonList("interest 3"))

interstitialAdContainer.addTargetingData(Gender.MALE)
        .addTargetingData(YearOfBirth(1990))
        .addTargetingData(userKeywords);

Rendering Problems in Android Studio

In case you got rendering problems(VerifyError) in Preview mode, add -noverify VM option to Android Studio:

  • Menu Help -> Edit Custom VM Options...
  • Add -noverify key
  • Restart Android Studio