Реализация нативной рекламы в мобильном приложении
Нативная реклама — это не «реклама, которая выглядит не как реклама». Google и Apple требуют явной маркировки («Реклама», «Ad», «Sponsored»), и нарушение этого правила ведёт к отклонению приложения. Нативная реклама — это объявление, которое визуально вписывается в дизайн, но честно идентифицирует себя. CTR у грамотно реализованной нативки в ленте — в 2–4 раза выше баннера.
Где чаще всего ломается реализация
Неправильный registerView.
AdMob требует регистрации всех кликабельных элементов в NativeAdView. Если не вызвать nativeAdView.mediaView = ... и не передать все view-компоненты, клики не будут трекаться:
val nativeAdView = inflater.inflate(R.layout.native_ad_layout, null) as NativeAdView
nativeAdView.mediaView = nativeAdView.findViewById(R.id.ad_media)
nativeAdView.headlineView = nativeAdView.findViewById(R.id.ad_headline)
nativeAdView.bodyView = nativeAdView.findViewById(R.id.ad_body)
nativeAdView.callToActionView = nativeAdView.findViewById(R.id.ad_call_to_action)
nativeAdView.iconView = nativeAdView.findViewById(R.id.ad_icon)
// После назначения всех view — биндим объявление
nativeAdView.setNativeAd(nativeAd)
Забытый nativeAdView.setNativeAd(nativeAd) в конце — объявление не показывается вообще. Это не ошибка в logcat, просто пустой layout.
Переиспользование в RecyclerView.
При прокрутке ячейки с нативной рекламой переиспользуются. Если не вызвать previousNativeAd.destroy() перед привязкой нового объявления — старый NativeAd продолжает держать ресурсы. На длинных лентах с нативной рекламой каждые 5–10 позиций это выражается в росте памяти ~15–20 MB за сессию.
override fun onViewRecycled(holder: NativeAdViewHolder) {
holder.nativeAdView.setNativeAd(null) // откепляет предыдущий NativeAd
// или сохраняем reference и вызываем nativeAd.destroy()
}
На iOS аналогичная проблема: GADNativeAd нужно явно обнулять в prepareForReuse() ячейки.
Шаблоны vs кастомный дизайн
AdMob предлагает GADNativeAdView (iOS) и NativeAdView (Android) как контейнеры с готовой логикой трекинга кликов. Верстать внутри этих контейнеров обязательно — нельзя просто наложить свои views поверх и ожидать, что клики будут считаться.
Дизайн шаблона — свободный в рамках гайдлайнов платформы. Ограничения: логотип/иконка рекламодателя должны быть видны, маркировка «Ad» обязательна, CTA-кнопка должна быть кликабельна (не просто текст).
Google запрещает нативную рекламу, которая визуально неотличима от редакционного контента — то есть без маркировки. За это дают strike и удаляют приложение из AdMob.
Загрузка и кэширование
Нативные объявления загружаются через AdLoader с forNativeAd(). Можно запросить до 5 объявлений за раз через withNativeAdOptions(NativeAdOptions.Builder().setRequestMultipleImages(true).build()) — это полезно для ленты, где нативка вставляется на разных позициях.
Кэшировать объявления дольше 1 часа не имеет смысла — AdMob аннулирует их со стороны сервера.
val adLoader = AdLoader.Builder(context, AD_UNIT_ID)
.forNativeAd { nativeAd ->
nativeAdsList.add(nativeAd)
if (!adLoader.isLoading && nativeAdsList.size == requestCount) {
insertAdsIntoList()
}
}
.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
// логируем, не показываем пользователю
}
})
.build()
adLoader.loadAds(AdRequest.Builder().build(), requestCount)
Сроки реализации нативной рекламы: шаблон в одном месте — 1–2 дня, кастомный дизайн с интеграцией в ленту/RecyclerView — 2–3 дня. Стоимость рассчитывается после обсуждения дизайна и количества точек размещения.







