Pull to refresh

Увеличиваем прибыль от iOS приложения втрое. Никакого продвижения, только техника…

Reading time 6 min
Views 74K
Привет, Хабрахабр!

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



Кому интересно, добро пожаловать под кат.

Название приложения называть не буду, скажу лишь, что обитает оно в категории Productivity. Платная версия увидела свет в день появления первого iPad, что не удивительно, т.к. изначально работала только на планшетах. Через полгода появилась версия для iPhone (universal app). Еще чуть позже — урезанная по функционалу, бесплатная версия с кнопкой, ведущей на покупку полной (отдельное приложение в AppStore).

Так они и существовали до января 2012 года. В бесплатной версии также присутствовала реклама, однако я так и не придумал, как же мне считать конверсию (бесплатная -> платная). Ситуация также усугублялась тем, что из бесплатной версии был «выпилен» код, который отвечал за синхронизацию, и, как следствие, пользователи не могли перенести данные при покупке полной версии (возвращать его было лень, codebase уже сильно разошлись).

Решено было удалить бесплатную версию и на ее место выпустить «пробную» с возможностью приобретения через in-app purchase полного функционала. Я уже и не помню, почему решил делать третье приложение, но оригинальная бесплатная версия до сих пор присутствует в AppStore и доступна только в Уганде (может, потому, что до сих пор с нее капают деньги за рекламу – пара долларов в день; хотя это ничего и не объясняет…).
Эксперименты с ценой я давно забросил, определив для себя оптимальную цену в $2.99. Это цена как полной версии, так и «разлочки» пробной; на протяжении всего периода, который я буду рассматривать, цена не менялась.

29 февраля 2012 года приложение попало в AppStore. Зная об ограничении в 20 МБ для загрузки приложений через сотовые сети, я добился размера приложения чуть меньше этого лимита. В приложении используется действительно много красивой и качественной графики (не спрашивайте, зачем это нужно для productivity приложения – просто это одна из «фишек», так надо).

И тут, как гром среди ясного неба, Apple совершила очередной технологический скачок. Я о Retina Display на iPad 3 — пришлось перерабатывать графику. С большим трудом я уложился в новый лимит – 50 МБ.



В течении четырёх месяцев приложение размером 50 мегабайт скачивалось в среднем 750 раз в день. Именно этот этап (на иллюстрации отмечен как этап «2») возьмем за точку отсчета (первый этап будем считать органическим ростом). Еще раз повторю, никакой раскрутки пробной версии не проводилось вообще.

Знаете, за несколько лет присутствия моих приложений в AppStore, я привык рассматривать отсутствие роста (загрузок, продаж) как неудачу. Нужно было что-то делать!

Но чудес не бывает — JPEG сильно не ужмешь. Единственным решением (которому я долгое время противился) оказалось вынести hi-res изображения для загрузки уже после установки. Набор ресурсов для iPhone и не-retina iPad остался в приложении, а 2048x2048 картинки «переехали» на сервер. Загрузка осуществлялась при первом обращении, в фоне. Если не вглядываться, то на новом iPad можно было и не заметить особой разницы (но она все таки была – значит нужно было грузить).

Я боялся бурной реакции пользователей за расход их интернет трафика. Но оказалось, что зря. Видимо, пользователи продукции Apple могут себе это позволить. Ни одной жалобы за более чем полгода не поступило.

Итак, этап «3» – 17 МБ. Эксперимент удался! Количество загрузок (ну и доход) выросли в полтора раза (в среднем 1200 в день). Но что же это??? Опять Apple “думает иначе”. На сцену выходит iPhone 5 с увеличенным экраном высотой 1136 px, а размер ресурсов в приложении (тех, что не скачиваются с сервера) — 1024х1024. Перфекционизм не позволяет мне игнорировать нехватку 112 точек. Шоу продолжается…

Принято решение взять рубеж в 10 МБ. Теперь в приложении остаются только 3 ресурсных файла, но уже размером 2048х2048 (из них в рантайме “вырезается” нужный размер, разумеется единожды – далее кэшируется), а остальные переезжают на сервер.

При этом на сервере ресурсы теперь именно в том разрешении, которое требуется устройству (320x480, 640x960, 640x1136, 1024x1024 и 2048x2048), что позволяет снизить трафик на сервере (в пике 90 Гб в месяц) и трафик у пользователей.

Как результат — этап «4» — 9.8 МБ. И очередное подтверждение наличия зависимости количества закачек от размера – 1700 в день. Напомню, это в два с лишним раза больше, чем наше «референсное» значение 750. Ну и доход, само собой… При том что минимальной поддерживаемой версией iOS теперь стала 4.3 (спасибо Apple, до этого момента приложение отлично работало и на 3.0).

Пару месяцев все складывается удачно. Но роста опять нет! Что же делать? Именно в этот период стали появляться сервисы вроде searchman.com, предлагающие компаративный анализ метаданных приложения и советующие изменения. Я поигрался с одним из них, и мне удалось пропихнуть в название приложения кучу ключевых слов. Ну, знаете как это бывает: %APP_NAME% — the best ever free mega tool for creating and managing %feature1%, %feature2% and %feature3% for iPhone, iPad, iPod Touch – free version, try me please. Ключевые слова вместе с незначительным уменьшением размера (до 9 МБ, этап «5») дали еще больший рост. К концу этапа я имел в среднем 3000 загрузок в день!

Этап «6» — проверка: до каких же пределов верна теория? Все PNG пережаты в JPEG с отдельным альфа-каналом (PNG). Так же, практически все PNG вынесены на сервер для загрузки (благо, технология отработана). Загруженные PNG используются вместо псевдо-AJPEG (разница всё-таки есть). Размер 2.9 МБ. Эффекта НЕТ! Вот он и предел.

Этап «7». Видя отсутствие эффекта от уменьшения размера, решаю отступить назад к отметке 5 МБ, т.к. использование псевдо-AJPEG немного попортило внешний вид элементов интерфейса. Цензоры Apple не пропускают название. Дилемма – или не выпускать апдейт (они не настаивают на изменении названия существующей версии), или проверить теорию влияния ключевых слов в названии, убрав их. Соглашаюсь с Apple — возвращаю название. Результат — падение до 2200 закачек в день.

Фактически, этапы 5 и 6 следует исключить из рассмотрения влияния размера на количество закачек (они оставлены только для сохранения хронологической последовательности), ибо изменения в них обусловлены в большей степени «хаком» с ключевыми словами.

Вывод: 50 МБ = 750 закачек, 5 МБ = 2200 закачек. Увеличение загрузок/дохода в три раза. Шутки ради, можно даже вывести приблизительную формулу: new_downloads ≈ sqrt(old_size / new_size) * old_downloads.

Я понимаю, что если Ваше приложение и так сильно меньше 10 МБ, то этот способ не для Вас. Но если больше – подумайте над оптимизацией. 5, 10, 20% прироста лишними не бывают.

Вы спросите про деньги? Отвечу, что конверсия (приведенная с учетом рекламы) составляет в среднем 2%. Так же отмечу, что даже на пике загрузок (3000 в день), бесплатная версия ни разу не приносила больше чем платная.

Версии программы существуют для iOS, Windows Phone, Windows 8 (Metro), Android (сейчас не доступна, выпускалась по франшизе другой компанией; скоро выйдет на весь мир в «улучшенном» виде; пользователи Android при виде приложения в 35 МБ «сходили с ума»). MacOS версия в разработке. А самая старая Win32 версия 2008 года выпуска до сих пор продается в среднем один раз в месяц. Продажи на Windows Phone и Windows 8, мягко говоря, смешные. Но на Windows 8 — конверсия 20% (это слабо укладывается в моей голове). Думаю, как продвинуться в Windows Marketplace? Если у кого есть идеи/опыт, пожалуйста, поделитесь – на какие сайты проситься на обзоры и т.д.

Из технических моментов хотел бы отметить необходимость «прогнать» все графические ресурсы через оптимизатор PNG/JPEG – мне это дало 7% уменьшения размера. Также не помешает упростить splash screen. В приложении 7 файлов, они показываются буквально на секунду. Убрал все градиенты и тенюшки, перевел в 8bit — сэкономил пару сотен килобайт.

Про рекламу: Apple iAd работает далеко не во всех странах, так что имеет смысл при ошибке показа iAd показывать рекламу из другого источника. Я использую Google AdMob. Да, я слышал про AdWhirl, но мне лень с ним разбираться – ротатор уже написал и отладил. eCPM держится на уровне $0.3 у AdMob и $0.5 у iAd, но количество показов AdMob в разы превосходит iAd. Да, еще я ротирую рекламу раз в 45 секунд (iAd->AdMob->iAd, а если iAd не доступен, то AdMob->AdMob…) – это дало мне порядка 30% прироста доходов от рекламы. Нет, мне не жалко трафика пользователя пробной версии, уж простите.

Может, кому пригодится код для поддержки псевдо-AJPEG. Все проверки вырезаны – я себе доверяю. Жесткая конвенция именования: image.png + image_mask.jpg. Обращение по имени без расширения. Поддержка кэша (без него – вообще 6 строк кода). За основу для чего-то более гибкого (если оно Вам нужно) — вполне сойдет.

#define maskedCacheStorePath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"maskedImageCache"]

+ (UIImage *)maskedImageNamed:(NSString *)imageName useCache:(Boolean)useCache {
    NSString *imageCacheStoreFile = nil;
    
    if (useCache) {
        if (![[NSFileManager defaultManager] fileExistsAtPath:maskedCacheStorePath])
            [[NSFileManager defaultManager] createDirectoryAtPath:maskedCacheStorePath withIntermediateDirectories:YES attributes:nil error:nil];
        imageCacheStoreFile = [maskedCacheStorePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]];
        if ([[NSFileManager defaultManager] fileExistsAtPath:imageCacheStoreFile])
            return [UIImage imageWithContentsOfFile:imageCacheStoreFile];
    }
    
    UIImage *image = [UIImage imageNamed:[imageName stringByAppendingPathExtension:@"jpg"]];
    UIImage *mask = [UIImage imageNamed:[[imageName stringByAppendingString:@"_mask"] stringByAppendingPathExtension:@"png"]];
    
    CGImageRef ref = CGImageCreateWithMask(image.CGImage, mask.CGImage);
    UIImage *result = [UIImage imageWithCGImage:ref scale:image.scale orientation:image.imageOrientation];
    CGImageRelease(ref);
    
    if (useCache && result)
        [UIImagePNGRepresentation(result) writeToFile:imageCacheStoreFile atomically:YES];
    
    return result;
}

За сим всё. Буду рад услышать о Вашем опыте и ответить на любые вопросы.
Tags:
Hubs:
+123
Comments 102
Comments Comments 102

Articles