Native
Native ad is a flexible type of advertising. You can adapt the display to your UI by preparing a template.
Appodeal provides 4 options to implement the layout of native ads 3 templates + your custom
implementation
All of them are inherited from the same NativeAdView
class.
NativeAdView
consists of the following components:
NativeIconView
- Icon of the native ad.AdAttributionView
- Advertising Indicator. This is a TextView labeled "Ad".TitleVIew
- Title of the native ad.DescriptionView
- Text descriptionView of the native ad.RatingBarView
- Rating of the app in [0-5] range.NativeMediaView
- Media content of the native ad.CallToActionView
- Button for click.AdChoiceView
- Special ad icon provided by ad network.
Templates implementation:
To display them, all you need to do is:
- Create programmatically or in your layout file one of View template classes
Native template views classes:
NativeAdViewNewsFeed
NativeAdViewAppWall
NativeAdViewContentStream
NativeAdView for custom implementation:
To display it, all you need to do is:
- Create a
NativeAdVIew
class programmatically or in your layout file - Inside the created
NativeAdView
, arrange all theView
/IconView
/MediaView
you need for displaying it in any style you prefer - Bind programmatically or in your layout file all necessary
View
/IconView
/MediaView
.
Native view for a Custom Implementation:
NativeAdView
You can use our demo app as a reference project.
Native Demo
Integration guide
- For templates
- For custom layout
- Create programmatically or in your layout file one of View template classes:
- XML
- Kotlin
- Java
<com.appodeal.ads.nativead.NativeAdViewNewsFeed
android:id="@+id/native_news_feed"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.appodeal.ads.nativead.NativeAdViewAppWall
android:id="@+id/native_app_wall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.appodeal.ads.nativead.NativeAdViewContentStream
android:id="@+id/native_content_stream"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
val newsFeedView = NativeAdViewNewsFeed(context)
val appWallView = NativeAdViewAppWall(context)
val contentStreamView = NativeAdViewContentStream(context)
NativeAdViewNewsFeed newsFeedView = new NativeAdViewNewsFeed(context);
NativeAdViewAppWall appWallView = new NativeAdViewAppWall(context);
NativeAdViewContentStream contentStreamView = new NativeAdViewContentStream(context);
- Get a view instance from layout OR add a programmatically created ViewTemplate to your View hierarchy:
- Kotlin
- Java
val newsFeedView = findViewById<NativeAdViewNewsFeed>(R.id.native_news_feed);
val appWallView = findViewById<NativeAdViewAppWall>(R.id.native_app_wall);
val contentStreamView = findViewById<NativeAdViewContentStream>(R.id.native_content_stream);
rootView.addView(newsFeedView)
rootView.addView(appWallView)
rootView.addView(contentStreamView)
NativeAdViewNewsFeed newsFeedView = findViewById(R.id.native_news_feed);
NativeAdViewAppWall appWallView = findViewById(R.id.native_app_wall);
NativeAdViewContentStream contentStreamView = findViewById(R.id.native_content_stream);
rootView.addView(newsFeedView);
rootView.addView(appWallView);
rootView.addView(contentStreamView);
- When the NativeAd is loaded just register it
- For single NativeAd
- For several NativeAd instances
- Kotlin
- Java
if (Appodeal.isLoaded(Appodeal.NATIVE)) {
newsFeedView.registerView(Appodeal.getNativeAdCount(1))
}
if (Appodeal.isLoaded(Appodeal.NATIVE)) {
newsFeedView.registerView(Appodeal.getNativeAdCount(1));
}
- Kotlin
- Java
val needToShow = 3
if (Appodeal.getAvailableNativeAdsCount() >= needToShow) {
val nativeAds = Appodeal.getNativeAdCount(needToShow)
newsFeedView.registerView(nativeAds[0])
appWallView.registerView(nativeAds[1])
contentStreamView.registerView(nativeAds[2])
}
int needToShow = 3;
if (Appodeal.getAvailableNativeAdsCount() >= needToShow) {
List<NativeAd> nativeAds = Appodeal.getNativeAdCount(needToShow);
newsFeedView.registerView(nativeAds.get(0));
appWallView.registerView(nativeAds.get(1));
contentStreamView.registerView(nativeAds.get(2);
}
- When the display has been terminated and you no longer plan to use the NativeAdView, you should call the destroy method:
- Kotlin
- Java
nativeAdView.destroy()
nativeAdView.destroy();
General requirements:
NativeAdView
must have min height as 32dp;NativeMediaView
must have mim size as 120dp x 120dp;- The
AdAttributionView
must clearly mark your nativeAd as "Ad" so that users don't mistake them for content; - You are allowed to scale the
NativeIconView
orNativeMediaView
down without modifying the aspect ratio; - You are allowed to crop the
NativeIconView
orNativeMediaView
symmetrically by up to 20% in only one dimension (height or width).
- Create your markdown with NativeAdView as root:
You can build a layout with any style, arrangement of elements and with any type of
ViewGroup
(ConstrainLayout
, RelativeLayout
, FrameLayout
)
<?xml version="1.0" encoding="utf-8"?>
<com.appodeal.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nativeAdView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:adChoicePosition="end_top"
app:callToActionViewId="@id/callToActionView"
app:descriptionViewId="@id/descriptionView"
app:iconViewId="@id/iconView"
app:mediaViewId="@id/mediaView"
app:ratingViewId="@id/ratingView"
app:titleViewId="@id/titleView"
app:adAttributionViewId="@+id/ad_attribution">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.appodeal.ads.nativead.NativeIconView
android:id="@+id/iconView"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_gravity="center_vertical"
android:layout_margin="5dp" />
<TextView
android:id="@+id/ad_attribution"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:background="@color/red" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/titleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="@+id/descriptionView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="3" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="horizontal">
<RatingBar
android:id="@+id/ratingView"
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<Button
android:id="@+id/callToActionView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="30dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<com.appodeal.ads.nativead.NativeMediaView
android:id="@+id/mediaView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.appodeal.ads.nativead.NativeAdView>
Requirements for NativeAdView
elements
Name of view | Type | Mandatory | Description |
---|---|---|---|
titleView | TextView | Mandatory | Title of the native ad. Maximum 25 symbols of the title should always be displayed. You can add ellipsis at the end if the title is longer. |
callToActionView | Button | Mandatory | Call-to-action button. Should be displayed without truncation on a visible button. |
descriptionView | TextView | Optional | Text description of the native ad. If you choose to display the description, you should display maximum 100 characters. You can add ellipsis at the end. |
ratingView | RatingBar | Optional | Rating of the app in [0-5] range |
adAttributionView | TextView | Mandatory | Advertising Indicator. This is a TextView labeled "Ad". You can specify the color of the text and background. See adAttribution settings. You can place it anywhere inside the NativeAdView . |
adChoicesView | ViewGroup | Attach automatically | Special ad icon provided by ad network. If SDK received AdChoice from ad network, it attached it automatically. You can specify a position in one of the corners of the NativeAdView . See setAdChoice position |
iconView | NativeIconView | Mandatory/Optional | Media content of the native ad. |
mediaView | NativeMediaView | Mandatory/Optional | Icon of the native ad. |
NativeAdView
must contain either NativeIconView
or NativeMediaView
.
The titleView
, callToActionView
and adAttributionView
has to be added in any cases.
- Set ids of all child views of
NativeAdView
.
You can do this either in the xml file of markdown (recommended way) or programmatically
- XML
- Kotlin
- Java
<com.appodeal.ads.nativead.NativeAdView
app:callToActionViewId="@id/callToActionView"
app:descriptionViewId="@id/descriptionView"
app:iconViewId="@id/iconView"
app:mediaViewId="@id/mediaView"
app:ratingViewId="@id/ratingView"
app:titleViewId="@id/titleView">
app:adAttributionViewId="@id/adAttribution">
val nativeAdView: NativeAdView = ...
nativeAdView.titleViewId = R.id.titleView
nativeAdView.callToActionViewId = R.id.callToActionView
nativeAdView.descriptionViewId = R.id.descriptionView
nativeAdView.ratingViewId = R.id.ratingView
nativeAdView.iconViewId = R.id.iconView
nativeAdView.mediaViewId = R.id.mediaView
nativeAdView.adAttributionViewId = R.id.adAttribution
// OR
nativeAdView.titleView = findViewById(R.id.titleView)
nativeAdView.callToActionView = findViewById(R.id.callToActionView)
nativeAdView.descriptionView = findViewById(R.id.descriptionView)
nativeAdView.ratingView = findViewById(R.id.ratingView)
nativeAdView.iconView = findViewById(R.id.iconView)
nativeAdView.mediaView = findViewById(R.id.mediaView)
nativeAdView.adAttributionView = findViewById(R.id.adAttribution)
NativeAdView nativeAdView: NativeAdView = ...
nativeAdView.setTitleViewId(R.id.titleView);
nativeAdView.setCallToActionViewId(R.id.callToActionView);
nativeAdView.setDescriptionViewId(R.id.descriptionView);
nativeAdView.setRatingViewId(R.id.ratingView);
nativeAdView.setIconViewId(R.id.iconView);
nativeAdView.setMediaViewId(R.id.mediaView);
nativeAdView.setAdAttributionViewId(R.id.adAttribution);
// OR
nativeAdView.setTitleView(findViewById(R.id.titleView));
nativeAdView.setCallToActionView(findViewById(R.id.callToActionView));
nativeAdView.setDescriptionView(findViewById(R.id.descriptionView));
nativeAdView.setRatingView(findViewById(R.id.ratingView));
nativeAdView.setIconView(findViewById(R.id.iconView));
nativeAdView.setMediaView(findViewById(R.id.mediaView));
nativeAdView.setAdAttributionView(findViewById(R.id.adAttribution));
- When the
NativeAd
is loaded just register it for showing:
- For single NativeAd
- For several NativeAd instances
- Kotlin
- Java
if (Appodeal.isLoaded(Appodeal.NATIVE)) {
newsFeedView.registerView(Appodeal.getNativeAdCount(1))
}
if (Appodeal.isLoaded(Appodeal.NATIVE)) {
newsFeedView.registerView(Appodeal.getNativeAdCount(1));
}
- Kotlin
- Java
val needToShow = 3
if (Appodeal.getAvailableNativeAdsCount() >= needToShow) {
val nativeAds = Appodeal.getNativeAdCount(needToShow)
nativeAdView1.registerView(nativeAds[0])
nativeAdView2.registerView(nativeAds[1])
nativeAdView3.registerView(nativeAds[2])
}
int needToShow = 3;
if (Appodeal.getAvailableNativeAdsCount() >= needToShow) {
List<NativeAd> nativeAds = Appodeal.getNativeAdCount(needToShow);
nativeAdView1.registerView(nativeAds.get(0));
nativeAdView2.registerView(nativeAds.get(1));
nativeAdView3.registerView(nativeAds.get(2));
}
- When the display has been terminated and you no longer plan to use the
NativeAdView
, you should call thedestroy
method:
- Kotlin
- Java
nativeAdView.destroy()
nativeAdView.destroy();
If you want to show a new NativeAd inside used nativeAdView, just call
nativeAdView.registerView(newNativeAd)
method.
Check If Ad Is Loaded
To check if at least 1 instance of NativeAd
is loaded, use the method:
- Kotlin
- Java
Appodeal.isLoaded(Appodeal.NATIVE)
Appodeal.isLoaded(Appodeal.NATIVE);
To get how many NativeAd
instances are loaded, use the method:
- Kotlin
- Java
val nativeAmount = Appodeal.getAvailableNativeAdsCount()
int nativeAmount = Appodeal.getAvailableNativeAdsCount();
By default, the Appodeal SDK with AutoCahce enabled loads 2 instances of NativeAd
each
We recommend you always check whether an ad is available before trying to show it.
Get Loaded Native Ads
To get loaded native ads, use the following method:
- Kotlin
- Java
val nativeAds: List<NativeAd> = Appodeal.getNativeAds(amount)
List<NativeAd> nativeAds = Appodeal.getNativeAds(int amount);
Once you get the ads, they are removed from our SDK cache.
Display
To display NativeAd
, you need to call the following code:
- Kotlin
- Java
NativeAdView.registerView(nativeAd: NativeAd)
NativeAdView.registerView(NativeAd nativeAd);
SDK can't show ads without a network connection!
NativeAdView.registerView()
returns a boolean value indicating whether the show
method call was passed to the appropriate SDK.
Before the registerView(nativeAd)
method is called, NativeAdView
is in the visibility == GONE
state. After the call, the state will automatically change to visibility == VISIBLE
.
You don't need to change the visibility state, Appodeal SDK does it automatically.
After calling destroy()
, the state will automatically change to visibility == GONE
.
NativeAdView
and its successors have a built-in attribute tools:visibility="visible"
so the view
will be displayed in your IDE markup during development.
Placements
Appodeal SDK allows you to tag each impression with different placement. To use placements, you need to create placements in Appodeal Dashboard. Read more about placements.
To show an ad with placement, you have to call show method:
- Kotlin
- Java
NativeAdView.registerView(nativeAd: NativeAd, yourPlacementName: String)
NativeAdView.registerView(NativeAd nativeAd, String yourPlacementName)
If the loaded ad can’t be shown for a specific placement, nothing will be shown.
If auto caching is enabled, sdk will start to cache another ad, which can affect display rate. To save the loaded ad for future use (for instance, for another placement) check if the ad can be shown before calling the show method:
- Kotlin
- Java
if (NativeAd.canShow(context: Context, yourPlacementName: String)) {
NativeAdView.registerView(nativeAd: NativeAd, yourPlacementName: String)
}
if (NativeAd.canShow(Context context, String yourPlacementName)) {
NativeAdView.registerView(NativeAd nativeAd, String yourPlacementName)
}
You can configure your impression logic for each placement.
If you have no placements, or call NativeAdView.registerView
with a placement that does not exist,
the impression will be tagged with 'default' placement and its settings will be applied.
Placement settings affect ONLY ad presentation, not loading or caching.
UnregisterView
To unregister the view from displaying the currently registered native ad use the method:
- Kotlin
- Java
NativeAdView.unregisterView()
NativeAdView.unregisterView();
UnregisterView
method does not hide the NativeAdView
. It suspends the NativeAd display
tracking.
UnregisterView
makes sense to use, for example, if the NativeAdView is out of the screen while
scrolling in the list, or is temporarily overlapped by another View
/Fragment
/Activity
Destroy
To destroy the native ad view and perform any necessary cleanup, and hide NativeAdView
use the
method:
- Kotlin
- Java
NativeAdView.destroy()
NativeAdView.destroy();
This method should be called when the native ad is no longer needed.
Also, when destroy()
is called, the unregisterView
logic is triggered.
Callbacks
- Kotlin
- Java
Appodeal.setNativeCallbacks(object : NativeCallbacks {
override fun onNativeLoaded() {
// Called when native ads are loaded
}
override fun onNativeFailedToLoad() {
// Called when native ads are failed to load
}
override fun onNativeShown(nativeAd: NativeAd) {
// Called when native ad is shown
}
override fun onNativeShowFailed(nativeAd: NativeAd) {
// Called when native ad show failed
}
override fun onNativeClicked(nativeAd: NativeAd) {
// Called when native ads is clicked
}
override fun onNativeExpired() {
// Called when native ads is expired
}
})
Appodeal.setNativeCallbacks(new NativeCallbacks() {
@Override
public void onNativeLoaded() {
// Called when native ads are loaded
}
@Override
public void onNativeFailedToLoad() {
// Called when native ads are failed to load
}
@Override
public void onNativeShown(NativeAd nativeAd) {
// Called when native ad is shown
}
@Override
public void onNativeShowFailed(NativeAd nativeAd) {
// Called when native ad show failed
}
@Override
public void onNativeClicked(NativeAd nativeAd) {
// Called when native ads is clicked
}
@Override
public void onNativeExpired() {
// Called when native ads is expired
}
});
All callbacks are called on the main thread.
Cache Manually
To disable automatic caching for native ads, use the code below before the SDK initialization:
- Kotlin
- Java
Appodeal.setAutoCache(Appodeal.NATIVE, false)
Appodeal.setAutoCache(Appodeal.NATIVE, false);
Read more on manual caching in our ** FAQ**.
Cache
To cache native ads, use:
- Kotlin
- Java
Appodeal.cache(this, Appodeal.NATIVE)
Appodeal.cache(this, Appodeal.NATIVE);
To cache multiple native ads, use:
- Kotlin
- Java
Appodeal.cache(this, Appodeal.NATIVE, 3)
Appodeal.cache(this, Appodeal.NATIVE, 3);
You may request a maximum of 5 NativeAd
The number of cached ads is not guaranteed and could be less than requested.
Check If Ad Is Initialized
To check if NativeAd
was initialized, you can use the method:
- Kotlin
- Java
Appodeal.isInitialized(Appodeal.NATIVE)
Appodeal.isInitialized(Appodeal.NATIVE);
Returnstrue
, if the NativeAd
was initialized.
Check If Autocache Is Enabled
To check if autocache is enabled for NativeAd
, you can use the
method:
- Kotlin
- Java
Appodeal.isAutoCacheEnabled(Appodeal.NATIVE)
Appodeal.isAutoCacheEnabled(Appodeal.NATIVE);
Returns true
, if autocache is enabled for native.
Get Predicted eCPM
To get the predicted eCPM from the next block in the caching queue, use the method:
- Kotlin
- Java
NativeAd.predictedEcpm
NativeAd.getPredictedEcpm();
Configuration
Set preferred media content type
You can tell the Appodeal SDK your preferred content type for NativeAd. To do this, use the method:
- Kotlin
- Java
// both static image and video native ads will be loaded
Appodeal.setPreferredNativeContentType(NativeMediaViewContentType.Auto)
// only static image native ads will be loaded
Appodeal.setPreferredNativeContentType(NativeMediaViewContentType.NoVideo)
// only video native ads will be loaded.
Appodeal.setPreferredNativeContentType(NativeMediaViewContentType.Video)
// both static image and video native ads will be loaded
Appodeal.setPreferredNativeContentType(NativeMediaViewContentType.Auto);
// only static image native ads will be loaded
Appodeal.setPreferredNativeContentType(NativeMediaViewContentType.NoVideo);
// only video native ads will be loaded.
Appodeal.setPreferredNativeContentType(NativeMediaViewContentType.Video);
Setting a video type does not guarantee that it will be loaded, but only indicates the preferred type.
To check if the downloaded advertisement contains video you can use the method:
- Kotlin
- Java
NativeAd.containsVideo()
NativeAd.containsVideo();
Return true
if NativeAd
contains video
Use the method to retrieve the preferred content type:
- Kotlin
- Java
Appodeal.getPreferredNativeContentType()
Appodeal.getPreferredNativeContentType();
Only affects content inside the NativeMediaView
. Therefore, it makes sense to use it only in
case of NativeAdViewContentStream
template or your out custom implementation of NativeAdView
.
Content for NativeIconView
is always a static image
Set adChoice position
You can specify a position in one of the corners of the NativeAdView
:
- XML
- Kotlin
- Java
app:adChoicePosition="end_top"
nativeAdView.setAdChoicesPosition(Position.END_TOP)
nativeAdView.setAdChoicesPosition(Position.END_TOP);
As a Position
you can specify one of 4 options:
START_TOP
- matches to the upper left corner of NativeAdView
;
START_BOTTOM
- matches to the lower left corner of NativeAdView
;
END_TOP
- matches the upper right corner of NativeAdView
;
END_BOTTOM
- matches the bottom right corner of NativeAdView
.
AdAttributionView settings
You may set text color and background color for AdAttributionView in NativeAdView
:
- XML
- Kotlin
- Java
app:adAttributionBackgroundColor="@color/red"
app:adAttributionTextColor="@color/black"
nativeAdView.setAdAttributionBackground(Color.RED)
nativeAdView.setAdAttributionTextColor(Color.BLACK)
nativeAdView.setAdAttributionBackground(Color.RED);
nativeAdView.setAdAttributionTextColor(Color.BLACK);
Color should have ColorInt format. See android.graphics.Color
.
For custom NativeAdView
, you may do the same via your xml markup using attributes android:textColor
and android:background
for adAttribution TextView
.
Works with lists
To use NativeAd
in RecyclerView
, you can use the following example:
- Create an ListItem entity that will serve to define the
itemViewType
in RecyclerView.ListAdapter:
- Kotlin
- Java
sealed interface ListItem {
fun getItemId(): Int
class NativeAdItem(val getNativeAd: () -> NativeAd?) : ListItem {
override fun getItemId() = NATIVE_AD_ITEM
companion object {
const val NATIVE_AD_ITEM = 3
}
}
data class YourDataItem(val userData: Int) : ListItem {
override fun getItemId() = USER_ITEM
companion object {
const val USER_ITEM = 2
}
}
}
public interface ListItem {
int getItemId();
int hashCode();
}
public final class NativeAdItem implements ListItem {
private final NativeAd nativeAd;
public NativeAdItem(NativeAd nativeAd) {
this.nativeAd = nativeAd;
}
@Override
public int getItemId() {
return NATIVE_AD_ITEM;
}
public NativeAd getNativeAd() {
return nativeAd;
}
public static final int NATIVE_AD_ITEM = 3;
}
public final class YourDataItem implements ListItem {
private final int userData;
public YourDataItem(int userData) {
this.userData = userData;
}
@Override
public int getItemId() {
return USER_ITEM;
}
public int getUserData() {
return userData;
}
public static final int USER_ITEM = 2;
}
- Create a
DiffUtil.ItemCallback<ListItem>
entity that will show theListAdapter
the differences between items:
- Kotlin
- Java
internal class DiffUtils : DiffUtil.ItemCallback<ListItem>() {
override fun areItemsTheSame(oldItem: ListItem, newItem: ListItem) =
oldItem.getItemId() == newItem.getItemId()
override fun areContentsTheSame(oldItem: ListItem, newItem: ListItem) =
oldItem.hashCode() == newItem.hashCode()
}
class DiffUtils extends DiffUtil.ItemCallback<ListItem> {
@Override
public boolean areItemsTheSame(ListItem oldItem, ListItem newItem) {
return oldItem.getItemId() == newItem.getItemId();
}
@Override
public boolean areContentsTheSame(ListItem oldItem, ListItem newItem) {
return oldItem.hashCode() == newItem.hashCode();
}
}
- Create a
ListAdapter
entity, which will be an adapter forRecyclerView
:
- Kotlin
- Java
class NativeListAdapter : ListAdapter<ListItem, ListHolder>(DiffUtils()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListHolder {
return when (viewType) {
NATIVE_AD_ITEM -> { DynamicAdViewHolder(NativeAdViewContentStream(parent.context)) }
else -> {
YourViewHolder(
YourDataItemBinding.inflate(LayoutInflater.from(parent.context),
parent,
false
))
}
}
}
override fun onBindViewHolder(holder: ListHolder, position: Int) {
when (val item = getItem(position)) {
is ListItem.YourDataItem -> (holder as YourViewHolder).bind(item)
is ListItem.NativeAdItem -> (holder as DynamicAdViewHolder).bind(item)
}
}
override fun getItemViewType(position: Int): Int {
return when (currentList[position]) {
is ListItem.YourDataItem -> USER_ITEM
is ListItem.NativeAdItem -> NATIVE_AD_ITEM
}
}
sealed class ListHolder(root: View) : RecyclerView.ViewHolder(root) {
class YourViewHolder(private val binding: YourDataItemBinding) : ListHolder(binding.root) {
fun bind(item: ListItem.YourDataItem) {
binding.root.text = item.userData.toString()
}
}
class DynamicAdViewHolder(itemView: View) : ListHolder(itemView) {
fun bind(item: ListItem.NativeAdItem) {
val nativeAd = item.getNativeAd.invoke()
if (nativeAd != null) {
(itemView as NativeAdView).registerView(nativeAd)
}
}
}
}
}
public class NativeListAdapter extends ListAdapter<ListItem, NativeListAdapter.ListHolder> {
public NativeListAdapter() {
super(new DiffUtils());
}
@Override
public ListHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if (viewType == NATIVE_AD_ITEM) {
return new DynamicAdViewHolder(new NativeAdViewContentStream(parent.getContext()));
} else {
YourDataItemBinding binding = YourDataItemBinding.inflate(inflater,
parent,
false);
return new YourViewHolder(binding);
}
}
@Override
public void onBindViewHolder(ListHolder holder, int position) {
ListItem item = getItem(position);
if (item instanceof YourDataItem) {
((YourViewHolder) holder).bind((YourDataItem) item);
} else if (item instanceof NativeAdItem) {
((DynamicAdViewHolder) holder).bind((NativeAdItem) item);
}
}
@Override
public int getItemViewType(int position) {
ListItem item = getItem(position);
if (item instanceof YourDataItem) {
return USER_ITEM;
} else if (item instanceof NativeAdItem) {
return NATIVE_AD_ITEM;
}
return super.getItemViewType(position);
}
abstract static class ListHolder extends RecyclerView.ViewHolder {
ListHolder(View root) {
super(root);
}
}
static class YourViewHolder extends ListHolder {
private YourDataItemBinding binding;
YourViewHolder(YourDataItemBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
void bind(YourDataItem item) {
binding.getRoot().setText(String.valueOf(item.getUserData()));
}
}
static class DynamicAdViewHolder extends ListHolder {
DynamicAdViewHolder(View itemView) {
super(itemView);
}
void bind(NativeAdItem item) {
NativeAd nativeAd = item.getNativeAd();
if (nativeAd != null) {
((NativeAdView) itemView).registerView(nativeAd);
}
}
}
}
NATIVE_AD_ITEM
- NativeAdItem.NATIVE_AD_ITEM
- As the markup of your Activity/Fragment, we use the markup
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorBackground">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</FrameLayout>
We'll use the example as the markup of your YourDataItem:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:textSize="64sp"
tools:text="1" />
- In your
Activity
/Fragment
, add the following code
- Kotlin
- Java
class NativeActivity : AppCompatActivity() {
private val getNativeAd: () -> NativeAd? = { Appodeal.getNativeAds(1).firstOrNull() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityNativeBinding.inflate(layoutInflater)
setContentView(binding.root)
val nativeListAdapter = NativeListAdapter()
binding.recyclerView.adapter = nativeListAdapter
setUpAppodealSDK()
}
private fun setUpAppodealSDK() {
Appodeal.setLogLevel(LogLevel.verbose)
Appodeal.setTesting(true)
Appodeal.initialize(this, APPODEAL_APP_KEY, Appodeal.NATIVE) { errors ->
val initResult = if (errors.isNullOrEmpty()) "successfully" else "with ${errors.size} errors"
Log.d("TAG", "onInitializationFinished: $initResult")
}
}
private fun obtainData(nativeListAdapter: NativeListAdapter) {
val yourDataItems = generateYourData()
nativeListAdapter.submitList(yourDataItems.addNativeAdItems())
}
private fun List<ListItem>.addNativeAdItems() =
this.foldIndexed(
initial = listOf(),
operation = { index: Int, acc: List<ListItem>, yourDataItem: ListItem ->
val shouldAdd = index % STEPS == 0 && index != 0
if (shouldAdd) {
acc + createNativeAdItem() + yourDataItem
} else {
acc + yourDataItem
}
}
)
private fun generateYourData(): List<ListItem> =
(1..USER_DATA_SIZE).toList().map { ListItem.YourDataItem(userData = it) }
private fun createNativeAdItem(): ListItem.NativeAdItem =
ListItem.NativeAdItem(getNativeAd = getNativeAd)
}
private const val USER_DATA_SIZE = 200
private const val STEPS = 5
public class NativeActivity extends AppCompatActivity {
private static final String TAG = "NativeActivity";
private static final String APP_KEY = "YOUR_APP_KEY";
private static final int USER_DATA_SIZE = 200;
private static final int STEPS = 5;
private final GetNativeAdCallback getNativeAd = () -> {
List<NativeAd> nativeAds = Appodeal.getNativeAds(1);
return nativeAds.size() > 0 ? nativeAds.get(0) : null;
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityNativeBinding binding = ActivityNativeBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
NativeListAdapter nativeListAdapter = new NativeListAdapter();
binding.recyclerView.setAdapter(nativeListAdapter);
setUpAppodealSDK();
}
private void setUpAppodealSDK() {
Appodeal.setTesting(true);
Appodeal.initialize(this, APPODEAL_APP_KEY, Appodeal.NATIVE, errors -> {
if (errors == null || errors.isEmpty()) {
Log.d(TAG, "onInitializationFinished: successfully");
} else {
Log.d(TAG, "onInitializationFinished: with " + errors.size() + " errors");
}
});
}
private void obtainData(NativeListAdapter nativeListAdapter) {
List<ListItem> yourDataItems = generateYourData();
List<ListItem> itemsWithNativeAd = addNativeAdItems(yourDataItems);
nativeListAdapter.submitList(itemsWithNativeAd);
}
private List<ListItem> generateYourData() {
List<ListItem> yourDataItems = new ArrayList<>();
for (int i = 1; i <= USER_DATA_SIZE; i++) {
yourDataItems.add(new YourDataItem(i));
}
return yourDataItems;
}
private List<ListItem> addNativeAdItems(List<ListItem> yourDataItems) {
List<ListItem> itemsWithNativeAd = new ArrayList<>();
for (int i = 0; i < yourDataItems.size(); i++) {
ListItem yourDataItem = yourDataItems.get(i);
boolean shouldAdd = i % STEPS == 0 && i != 0;
if (shouldAdd) {
itemsWithNativeAd.add(createNativeAdItem());
}
itemsWithNativeAd.add(yourDataItem);
}
return itemsWithNativeAd;
}
private NativeAdItem createNativeAdItem() {
return new NativeAdItem(getNativeAd.getNativeAd());
}
interface GetNativeAdCallback {
NativeAd getNativeAd();
}
}
STEPS
- step through which the insertion of NativeAd
will be repeated;
addNativeAdItems()
- logic of inserting NativeAd
into the list through a certain number of STEPS
.
Done! When you want to insert native ads into RecyclerView
, simply call the obtainData()
method
Common Mistakes
- No adAttributionView
The majority of ad networks require publishers to add a special mark to a native ad, so users don’t mistake them for content. That’s why you always need to make sure, that native ads in your app have the ad attribution (e.g., “Ad”) or the AdChoices icon.
- Absence of the required native ad elements
Every native ad should contain:
-
titleView TextView;
-
callToActionView Button;
-
adAttribution TextView;
-
NativeIconView
orNativeMedaiaView
. -
Native ad elements alteration
Advertisers expect that their ads will be displayed clearly and without any alteration. You can scale buttons and images, but you shouldn't crop, cover or distort them.
- Overlaying elements of native ads on each other
Make sure, that all elements of a native ad are visible and not overlaid.
Native ads requirements:
- All of the fields of native ad marked as mandatory must be displayed.
- Image assets can be resized to fit your ad space but should not be significantly distorted or cropped.
Check Viewability
You can always check in logs if show was tracked and your ad is visible.
You will see the Native [Notify Shown] log if show was tracked successfully.
- Log
Appodeal com.example.app D Native [Notify Shown]