Баннеры – один из наиболее популярных видов рекламы в мобильных приложениях. Они не занимают много места, как, например, полноэкранная (interstitial) реклама. И позволяют совместить их с элементами пользовательского интерфейса приложения. Их можно добавить на разные экраны в приложении.

Прочитав данную статью, вы узнаете, как лучше вставить баннеры таким образом, чтобы они не мешали пользователю и не портили вид приложения. При этом вам не придётся изменять layout xml и вносить много изменений в код приложения. Вы можете внедрить баннеры в своё готовое приложение, добавив всего несколько строк кода. Подход, описанный в статье, универсальный, вы можете использовать его для API любых рекламных сервисов. Статья будет интересна как для новичков, так и для опытных разработчиков. Если вы — новичок в разработке, то для того, чтобы понять предмет статьи, от вас не потребуется каких-либо глубоких знаний. Достаточно понимания базовых концепций разработки под Android. А опытные разработчики могут найти в ней готовое решение, которое они могут внедрить у себя. Но инициализация рекламного сервиса, работа с конкретными рекламными API и кеширование находятся за пределами данной статьи. Для решения таких вопросов, пожалуйста, обратитесь к руководству для вашего конкретного рекламного сервиса.

Идея статьи возникла от того, что в одном из наших приложений для Android нам было необходимо разместить баннеры в нескольких местах, но сделать это следовало таким образом, чтобы не испортить вид приложения и не перекрыть баннерами элементы управления. Код приложения был уже написан полностью и перекраивать его нам очень не хотелось, поэтому мы постарались сделать так, чтобы добавление баннеров было максимально простым, корректным и не затрагивало работу существующего кода. Другая причина — нам потребовалось создать платную версию приложения без рекламы. А если бы внедрение баннеров потребовало бы изменение layout xml, то это сильно бы усложнило создание версии без рекламы.

Чтобы было более наглядно и понятно то, о чём я пишу, посмотрите на следующий экран:



Элементы пользовательского интерфейса занимают всё пространство экрана. Пустых мест нет. В таком случае, мы можем разместить баннер внизу или вверху. Вариант размещения баннера снизу предпочтительнее, так как баннер будет находится подальше от кнопок и пользователь не заденет баннер, случайно пытаясь нажать на «Выбрать» или «Назад». Нам необходимо разместить баннер снизу экрана под GridView с фото. Так как баннер загружается по сети, он может быть не сразу и не всегда недоступен. Следовательно, не в каждый момент времени его можно показать и может получиться пустое место снизу. Если мы оставим это пустое место – получится очень некрасиво. Будет выглядеть, как будто это грубая недоработка дизайна интерфейса. Если мы разместим баннер поверх GridView, то он перекроет собой части фото и создаст неудобства пользователю, что тоже недопустимо.

Тогда сводим задачу к тому, что нам необходимо сделать так, чтобы не было дополнительных отступов. А когда баннер загружен и может быть показан – динамически добавить отступ снизу и показать баннер. С другой стороны, нам необходимо сделать код размещения баннеров максимально простым, без сложных инициализаций. Т.е. передавать id элементов или ссылки на контейнеры (ViewGroup) недопустимо. Вставлять баннеры в layout xml каждого экрана, куда нам необходимо добавить баннер – тоже недостустимо, т.к. потребует значительных изменений. В идеале, код установки баннера должен выглядеть следующим образом:

Ads.showBottomBanner(activity);

Всего одна строка кода, один вызов метода, которому передаётся только ссылка на Activity в которой будет размещён баннер. Такой код можно вставить в метод Activity onCreate.

Динамическое добавление отступа

Для того, чтобы это реализовать, нам необходимо знать, что находится в View и получить к этому доступ. Прямого метода для доступа к content view в Activity нет. Но благодаря пользователю nickes со StackOverflow мы нашли решение. Необходимо идти через Window, в котором находится Activity. У Window есть DecorView, а в DecorView находится ContentView. Первый дочерний элемент в нём – это и есть ViewGroup из layout xml.

Так что нам требуется Window, затем мы получаем DecorView, затем получаем ContentView и затем получаем первый дочерний элемент ContentView. И у этого дочернего элемента мы изменяем отступ:

public static void setupContentViewPadding(Activity activity, boolean top, int margin) {
	View view = ((ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0);
	if (top)
		view.setPadding(view.getPaddingLeft(), margin, view.getPaddingRight(), view.getPaddingBottom());
	else
		view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), margin);
}

Размещение баннера

Мы нашли решение, как динамически добавить отступ. Теперь нам необходимо разместить сам баннер. У разных рекламных сервисов разные API. У некоторых есть View баннера, который вы можете создать и добавить в ViewGroup. Но некоторые рекламные API не имеют доступа к View баннера, а имеют только метод, который показывает баннер. Рассмотрим оба варианта.

API, в котором есть View баннера

Назовём класс View баннера — Banner. (Чтобы узнать, как он реально называется в вашем случае и как с ним работать, пожалуйста, обратитесь к руководству вашего рекламного сервиса.)

Сначала, нам необходимо создать объект Banner:

final Banner banner = new Banner(activity);

Затем ему следует назначить слушатель событий. Нас интересует событие успешной загрузки баннера (это опять код — пример. Для того, чтобы узнать как слушатель называется и как его использовать, обратитесь, пожалуйста, к руководству вашего рекламного сервиса):

banner.setBannerListener(new BannerListener() {
		@Override
		public void onReceiveAd(View view) {
	                        // добавить отступ снизу
				setupContentViewPadding(activity, true, BANNER_HEIGHT);
		}
	});

Когда баннер загружен, мы вызываем setupContentViewPadding, чтобы динамически добавить отступ снизу.

Затем мы добавляем наш баннер в Window. Мы добавляем его поверх существующих элементов. В классе Window есть метод addContentView для этого:

FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
			FrameLayout.LayoutParams.MATCH_PARENT, 
			height);//  Utils.toDIP(activity, BANNER_HEIGHT));

layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
activity.getWindow().addContentView(banner, layoutParams);

API без View баннера

У нас нет View баннера и мы не можем создать и разместить его явным образом. Но API имеет методы, вроде showBanner — показать баннер.

Я условно назову класс рекламного API — AdAPI (вам следует обратится к руководству вашего рекламного сервиса, чтобы узнать, как называется класс в которой есть методы размещения баннеров). В этом случае, код размещения баннера будет выглядеть примерно так:

Ad banner = AdAPI.loadBanner();
banner.addListener(new AdListener() {
     public void adLoaded() {
            // add bottom padding, when banner is loaded.
            setupContentViewPadding(activity, true, BANNER_HEIGHT);
     }
});

Где BANNER_HEIGHT — константа равная высоте баннера.

Здесь возникают некоторые затруднения. Вам следует точно узнать или установить высоту баннера. У нас была такая проблема: мы запускали наше приложение на 3.7 дюймовом смартфоне и на 10.1 дюймовом планшете. Размеры баннера оказались разными на разных устройствах. На смартфоне баннер выглядел отлично, но на планшете он оказался слишком большим и отнял слишком много места у других элементов. Если ваш рекламный сервис позволяет явно задать высоту баннера — лучше задайте, чтобы не было таких неприятных неожиданностей.

Результат



Как вы можете видеть, баннер показан и не перекрывает другие элементы. Отступ снизу добавлен динамически.

Это то, что нам требовалось.

Использование

Подводя итог всему вышесказанному, привожу способ интеграции кода в ваше приложение.

Класс Ads:

public class Ads {
	// замените на реальное значение высоты баннера
	final private static int BANNER_HEIGHT = 75;

	public static void showBottomBanner(Activity activity)  {
		// замените на реальный код для работы с вашим рекламным сервисом

		final Banner banner = new Banner(activity);

		banner.setBannerListener(new BannerListener() {
			@Override
			public void onReceiveAd(View view) {
	                        // добавить отступ снизу
				setupContentViewPadding(activity, true, BANNER_HEIGHT);
			}
		});

		FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
				FrameLayout.LayoutParams.MATCH_PARENT, 
				height);//  Utils.toDIP(activity, BANNER_HEIGHT));

		layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
		activity.getWindow().addContentView(banner, layoutParams);
	}

	public static void setupContentViewPadding(Activity activity, boolean top, int margin) {
		View view = ((ViewGroup) activity.getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0);
		if (top)
			view.setPadding(view.getPaddingLeft(), margin, view.getPaddingRight(), view.getPaddingBottom());
		else
			view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), margin);
	}
}

Замените код в методе showBottomBanner на вызовы API вашего рекламного сервиса.

Чтобы разместить баннер, добавьте строчку кода Ads.showBottomBanner(this) в метод Activity onCreate.

Заключение

В статье я привёл описание как интегрировать баннеры в приложение наиболее корректным и простым способом. Есть и другие способы размещения баннеров. Например, можно взять первый экран показанный в статье и разместить баннер не снизу, а между элементами.

Надеюсь, статья была полезна для вас.

Пожалуйста, пишите ваши замечания в комментариях.

Благодарю за внимание. Успехов вам в разработке!

Комментарии (6)


  1. datacompboy
    13.07.2015 17:54
    +3

    А разве их не специально встраивают так, чтоб чуть-чуть перекрывало контролы, для повышения CTR?


    1. sergeyotro
      13.07.2015 18:19

      Это противоречит правилам AdMob, можно предпреждение/бан схватить, если реклама будет слишком близко к контролам.


      1. datacompboy
        13.07.2015 18:20

        Интересно, а как пожаловаться? Я десятки «игрищ» видел, вполне себе из топа, с такой радостью.


        1. pyra
          13.07.2015 22:51
          +1

          в баннере есть i в кружочке, если нажать то будет три кнопки. Одна из них «Ad covers the page»


          1. datacompboy
            14.07.2015 11:10

            значит это не адмоб, так как никаких кружочков нет.


    1. BitGriff Автор
      14.07.2015 11:41
      +1

      Нашей мотивацией было даже не то, что могут забаннить. А то, что реклама не должна портить функциональность приложения.
      Это ладно, если баннер стоит поверх фона или чего-то не важного, но он создавать проблемы пользователю, если что-то перекроет.