Advertising SDK Standard Android
Android Ads SDK (from now on SDK) is the tool that helps monetize advertising inventory in Android applications. SDK requests and display advertisement creatives in the host's app.
SDK provides the ability to download and display the following types of ad creatives in your application:
Banners:
HTML Banner (HTML advertising content) - HTML-markup banners are embedded inside the
CreativeView
hierarchy. For serving HTML, SDK usesandroid.webkit.WebView
under the hood (built-in browser engine), which renders and displays HTML code.Image Banner - advertising content presented as links on pictures. SDK operates by these links on the pictures to render advertising content.
Media Banner (video, audio) - media advertising content based on VAST specifications.
For more information, see the section Display banner advertising.
Product:
- Product Creative is a particular type of advertising creative for RetailMedia platforms, using SKU product identifiers in the RetailMedia platform.
For more information, see the section Display product creative.
Before you start
You should know the following parameters required for initialization and use of SDK. Ask the SDK team to give them to you.
- bannerUrl - URL for banner creatives (HTML Banner, Image Banner, Media Banner). Eg:
"https://my.server.com/banner_creative"
. - productUrl - URL for product creative. Eg:
"https://my.server.com/product_creative"
.
SDK version:
Demo: Advertising SDK Example
Stable release: Advertising SDK Standard
Requirements
- Kotlin version >= 1.6.20
- Android 5.0+ (API Level >= 21)
Installation
Import Gradle dependency.
To use Android Ads SDK you need to install a dependency in your application’s Gradle file:
dependencies {
//... other dependencies
implementation 'com.github.solutionarchitectstech:mobile_sdk_release:{{ version }}'
//... other dependencies
}
SDK initialization
In order to initialize the SDK and create of ad placements by the developer should call TechAdvetrising.init()
method at the time of the application launch or at the moment of user authorization.
You must provide initConfig
or remoteConfigUrl
in the params, but if you submit both, then initConfig
will have higher priority.
IMPORTANT
SDK only has access to the main application process. If your appliation uses several processes, you need to register content provider to extract the ApplicationContext
:
<application>
<provider
android:name=".AdvertisingSDKContextProvider"
android:authorities="${applicationId}.AdvertisingSDKContextProvider"
android:exported="true" />
</application>
// If you want to use internal 'CUSTOM' protocol in the SDK.
TechAdvertising.init(
storeUrl = "https://play.google.com/store/apps/details?id=com.myapp",
sessionId = "YOUR_SESSION_ID",
initConfig = InitConfig(
core = CoreDestination(
bannerUrl = "https://YOUR_BANNER_CREATIVE_ENDPOINT",
productUrl = "https://YOUR_PRODUCT_CREATIVE_ENDPOINT"
),
),
headers = mapOf("Authorization" to {
"Bearer CUSTOM_AUTH_TOKEN"
}),
debugMode = true,
)
// Here is an example, if you want to use 'OpenRTB' protocol.
TechAdvertising.init(
storeUrl = "https://play.google.com/store/apps/details?id=com.myapp",
sessionId = "YOUR_SESSION_ID",
transactionProtocol = TransactionProtocol.OPEN_RTB,
publisherId = "YOUR_PUBLISHER_ID", // Optional, set this up here if you have it
appContentType = RTBContext.OTHER, // Optional
appContentProductionQuality = RTBProductionQuality.PROFESSIONALLY_PRODUCED, // Optional
appContentMediaRating = RTBMediaRating.ALL_AUDIENCES, // Optional
initConfig = InitConfig(
core = CoreDestination(
bannerUrl = "https://YOUR_OPENRTB_ENDPOINT",
),
),
headers = mapOf(
"Authorization" to { "Bearer YOUR_AUTH_TOKEN" },
"User-Agent" to { "YOUR_CUSTOM_USER_AGENT" }
),
debugMode = true
)
// If you already have your authorized user id here, then keep the following line enabled.
// Otherwise, remove it here and follow recommendations in the 'User (UID)' chapter below.
TechAdvertising.uid = "YOUR_AUTHORIZED_USER_ID"
TechAdvertising.init(
storeUrl: String,
sessionId: String,
transactionProtocol: TransactionProtocol = TransactionProtocol.CUSTOM,
publisherId: String? = null,
appContentType: RTBContext? = null,
appContentProductionQuality: RTBProductionQuality? = null,
appContentMediaRating: RTBMediaRating? = null,
debugMode: Boolean = false,
headers: Map<String, () -> String>? = null,
initConfig: InitConfig? = null,
remoteConfigUrl: String? = null
)
public class TechAdvertising {
public companion object {
public var uid: String? = null
}
}
storeUrl
- link to the app in the app store.sessionId
- Unique session id determining the current application session. There are types of mobile apps:- Online app (your application uses your business backend) - in this case, please provide the session id, which matches the server-side session of your backend - this is the preferable way.
- Offline app (your mobile doesn't use its business backend). If your app doesn't use the backend, then your mobile app can pass generated
UUID
value here. IMPORTANT: yourUUID
must be generated once on each first application startup. You must never re-generate it during the application lifecycle. Only if your app is terminated (removed from memory) and re-started again, only this triggers a newUUID
value.
transactionProtocol
- Ad transaction protocol (with specific options inside). This option determines the "Layer-3 Transaction" of AdCOM v1.0. SDK supports the following transaction protocols:CUSTOM
- Internal custom protocol (used by default).OPEN_RTB
- OpenRTB 2.6
publisherId
- (optional) Unique identifier of publisher.appContentType
- (optional) Type of your application content (game, video, text, etc.). Refer to List: Content Contexts in AdCOM 1.0.appContentProductionQuality
- (optional) Production quality (spcific for your application content). Refer to List: Production Qualities in AdCOM 1.0.appContentMediaRating
- (optional) Media rating per IQG guidelines (specific for your application content). Refer to List: Media Ratings in AdCOM 1.0.debugMode
- flag that enables logging of debug messages in application. Defaultfalse
.headers
- (optional) dictionary that forms specific HTTP headers.initConfig
- (optional) local config provides URLs for each type of ad (see. InitConfig)remoteConfigUrl
- (optional) URL to configuration server API. An example of API response in JSON format:JSON{ "core": { "bannerUrl": "https://my.server.com/banner_creative", "productUrl": "https://my.server.com/product_creative" } }
TechAdvertising.uid
- (optional) - see our recommendations (when to set / clean this value) in the section User ID (UID) below.
User ID (UID)
Your mobile application might be:
- Anonymous (public - no user based authorization at all). For example: any user can use whole functionality of your app without needs to register own user account. Public (anonymous) usage.
- AuthN/AuthZ based (user based authorization required). For example: Sign-in screen on startup.
- Mixed app (some screens of your app are publicly available for anyone, but other ones are only available for authorized users). For example: Anyone (without user account) can navigate between catalog / products screens. But if user tries to 'Add to cart' or 'To make an order', then application asks user to pass authorization (Sign-in / Sign-up).
IMPORTANT
Advertising SDK provides TechAdvertising.uid
property. Please, setup this property with 'user id' value of your real authorized user.
You have to set this property on each successful 'Sign-in' attempt.
You can skip setup of this property only in one scenario: if your mobile is Anonymous and never uses user authorization.
Here is an example how to set TechAdvertising.uid
property:
try {
val authSession = myAuthService.signIn(username, password)
if (!authSession.success) {
TechAdvertising.uid = null
return
}
TechAdvertising.uid = authSession.user.id
// Here, you do your own business logic specific for your mobile app
// after user passes authorization.
// Eg: navigate to 'Main' screen, or navigate to 'Cart' screen, etc ...
} catch (e: Exception) {
TechAdvertising.uid = null
Log.e(TAG, "ERROR: Unable to sign-in due error", e)
}
public object TechAdvertising : CommonAdvertising() {
public var uid: String? = null
}
uid
- (optional) Unique user ID, authorized in your mobile app.
Display banner
Our SDK provides the following types of banner creatives:
HTML Banner
This is an advertising creative that uses HTML content for advertising. SDK uses HTML rendering mechanisms to display this type of creatives (android.webkit.WebView
). This implementation implies that an HTML page is added to the CreativeView
hierarchy, the advertising content. For example, as a banner, you can display a form questionnaire for users with controls, visual effects, and additional logic that can be performed using JavaScript.
Image Banner
This is an advertising creative that uses a picture file to display advertisements. It is an easy-to-use version of a banner for displaying advertising content in the form of a simple picture, which entails more incredible performance when displaying advertising and less delay on rendering content.
Media Banner (video, audio)
This creative is an advertising creative that uses VAST specifications underhood to display media content as an advertisements.
To request and display ads, do the following steps:
- Add
CreativeView
to yourlayout
:
...
<tech.solutionarchitects.advertisingsdk.creative.presentation.CreativeView
android:id="@+id/creativeView"
android:layout_width="YOUR_WIDTH_DP"
android:layout_height="YOUR_HEIGHT_DP" />
...
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.my_activity)
val root = findViewById<ViewGroup>(R.id.root)
val creativeView = CreativeView(this)
// Optionally, you can enable or disable adaptive UI using the following property.
// This option fits banner content to aspect ratio of your `CreativeView` frame.
// 'true' is used by default.
creativeView.scaleToFit = true
// Optionally, you can enable or disable vertical and horizontal scrolling of HTML content
// inside of `CreativeView` frame.
// Eg: if you use complex HTML content as a banner creative, but your app UI doesn't provide enough
// frame size to show whole HTML content. So, you can enable this option to give capability to
// your users to scroll the HTML content to see it.
// 'false' is used by default.
creativeView.isScrollEnabled = false
val viewWidth = ...
val viewHeight = ...
val layoutParams = ViewGroup.LayoutParams(viewWidth, viewHeight)
creativeView.layoutParams = layoutParams
root.addView(creativeView)
}
}
- Configure advertisement parameters for
CreativeView
using CreativeQuery:
// If you use internal 'CUSTOM' protocol then use the following creative query
creativeView.query = CreativeQuery(
// NOTICE: Placement ID is required for 'CUSTOM' protocol
placementId = "YOUR_PLACEMENT_ID",
sizes = listOf(Size(width = 260, height = 106)),
floorPrice = 2.0,
currency = "RUB",
customParams = mapOf(
"property1" to "value1",
"property2" to "value2"
)
)
// If 'OpenRTB' protocol then this example
creativeView.query = CreativeQuery(
// NOTICE: there is no `placementId` needed if 'OpenRTB' protocol is used.
sizes = listOf(Size(width = 260, height = 106)),
// NOTICE: `markupType` is recommended if you use 'OpenRTB' protocol.
// Set this up as `.BANNER`, `.VIDEO`, `.AUDIO` or `.NATIVE` in your request query.
markupType = MarkupType.BANNER,
floorPrice = 2.0,
currency = "RUB",
customParams = mapOf(
"property1" to "value1",
"property2" to "value2"
)
)
- Create Creative to control banner.
val creative = Creative(
lifecycle = lifecycle,
creativeView = creativeView,
listener = object : CreativeEventListener {
override fun onLoadDataSuccess(creativeView: CreativeView) {
// Handle success (banner request executed successfully)
}
override fun onLoadDataFail(creativeView: CreativeView, throwable: Throwable?) {
// Handle an error while banner request in progress
}
override fun onLoadContentSuccess(creativeView: CreativeView) {
// Handle success (banner content loaded successfully)
}
override fun onLoadContentFail(creativeView: CreativeView, throwable: Throwable?) {
// Handle an error while banner content loaded
}
override fun onNoAdContent(creativeView: CreativeView) {
// Server returns 204-NoContent response
}
override fun onClose(creativeView: CreativeView) {
// Banner has been closed (eg: user pressed the close button of the banner)
}
}
)
- Call
load
of Creative to load advertisement
creative.load()
Display dynamic collections
If you wish to use dynamic lists of banners, based on androidx.recyclerview.widget.RecyclerView
and adapter, extended from RecyclerView.Adapter
, then please see our example code (use it as a template in your solution): CreativeRecyclerViewActivity.kt
This helps you:
- To avoid banner loading if user has not scrolled to necessary banner yet.
- To get smoothness UI effect of scrolling.
- To minimize memory-leak risks.
Display product creative
Product Banner is a special type of advertising creative for RetailMedia platforms, which uses the SKU product identifier in the RetailMedia platform. In this case, SDK does not render advertising content or perform tracking and landing page navigation functions. In the case of this advertising creative, it is the responsibility zone of the host developer. Having received a response from SDK with a list of creatives and their SKU, the developer forms a display of advertising content based on existing pictures of products in the platform on these SKUs, according to the internal templates and styles, providing a call for the necessary tracking of events.
val productCreative = ProductCreative(
query = ProductCreativeQuery(
placementId = "YOUR_PLACEMENT_ID",
customParams = mapOf(
"property1" to "value1",
"property2" to "value2"
)
),
listener = object : ProductCreativeEventListener {
override fun onLoadDataSuccess() {
// Handle success (product request executed successfully)
}
override fun onLoadDataFail(throwable: Throwable) {
// Handle an error while product request in progress
}
override fun onLoadContentSuccess(entity: ProductCreativeEntity) {
// Handle success (product content loaded successfully)
}
override fun onLoadContentFail(query: ProductCreativeQuery, throwable: Throwable?) {
// Handle an error while product content loaded
}
override fun onNoAdContent(query: ProductCreativeQuery) {
// Server returns 204-NoContent response
}
}
)
productCreative.load()
load(path: String = "")
- main method to load creative.path
- path of your URL, that will concatenate with url from InitConfig orremoteConfig
. Default""
.
query
- description of requested product creative (see ProductCreativeQuery)listener
- product loading event handler (see ProductCreativeEventListener)
Helpers
InitConfig
Local config that contains urls for each type of advertisement
public data class InitConfig(
val core: CoreDestination = CoreDestination(),
)
core
- URl-config for common ad creatives (see CoreDestination)
CoreDestination
URl-config for common ad creatives
public data class CoreDestination(
val bannerUrl: String = "",
val productUrl: String = ""
)
bannerUrl
- URL for banner creative request. Default""
.productUrl
- URL for product creative request. Default""
.
CreativeView
View container which used to display retrieved advertisement inside (HTML Banner, Image Banner, Media Banner). All internal UI hierarchy is constructed automatically by our SDK based on obtained (from server) creative type.
public class CreativeView(
context: Context,
attrs: AttributeSet? = null,
) : FrameLayout(context, attrs) {
public var query: CreativeQuery? = null
public var scaleToFit: Boolean = true
public var isScrollEnabled: Boolean = false
public var isFullscreenEnabled: Boolean = false
}
query
- (optional) Banner creative query. Set this up before you start banner loading. If you keep this parameter asnull
then Creative controller ignores such banner view while banner loading. See more details in the CreativeQuery.scaleToFit
- Enable / disable adaptive UI. This option fits banner content to aspect ratio of yourCreativeView
frame. Defaulttrue
.isScrollEnabled
- Enable / disable vertical and horizontal scrolling of HTML content inside ofCreativeView
frame. Defaultfalse
. Eg: if you use complex HTML content as a banner creative, but your app UI doesn't provide enough frame size to show whole HTML content. So, you can enable this option to give capability to your users to scroll the HTML content to see it.isFullscreenEnabled
- Enable / disable to show banner creative in modal fullscreen mode. Defaultfalse
.
Creative
Controller for banner
public class Creative {
public constructor(
lifecycle: Lifecycle,
creativeView: CreativeView,
listener: CreativeEventListener
) : this(lifecycle, listOf(creativeView), listener)
public constructor(
lifecycle: Lifecycle,
creativeViews: List<CreativeView>,
listener: CreativeEventListener
)
public fun load(path: String? = null)
}
load(path: String? = null)
- method to load banners.path
- (optional) substring, merged with URL fromInitConfig
or with configuration server response byremoteConfigUrl
.
lifecycle
- Lifecycle your Activity or Fragment.creativeView
-CreativeView
container, used to display retrieved banner content.creativeViews
- list ofCreativeView
containers to load creatives with a single request using Multi Impression technology.listener
- handler of creatives events CreativeEventListener.
INFO
Multi Impression is a functionality that allows you to request ads for a list of banners with one single request. This saves battery power and Internet traffic
WARNING
Multi Impression - is still under development. We do not recommend it for PRODUCTION code.
CreativeEventListener
Callback listener to handle events while banner creative lifecycle.
public interface CreativeEventListener {
public fun onLoadDataSuccess(creativeView: CreativeView)
public fun onLoadDataFail(creativeView: CreativeView, throwable: Throwable?)
public fun onLoadContentSuccess(creativeView: CreativeView)
public fun onLoadContentFail(creativeView: CreativeView, throwable: Throwable?)
public fun onNoAdContent(creativeView: CreativeView)
public fun onClose(creativeView: CreativeView)
}
onLoadDataSuccess
- a request to the ad server returned creative data;onLoadDataFail
- an error when requesting the ad server;onLoadContentSuccess
- the creative was successfully loaded;onLoadContentFail
- error while loading the creatives;onNoAdContent
- server returned 204 HTTP code;onClose
- banner has been closed (eg: user pressed the close button of the banner);
CreativeQuery
Query criteria to request banner creative.
@Parcelize
public data class CreativeQuery(
var placementId: String = "",
val sizes: List<Size>,
val markupType: MarkupType? = null,
val floorPrice: Double? = null,
val currency: String? = null,
val customParams: Map<String, String>? = null,
) : Parcelable
placementId
- ID of the ad slot. Set this up in your query if you use 'CUSTOM' protocol in the SDK initialization. Eg:123456
. Skip it (don't set it) if you use 'OpenRTB' protocol.sizes
- list of valid sizes for the banner. Eg:listOf(Size(300,250))
.markupType
- (optional) Type of the creative markup (.BANNER
,.VIDEO
,.AUDIO
,.NATIVE
). This property is recommended if you use 'OpenRTB' protocol. Here you specify what kind of creative you expect to receive from a server.floorPrice
- (optional) minimal show price.currency
- (optional) currency of payment.customParams
- (optional) custom parameters to add to banner request. NOTICE: JSON-compatible object must be passed only, otherwise runtime error (onLoadDataFail()
). Eg:kotlincustomParams = mapOf( "sku" to mapOf( "id" to "LG00001", "name" to "Lego bricks (speed boat)", "extra" to mapOf( "variances" to listOf("Medium", "Electrical"), "points" to 33.20 ) ), "categories" to listOf("Kids", "SpecialOffer", "2025"), "gdprConsent" to "CPsmEWIPsmEWIABAMBFRACBsABEAAAAgEIYgACJAAYiAAA.QRXwAgAAgivA", "ccpa" to "1YNN", "coppa" to 1, "discount" to 0.20, "contacts" to listOf( mapOf( "name" to "John Doe", "email" to "john.doe@mail.me" ), null, mapOf( "name" to "Jane Groovy", "email" to "jane.groovy@mail.me" ), ) )
Size
Size
object describing the size of an ad placement. When initialized takes two integers corresponding to the width and height of an ad placemnt in pixels.
class Size(val width: Int, val height: Int) {...}
width
- Width in pixels. Eg:300
height
- Height in pixels. Eg:250
Size(width = 300, height = 250)
ProductCreative
Controller to load (to manage) product creatives.
public class ProductCreative {
public constructor(
query: ProductCreativeQuery,
listener: ProductCreativeEventListener
)
public constructor(
queries: List<ProductCreativeQuery>,
listener: ProductCreativeEventListener
)
public fun load(path: String = "")
}
load(path: String = "")
- method to load product creatives.path
- substring merged with URL fromInitConfig
or with configuration server response byremoteConfigUrl
. Default""
.
query
- description of the requested creative ProductCreativeQuery.queries
- list of requested creatives ProductCreativeQuery.listener
- handler of creative events ProductCreativeEventListener.
INFO
Multi Impression is a functionality that allows you to query multiple product creatives with one single request. This saves battery and internet traffic.
WARNING
Multi Impression - is under development. We do not recommend to use it with PRODUCTION code.
ProductCreativeQuery
Query criteria of requested product creative.
public data class ProductCreativeQuery(
val placementId: String,
val customParams: Map<String, String>? = null,
)
placementId
- ID of the ad slot. Eg:123456
.customParams
- (optional) custom parameters to add to banner request. NOTICE: JSON-compatible object must be passed only, otherwise runtime error (onLoadDataFail()
). Eg:kotlincustomParams = mapOf( "sku" to mapOf( "id" to "LG00001", "name" to "Lego bricks (speed boat)", "extra" to mapOf( "variances" to listOf("Medium", "Electrical"), "points" to 33.20 ) ), "categories" to listOf("Kids", "SpecialOffer", "2025"), "gdprConsent" to "CPsmEWIPsmEWIABAMBFRACBsABEAAAAgEIYgACJAAYiAAA.QRXwAgAAgivA", "ccpa" to "1YNN", "coppa" to 1, "discount" to 0.20, "contacts" to listOf( mapOf( "name" to "John Doe", "email" to "john.doe@mail.me" ), null, mapOf( "name" to "Jane Groovy", "email" to "jane.groovy@mail.me" ), ) )
ProductCreativeEventListener
Callback listener to handle events while product creative lifecycle.
public interface ProductCreativeEventListener {
public fun onLoadDataSuccess()
public fun onLoadDataFail(throwable: Throwable)
public fun onLoadContentSuccess(entity: ProductCreativeEntity)
public fun onLoadContentFail(query: ProductCreativeQuery, throwable: Throwable?)
public fun onNoAdContent(query: ProductCreativeQuery)
}
onLoadDataSuccess
- successful request to the server;onLoadDataFail
- the server returned an error;onLoadContentSuccess
- ProductCreativeEntity found by the givenquery
(product content loaded successfully);onLoadContentFail
- an error occurred while product content loaded;onNoAdContent
- server returned 204 HTTP code;
ProductCreativeEntity
data class ProductCreativeEntity(
val requestId: String,
val placementId: String,
val sku: String,
val disclaimer: String?,
val externalId: String,
val tracking: ProductCreativeTrackingEntity?,
val advertiser: String?
)
requestId
- id of request.placementId
- ID of the ad slot. Eg:123456
.sku
- unique product identifier.disclaimer
- (optional) written disclaimer or disclaimer of liability when publishing advertising content.externalId
- external unique ad identifier.tracking
- (optional) object containing URLs for event tracking ProductCreativeTrackingEntity.advertiser
- (optional) advertiser that provide ad source.
ProductCreativeTrackingEntity
Object represents tracking urls of requested product creative. Which must be invoked on your mobile app side.
data class ProductCreativeTrackingEntity(
val click: List<String>,
val impression: List<String>,
val view: List<String>
)
click
- list of urls to track click on ads.impression
- list of urls to track impression of ads.view
- list of urls to track viewability of ads.