Адаптивный inline-баннер

Адаптивный inline-баннер — гибкий формат баннерной рекламы, обеспечивающий максимальную эффективность за счет оптимизации размера рекламы для каждого устройства.

Данный тип рекламы позволяет разработчикам указывать максимально допустимые ширину и высоту объявления, при этом наиболее оптимальный размер рекламы определяется автоматически. Чтобы выбрать лучший размер объявления, встроенные адаптивные баннеры используют максимальную, а не фиксированную высоту. Это приводит к возможности для повышения производительности.

Как правило, такой формат используется в приложениях-лентах или там, где допустимо обеспечить основной фокус на рекламе.

Это руководство покажет, как интегрировать адаптивный inline-баннер в Android‐приложение. В дополнение к примерам кода и инструкции оно содержит рекомендации по использованию данного формата рекламы, а также ссылки на дополнительные ресурсы.

Дополнительно об интеграции адаптивного inline-баннера смотрите в видео:

Пререквизит

  1. Выполните шаги по интеграции sdk, описанные в Быстром старте.
  2. Заранее проинициализируйте рекламный SDK.
  3. Убедитесь, что используете самую актуальную версию Yandex Mobile Ads SDK, а в случае использовании медиации — наиболее свежую версию единой сборки.

Имплементация

Основные шаги по интеграции адаптивного inline-баннера:

  • Создать и настроить вью для отображенния баннерной рекламы.
  • Зарегистрировать слушатель методов обратного вызова.
  • Загрузить рекламу.
  • Передать дополнительные настройки, если вы работаете через систему Adfox.

Особенности подключения адаптивного inline-баннера

  1. Все вызовы методов Yandex Mobile Ads SDK необходимо выполнять из главного потока.

  2. Чтобы видеореклама успешно отображалась на экране вашего приложения, необходимо включить аппаратное ускорение. Аппаратное ускорение включено по умолчанию, но некоторые приложения его выключают. Если это относится к вашему приложению, рекомендуется включить аппаратное ускорение для классов активности, использующих рекламу.

  3. Если вы получили ошибку в коллбэке onAdFailedToLoad(), не пытайтесь загрузить новое объявление снова. Если всё же необходимо это сделать, ограничьте число повторных попыток загрузки рекламы. Это поможет избежать постоянных неудачных запросов и проблем с подключением в случае ограничений.

  4. Чтобы адаптивные inline-баннеры работали правильно, сделайте макеты приложения адаптивными. Невыполнение этого требования может привести к некорректному отображению рекламы.

  5. Адаптивные inline-баннеры лучше всего работают при использовании всей доступной ширины. В большинстве случаев это будет полная ширина экрана используемого устройства. Обязательно учитывайте применимые в приложении отступы (padding) и безопасные зоны (safe area) дисплея.

  6. Адаптивный inline-баннер предназначен для размещения в прокручиваемом контенте. Баннер может быть такой же высоты, как экран устройства, или ограничен максимальной высотой, в зависимости от API.

  7. Для получения размера рекламного объявления воспользуйтесь методом BannerAdSize.inlineSize(context, adWidth, maxAdHeight), принимающим в качестве аргументов контекст, доступную ширину рекламного контейнера и максимально допустимую высоту объявления.

  8. Объект BannerAdSize, рассчитанный с помощью метода BannerAdSize.inlineSize(context, adWidth, maxAdHeight) содержит технические данные для выбора наиболее эффективных размеров рекламных объявлений на стороне бэкенда. Высота рекламного объявления может изменяться при каждой загрузке рекламы. Актуальные значения ширины и высоты рекламы доступны после получения сообщения об успешной загрузке рекламы.

Добавление рекламной вью в макет приложения

Для отображения баннерной рекламы необходимо добавить BannerAdView в макет приложения. Сделать это можно программно или через XML-файл.

Пример добавления BannerAdView в макет экрана приложения:

# activity.xml
...
<com.yandex.mobile.ads.banner.BannerAdView
        android:id="@+id/ad_container_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
...

Вы также можете создать объект BannerAdView программно:

val bannerAd = BannerAdView(this)
final BannerAdView bannerAd = new BannerAdView(this);

Загрузка и отображение рекламы

После создания и добавления BannerAdView на экран приложения, рекламу необходимо загрузить. Перед загрузкой адаптивного inline-баннера необходимо рассчитать размер рекламы для каждого устройства.

Делается это автоматически через API SDK: BannerAdSize.inlineSize(context, adWidth, maxAdHeight). В качестве аргумента необходимо передать контекст, доступную ширину рекламного контейнера и максимально допустимую высоту объявления. Адаптивные inline-баннеры лучше всего работают при использовании всей доступной ширины экрана. В большинстве случаев это будет полная ширина экрана используемого устройства. Обязательно учитывайте применимые в приложении отступы (padding) и безопасные зоны (safe area) дисплея:

private val adSize: BannerAdSize
    get() {
        val screenHeight = resources.displayMetrics.run { heightPixels / density }.roundToInt()
        // Calculate the width of the ad, taking into account the padding in the ad container.
        var adWidthPixels = binding.adContainerView.width
        if (adWidthPixels == 0) {
            // If the ad hasn't been laid out, default to the full screen width
            adWidthPixels = resources.displayMetrics.widthPixels
        }
        val adWidth = (adWidthPixels / resources.displayMetrics.density).roundToInt()
        val maxAdHeight = screenHeight / 2

        return BannerAdSize.inlineSize(context, adWidth, maxAdHeight)
    }
@NonNull
private BannerAdSize getAdSize() {
    final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
    final int screenHeight = Math.round(displayMetrics.heightPixels / displayMetrics.density);
    // Calculate the width of the ad, taking into account the padding in the ad container.
    int adWidthPixels = mBinding.adContainerView.getWidth();
    if (adWidthPixels == 0) {
        // If the ad hasn't been laid out, default to the full screen width
        adWidthPixels = displayMetrics.widthPixels;
    }
    final int adWidth = Math.round(adWidthPixels / displayMetrics.density);
    // Determine the maximum allowable ad height. The current value is given as an example.
    final int maxAdHeight = screenHeight / 2;

    return BannerAdSize.inlineSize(this, adWidth, maxAdHeight);
}

Для загрузки рекламы также потребуется Activity context и идентификатор рекламного места (adUnitId), полученный вами в ПИ.

Для уведомления об успешной или неудачной загрузке рекламы, а также для отслеживания событий жизненного цикла адаптивного inline-баннера, объекту класса BannerAdView необходимо установить слушатель методов обратного вызова BannerAdEventListener.

Расширить параметры запроса за рекламой можно через AdRequest.Builder(), передав в запросе данные об интересах пользователя, контекстные данные страницы, локацию или другие дополнительные данные. Дополнительные контекстные данные на запросе могут значительно улучшить качество рекламы. Подробнее читайте в разделе Таргетирование рекламы.

В следующем примере показано как загрузить адаптивный inline-баннер. После успешной загрузки баннер отобразится автоматически:

class AdaptiveInlineBannerAdActivity : AppCompatActivity(R.layout.activity_inline_banner_ad) {
    private var bannerAd: BannerAdView? = null
    private lateinit var binding: ActivityInlineBannerAdBinding

    private val adSize: BannerAdSize
        get() {
            val screenHeight = resources.displayMetrics.run { heightPixels / density }.roundToInt()
            // Calculate the width of the ad, taking into account the padding in the ad container.
            var adWidthPixels = binding.adContainerView.width
            if (adWidthPixels == 0) {
                // If the ad hasn't been laid out, default to the full screen width
                adWidthPixels = resources.displayMetrics.widthPixels
            }
            val adWidth = (adWidthPixels / resources.displayMetrics.density).roundToInt()
            // Determine the maximum allowable ad height. The current value is given as an example.
            val maxAdHeight = screenHeight / 2

            return BannerAdSize.inlineSize(context, adWidth, maxAdHeight)
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityInlineBannerAdBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Since we're loading the banner based on the adContainerView size,
        // we need to wait until this view is laid out before we can get the width
        binding.adContainerView.viewTreeObserver.addOnGlobalLayoutListener(object :
            ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                binding.adContainerView.viewTreeObserver.removeOnGlobalLayoutListener(this);
                bannerAd = loadBannerAd(adSize)
            }
        })
    }

    private fun loadBannerAd(adSize: BannerAdSize): BannerAdView {
        return binding.banner.apply {
            setAdSize(adSize)
            setAdUnitId("your-ad-unit-id")
            setBannerAdEventListener(object : BannerAdEventListener {
                override fun onAdLoaded() {
                    // If this callback occurs after the activity is destroyed, you
                    // must call destroy and return or you may get a memory leak.
                    // Note `isDestroyed` is a method on Activity.
                    if (isDestroyed) {
                        bannerAd?.destroy()
                        return
                    }
                }

                override fun onAdFailedToLoad(adRequestError: AdRequestError) {
                    // Ad failed to load with AdRequestError.
                    // Attempting to load a new ad from the onAdFailedToLoad() method is strongly discouraged.
                }

                override fun onAdClicked() {
                    // Called when a click is recorded for an ad.
                }

                override fun onLeftApplication() {
                    // Called when user is about to leave application (e.g., to go to the browser), as a result of clicking on the ad.
                }

                override fun onReturnedToApplication() {
                    // Called when user returned to application after click.
                }

                override fun onImpression(impressionData: ImpressionData?) {
                    // Called when an impression is recorded for an ad.
                }
            })
            loadAd(
                AdRequest.Builder()
                    // Methods in the AdRequest.Builder class can be used here to specify individual options settings.
                    .build()
            )
        }
    }
}
public class AdaptiveInlineBannerAdActivity extends AppCompatActivity {
    @Nullable
    private BannerAdView mBannerAd = null;
    private ActivityInlineBannerAdBinding mBinding;

    public AdaptiveInlineBannerAdActivity() {
        super(R.layout.activity_inline_banner_ad);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = ActivityInlineBannerAdBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());

        // Since we're loading the banner based on the adContainerView size,
        // we need to wait until this view is laid out before we can get the width
        mBinding.adContainerView.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        mBinding.adContainerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        mBannerAd = loadBannerAd(getAdSize());
                    }
                }
        );
    }

    @NonNull
    private BannerAdSize getAdSize() {
        final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        final int screenHeight = Math.round(displayMetrics.heightPixels / displayMetrics.density);
        // Calculate the width of the ad, taking into account the padding in the ad container.
        int adWidthPixels = mBinding.adContainerView.getWidth();
        if (adWidthPixels == 0) {
            // If the ad hasn't been laid out, default to the full screen width
            adWidthPixels = displayMetrics.widthPixels;
        }
        final int adWidth = Math.round(adWidthPixels / displayMetrics.density);
        // Determine the maximum allowable ad height. The current value is given as an example.
        final int maxAdHeight = screenHeight / 2;

        return BannerAdSize.inlineSize(this, adWidth, maxAdHeight);
    }

    @NonNull
    private BannerAdView loadBannerAd(@NonNull final BannerAdSize adSize) {
        final BannerAdView bannerAd = mBinding.banner;
        bannerAd.setAdSize(adSize);
        bannerAd.setAdUnitId("your-ad-unit-id");
        bannerAd.setBannerAdEventListener(new BannerAdEventListener() {
            @Override
            public void onAdLoaded() {
                // If this callback occurs after the activity is destroyed, you
                // must call destroy and return or you may get a memory leak.
                // Note `isDestroyed` is a method on Activity.
                if (isDestroyed() && mBannerAd != null) {
                    mBannerAd.destroy();
                }
            }

            @Override
            public void onAdFailedToLoad(@NonNull final AdRequestError adRequestError) {
                // Ad failed to load with AdRequestError.
                // Attempting to load a new ad from the onAdFailedToLoad() method is strongly discouraged.
            }

            @Override
            public void onAdClicked() {
                // Called when a click is recorded for an ad.
            }

            @Override
            public void onLeftApplication() {
                // Called when user is about to leave application (e.g., to go to the browser), as a result of clicking on the ad.
            }

            @Override
            public void onReturnedToApplication() {
                // Called when user returned to application after click.
            }

            @Override
            public void onImpression(@Nullable ImpressionData impressionData) {
                // Called when an impression is recorded for an ad.
            }
        });
        final AdRequest adRequest = new AdRequest.Builder()
                // Methods in the AdRequest.Builder class can be used here to specify individual options settings.
                .build();
        bannerAd.loadAd(adRequest);
        return bannerAd;
    }
}

Освобождение ресурсов

Если метод обратного вызова был вызван после окончания жизненного цикла Activity, освободите ресурсы вызовом функции destroy() для используемого объекта рекламы:

private fun loadBannerAd(adSize: BannerAdSize): BannerAdView {
    return binding.banner.apply {
        setBannerAdEventListener(object : BannerAdEventListener {
            override fun onAdLoaded() {
                // If this callback occurs after the activity is destroyed, you
                // must call destroy and return or you may get a memory leak.
                // Note `isDestroyed` is a method on Activity.
                if (isDestroyed) {
                    bannerAd?.destroy()
                    return
                }
            }
            ...
        })
        ...
    }
}
@NonNull
private BannerAdView loadBannerAd(@NonNull final BannerAdSize adSize) {
    final BannerAdView bannerAd = mBinding.banner;
    bannerAd.setBannerAdEventListener(new BannerAdEventListener() {
        @Override
        public void onAdLoaded() {
            // If this callback occurs after the activity is destroyed, you
            // must call destroy and return or you may get a memory leak.
            // Note `isDestroyed` is a method on Activity.
            if (isDestroyed() && mBannerAd != null) {
                mBannerAd.destroy();
            }
        }
        ...
    });
    ...
    return bannerAd;
}

Тестирование интеграции адаптивного inline-баннера

Использование демоблоков для тестирования рекламы

Для проверки корректной интеграции адаптивного inline-баннера, а также для тестирования вашего приложения, рекомендуется использовать тестовую рекламу.

Для гарантированного возврата тестовых объявлений на каждый запрос за рекламой, мы создали специальный демонстрационный идентификатор рекламного места. Используйте его для проверки корректной интеграции рекламы.

Демонстрационный adUnitId: demo-banner-yandex.

Важно

Убедитесь, что перед выкладыванием приложения в store, вы заменили демонстрационный идентификатор рекламного места на настоящий, полученный в ПИ.

Список всех доступных демонстрационных идентификаторов рекламного места доступен в разделе Демоблоки для тестирования.

Проверка корректной интеграции рекламы

Проверить корректность интеграции адаптивного inline-баннера можно через встроенный в sdk анализатор.

Данный инструмент проверяет корректность подключения рекламы и выводит в лог подробный отчет. Для просмотра отчета, выполните поиск по ключевому слову "YandexAds" в инструменте отладки Android-приложений Logcat.

adb logcat -v brief '*:S YandexAds'

В случае успешной интеграции, вы увидите следующее сообщение:

adb logcat -v brief '*:S YandexAds'
mobileads$ adb logcat -v brief '*:S YandexAds'
I/YandexAds(13719): [Integration] Ad type banner was integrated successfully

В случае обнаружения проблем при интеграции баннерной рекламы — подробный отчет о проблемах и рекомендации по их устранению.

Дополнительные ресурсы