Баннерная реклама в iOS-приложении16.10.2018 11:49
Сегодня мы открываем цикл статей о том, о чём обычно не говорят на технических конференциях и митапах. Этот и последующие посты расскажут, как устроен механизм монетизации в популярном в США развлекательном iOS-приложении iFunny, разработкой которого мы занимаемся. Реклама — один из основных способов монетизации бесплатных приложений. Но это сейчас, а какие варианты были в 2011 году, когда появился iFunny? Сервис изначально строился как крепкий, устойчивый бизнес, поэтому с самого первого дня компания решила не заигрывать с пользователями и не заниматься играми с условной капитализацией.
На тот момент основным вариантом монетизации было создать бесплатную урезанную версию сервиса, а затем пытаться продать основной функционал. Потребитель был молод, неопытен и не был готов расставаться с суммами больше одного доллара.
Несложная математика показывала, что при конверсии 10% получить ARPU больше 10 центов — задача практически невыполнимая.
Тогда пришлось задуматься, как ещё можно монетизировать продукт. Рекламная модель уже очень хорошо работала в вебе, и можно было предположить, что скоро она расцветёт и на телефонах. Вообще началом мобильной рекламной модели монетизации можно считать появление AdWhirl — сервиса, который позволял интегрировать SDK рекламных сетей и ротировать их. Его появление позволило поднять FillRate в среднем до 50% по рынку и сделать доход от рекламной модели хотя бы сопоставимым с однодолларовой продажей. Сам принцип имплементации всех возможных источников спроса и организации конкуренции между ними стал основным драйвером роста рекламной индустрии и продолжает эксплуатироваться по сей день.
Но чем сложнее система, тем менее стабильной она становится, что абсолютно неприемлемо для крупных сервисов уровня iFunny. Начав двигаться в этом направлении в 2011 году, компания создала один из самых эффективных механизмов работы с мобильной баннерной и нативной рекламой и увеличила показатель выручки на одного пользователя в 40 раз, что позволило развивать не только внутренние проекты, но и заняться инвестициями в другие компании.
MoPub и компания
С 2012 года мы перешли с AdWhirl на MoPub.
MoPub — это мобильная рекламная платформа с возможностью надстройки своих собственных модулей, которая включает в себя несколько больших инструментов:
MoPub marketplace — собственная рекламная биржа;
медиатор рекламных сетей для работы с внешними сетями;
механизм заказов, позволяющий самостоятельно размещать баннеры в собственном приложении и настраивать их показы.
Основные достоинства MoPub:
умеет работать с большинством рекламных сетей;
понятный механизм подключения новых сторонних сетей;
открытый исходный код;
огромное количество базовых настроек и таргетингов;
большое комьюнити вокруг сети, есть даже своя конференция.
Есть у MoPub и недостатки:
не принимаются пул-реквесты на GitHub и вообще отсутствует реакция на них;
панель управления очень сложная, и для разработчика при отладке требуется некоторое время, чтобы вникнуть в её структуру.
Сила в правде
Как говорил герой одного русского фильма: «Сила в правде». В этой части я расскажу о трудностях, с которыми нам, как разработчикам приложения, пришлось столкнуться после первых миллионов скачиваний iFunny, роста аудитории и рекламного трафика от более, чем 100 партнёров.
Контент
Рекламный рынок — очень закрытая «каста» технологических компаний, но при этом агрегаторы имеют большую сеть партнёров: от крупных компаний, которые работают с миллионными бюджетам, до мелких фирм, заточенных под конкретные целевые аудитории.
Эта закрытость и разрозненность партнёров, несмотря на премодерацию баннеров и достаточно жёсткие правила по рекламному контенту, позволяет не самым честным продавцам рекламы публиковать креативы, которые являются запрещённым или портят пользовательский опыт в приложении.
Можно выделить несколько основных категорий «непотребного» контента в рекламных баннерах:
порно-контент. В последнее время его появляется всё меньше, но тем не менее он имеет место быть. Мы не можем публиковать данный контент в статье, поэтому картинки тут не будет;
системные алерты в баннерах, пример можно посмотреть у одного из пользователей twitter.com/IfunnyStates/status/1029393804749668352
контент со звуком. Звуки не запрещены рекламными сетями, как и анимации, но если звук играет без взаимодействия с интерфейсом — это воспринимается пользователями как баг приложения и негативно влияет на пользовательский опыт;
привлечение внимания. Хороший баннер должен привлекать внимание пользователя, но не всегда это происходит честным образом: иногда в баннеры попадают мерцающие видео. Ещё один нечестный способ заставить пользователя тапнуть на баннер — имитировать интерфейс приложения, например так:
Кстати, в России обычный тап по этому баннеру может оформить платную подписку у некоторых операторов сотовой связи, и вы даже не узнаете об этом, пока не увидите детализацию. Это также нечестный способ работы с рекламой, но у операторов в США нет такой возможности.
Автоклики
Как показывает мой опыт, это крайне негативный для пользователей кейс. Используя возможности JavaScript, WKWebView или UIWebView, а также дыры внутри реализации рекламных библиотек, можно сделать рекламу, которая будет сама открывать контент баннера и уводить пользователя из приложения.
Для того чтобы повторить такую проблему на примере с MoPub, достаточно добавить в баннер javascript-код следующего содержания:
Это работало долго во многих версиях MoPub, вплоть до версии 4.13.
Исследуя реализацию MoPub, можно было генерировать более сложные ссылки, которые позволяли не только открывать рекламу на полный экран, но и отправлять пользователя в AppStore на определённое приложение и даже не учитывать показ баннера.
Кстати, в примечаниях к релизу версии 4.13.0 MoPub SDK для iOS нет информации об этом фиксе, так как это была достаточно серьёзная дыра в SDK, и нечестные партнёры MoPub эксплуатировали её достаточно активно. Как показывают логи, о которых расскажу дальше, ежедневно приходилось блокировать до 2 миллионов попыток открытия баннера без пользовательского взаимодействия с ним.
В случае с MoPub получилось найти и повторить проблему достаточно легко, но другие сети, с которыми работает iFunny, имеют закрытый код, и бороться с возникающими автокликами приходится посредствам блокировки баннеров или даже отключения сетей на некоторое время. iFunny плотно работает со всеми рекламными партнёрами и сообщает им о таких баннерах. Так как молодая аудитория iFunny интересна рекламодателям, то партнёры охотно идут навстречу и убирают из ротации подобную рекламу.
Краши
Краши — это всегда плохо. Ещё хуже, когда они случаются из-за зависимости с закрытым кодом, и повлиять на них можно только косвенно. За годы работы с рекламой в iFunnу выделили для себя несколько типов крашей, которые можно разделить на несколько групп.
Системные
Сюда относятся исключения в сетевой библиотеке, WKWebView (UIWebView), OpenGL. Прямо повлиять на этот тип крашей очень сложно, но на некоторые повлиять всё же удалось, предварительно изучив работу WebView-компонента с WebGL.
Причём происходят они исключительно при уходе в фон. Это связно с тем, что движок OpenGL не должен работать, когда приложение находится в фоновом режиме.
Фикс здесь оказался достаточно простым:
При уходе в фон нужно забрать скриншот баннера.
Удалить рекламную View с экрана, чтобы WebView-компонент перестал использовать OpenGL. При выходе из фона вернуть всё как было.
Это проблемы, которые происходят на стыке iFunny, Mopub и провайдера рекламы. Как правило, они возникают после обновления библиотеки провайдеров и из-за новых способов взаимодействия с ними.
Последний такой случай был в июне этого года, после очередного обновления одной из используемых библиотек. Новый способ инициализации библиотеки предлагал использовать синглтон для конфигурации настроек сети.
Обращение к нему дважды, как происходило в реализации, периодически вызывало фриз главного потока, поэтому пришлось обернуть инициализацию в dispatch_once.
QA-отдел iFunny умеет хорошо тестировать рекламные библиотеки, поэтому эта проблема была найдена в ходе тестирования обновления.
Неожиданные
Этот тип крашей вообще не поддаётся контролю, так как происходит без каких-либо изменений в клиенте.
Связаны они с обновлением бэкенда у партнёров и отсутствием обратной совместимости. Такие краши часто происходят у крупных провайдеров рекламы, но быстро исправляются, так как действуют на большое количество приложений одновременно.
Были случаи, когда crash free iFunny за сутки опускалось со стандартных 99,8% до 80%, а количество гневных комментариев в сторе исчислялось десятками.
Производительность
Баннерная реклама, как правило, использует WebView-компоненты для отображения рекламы, поэтому каждый показанный баннер — это инициализация нового WebView со всеми его зависимостями.
Кроме того, часть партнёров использует WebView и для общения с собственными бэкендом, так как баннерная реклама на мобильных устройствах — это потомок рекламы в вебе.
Бывает, что после обновления находятся утечки памяти внутри новой библиотеки. После появления в Xcode инструмента Memory Graph находить утечки в сторонних библиотеках стало гораздо легче, поэтому сейчас удаётся оперативно сообщать о них партнёрам.
Ниже — гифка работы iFunny в простое, когда реклама для пользователя отсутствует:
Решения
Но несмотря на все проблемы, описанные выше, iFunny работает стабильно и каждый день вызывает улыбки у миллионов своих пользователей.
За годы активной работы с рекламой у команды разработки появилось несколько инструментов, которые позволяют успешно мониторить рекламные проблемы и вовремя реагировать на них.
Система логирования
Сейчас система логирования исключений в iFunny распространилась на всё приложение: для этого используется собственный бэкенд с базой на ClickHouse и отображением в Grafana.
Но первой задачей для работы с логами в приложении стало именно логирование исключительных ситуаций в рекламе.
Для определения факта переадресации в iFunny есть несколько связанных компонент. Расскажу подробнее о каждой из них.
IFAdView
Это наследник от класса MPAdView (он отвечает за показ рекламы в MoPub).
В этом классе переопределён метод hitTest: withEvent:
Это триггер на открытие AppStore из приложения, мы перечисляем все доступные URL для этого.
IFAdsExceptionManager
Класс, который собирает в себя триггеры и генерирует запись исключения в лог.
Чтобы было понятно, какие есть триггеры, опишу каждый метод интерфейса этого класса.
- (void)triggerTouchView;
Метод для записи взаимодействия с рекламным баннером.
- (void)triggerItunesURL:(NSString *)itunesURL;
Триггер, который определяет, что происходит редирект в iTunes.
- (void)triggerResignActive;
Триггер для определения потери активности приложением. В нём происходит сравнение двух предыдущих триггеров.
- (void)resetTriggers;
Сброс триггеров. Вызываем при уходе в фон или когда открываем AppStore сами, например, когда отправляем пользователя поставить оценку в старых версиях iOS.
Свойства для записи последней успешно или неуспешно запрошенной и загруженной рекламы. Нужны для формирования сообщения в лог.
Видно, что алгоритм получился достаточно простым, но эффективным. Он позволяет отслеживать нам не только автооткрытия из MoPub, но и из других сетей.
В последнее время реклама с автооткрытием часто открывает SKStoreProductViewController, поэтому сейчас мы работаем над определением автооткрытия этого контроллера. Алгоритм определения этого исключения будет несколько сложнее, но здесь нам поможет Objective-C Runtime.
Локальный стенд
На основе системы логирования в iFunny также начали разрабатывать локальный стенд, чтобы в реальном времени получать и отлаживать рекламу, которую видят пользователи.
Стенд состоит из:
билд-агента
устройства
набора тестов для каждого провайдера
Одно из интересных решений, которое используется на стенде, — IDFA из жалоб пользователей для получения реальной рекламы.
Примерно с 2016 года мы перестали получать реальную рекламу, таргетированную на США, используя только VPN, поэтому приходится подменять IDFA устройства на IDFA реальных пользователей.
Делается это достаточно легко с использованием Objective-C Runtime и свизлинга. Нужно подменить метод advertisingIdentifier у класса ASIdentifierManager.
Для передачи с билд-агента пользовательского IDFA в билд используется метод, описанный в статье.
В заключении хочется сказать, что баннерная реклама отлично работает в США, и за семь лет её активного использования как основного способа монетизации в iFunny научились с ней хорошо работать.
Но несмотря на то, что баннеры приносят 75% доходов компании, постоянно ведётся работа над альтернативными способами монетизации и уже накоплен некоторый опыт в нативной рекламе и использовании рекламных аукционов на рынке США.