Як ми розробили Android-застосунок і втратили все, крім досвіду
Привіт! Мене звати Сергій, я Director of Technology в Onix-Systems. Компанію засновано 2000 року, вона займається аутсорсингом для організацій зі США та Європи. За останні 8 років у нас було чимало різних проектів у різних напрямах. Часто в команді були люди, які, попрацювавши деякий час, говорили, що в аутсорсі нецікаво, а треба йти в стартапи й створювати свої продукти. Ми провели експеримент зі створення свого продукту всередині компанії, і я хотів би поділитися досвідом з тими, хто впевнений, що працювати над продуктом краще, ніж на замовлення.
Ми розробили YouStream ― мобільний застосунок з можливістю транслювання відео/аудіо з камер телефона й рестриму з екшен-камери. Проте виникла проблема через застосування іконки, схожої на ту, яку використовує YouTube. А потім ми й взагалі втратили доступ до облікового запису, під яким було створено проект у Google Cloud Platform для YouStream. Докладніше про це — нижче.
Експеримент проводили люди, які перебували на бенчі, для того щоб розвинути й продемонструвати нашу обізнаність у вузькій ніші. За весь час в проекті взяв участь один Android-розробник та один дизайнер. Пізніше у відділі маркетингу створили сайт проекту. Ми розраховували, що коли зможемо показати власний застосунок, до нас почнуть звертатися серйозні замовники, кому буде потрібен такий досвід, і ми можемо розробити для них потужніші рішення на базі нашої бібліотеки. Поки що до нас приходять студенти, які шукають рішення для своїх дипломних робіт і просять про допомогу.
Ідея
Колись у 2017 році в аутсорсингу часто траплялося завдання розробити мобільний застосунок, з можливістю транслювання відео/аудіо з фронтальної та головної камер Android-пристроїв + рестриму з екшен-камери типу GoPro й китайських аналогів.
Проаналізувавши готові бібліотеки й рішення на ринку, ми не знайшли жодного готового рішення, яке б задовольняло всі наші вимоги. Сирі, забаговані, написані на одному коліні бібліотеки, абсолютно не готові для продакшену. Деякі з них були платними, але працювали гірше за opensource-рішення. Основні проблеми наявних розробок були такі:
- жодна не вміє працювати з екшен-камерами;
- нестабільність;
- незрозумілі витрати пам’яті;
- відсутність типу масштабу для фрагмента попереднього перегляду;
- керування пропорціями прев’ю камери;
- відсутність логіки з перепід’єднаннями в разі втрати зв’язку;
- погана робота за умов нестабільного з’єднання;
- неправильне генерування часових міток для аудіо (на YouTube такий стрим має звукові артефакти);
- повільна робота на будь-яких пристроях;
- проблеми з ліцензіями тощо.
Реалізація
Після всього цього ми ухвалили рішення спробувати розробити свій велосипед. Розробляли бібліотеку декілька місяців. Увесь конвеєр кодування RTMP-протоколу зреалізовано в нативному модулі, написаному мовою C для максимальної продуктивності. Найскладніше було змусити коректно працювати одночасно два мережеві модулі для рестриму з екшен-камери, довелося дивитися підказки в соурскоді андроїду.
У результаті ми одержали aag-бібліотеку AVLib + демо + кастом-ліцензію, яка дає змогу використовувати продукт з комерційною метою без відкритого коду.
Технічні моменти, які хотілося б виокремити
Щоб одержати рестрим «прев’ю камери» з екшен-камери на RTMP-сервер, довелося патчити libRTMP і розв’язувати проблему одночасної роботи з двома мережевими інтерфейсами. Основною проблемою було змусити працювати libRTMP із сокетом, який під’єднано до вибраного мережевого з’єднання, яке створено на боці Java. У цій ситуації сокет, який створено на боці Java для визначеного мережевого з’єднання, що ми передавали в хащі libRTMP, через різний час закривала сама система, і ми не зрозуміли такої поведінки.
Довго ламаючи голову над цією проблемою, ми підійшли до неї з іншого боку: з’єдналися із сокетом, створеним усередині libRTMP через fwmarkd на задане мережеве з’єднання. Можливо, комусь це знадобиться.
Java side:
Network cellularNetwork; // request and obtain network // .... int networkId = Integer.valueOf(cellularNetwork.toString()); // get network id // pass id to rtmp stream module // and using fwmarkd bind socket to network
Native RTMP module:
const struct sockaddr_un SERVER_PATH = {AF_UNIX, "/dev/socket/fwmarkd"}; int attach_socket_to_network(unsigned networkId, int socketFd) { if (socketFd < 0) { return -EBADF; } struct FCommand command = {SELECT_NETWORK, netId, 0}; int resp = send_command(&command, socketFd); return resp; }
Усю рутинну роботу з повертання зображення, співвідношення сторін, переініціалізації прев’ю з камери було зроблено самостійно вручну. Нині це все, мабуть, не актуально, тому що Google зовсім нещодавно (у вересні 2019 р.) в альфа-версії випустив для цього нормальну бібліотеку.
Основні фічі бібліотеки:
- Швидка робота стримінгу. Ядро написане чистою мовою C.
- Стабільна робота на всіх пристроях, підтримка застарілих і повільних пристроїв з Android 4.1+.
- Підтримка транслювання з: головної камери, фронтальної, екшен-камери (типу GoPro), екрана пристрою (скринстримінг).
- Автовизначення потужності пристрою і встановлення оптимальної конфігурації стримінгу.
- Стабільність роботи в мережах з поганим зв’язком, логіка реконектів.
- Підтримка перевертання пристрою, зміна розміру без переініціалізації стриму.
- Налаштування: розмір фрейма, якість, бітрейт, вимкнення аудіо тощо.
- Інтеграція за один клік. Підтримка Activities and Fragments.
- Типи масштабів, корегування співвідношення сторін, повний життєвий цикл оброблення стриму.
- Простий інтерфейс без зайвих залежностей.
- Підтримка armv7a, armv8-64 20. Фокусування на екрані тапом.
- Запис стриму у файл.
Для демонстрації роботи бібліотеки AVLib було створено невеликий застосунок, щоб перевірити попит на такі рішення. Лише декілька екранів, простий, але яскравий дизайн. Застосунок дає змогу за один клік миттєво створити трансляцію на свій канал у ютубі й поділитися прямим посиланням на стрим.
Дата публікації в магазині Google Play — лютий 2018 р.
Розвиток застосунку
Перші півроку все було передбачувано. Непоганий рейтинг, стабільний невеликий приріст нових користувачів, але досить слабкий ретеншен (загалом, люди недовго користувалися застосунком). Яскравий дизайн робив свою справу. Застосунок установлювали, але активно не використовували. Попри це застосунок дедалі вище тримався в списку ранжування магазину Google Play.
Побачивши, що залучення нових користувачів відбувається природним шляхом, ми сконцентрували зусилля на втриманні користувачів, дотримуючись такого процесу:
- Генерування гіпотези на базі аналітики, результатів попередніх експериментів і зворотного зв’язку від реальних користувачів.
- Реалізація і перевірка гіпотези.
- Аналіз результатів.
Почали з додавання експериментальних фіч, які дають змогу втримати користувача в нашому застосунку (наприклад, чат).
Стратегія була така: формуємо беклог з фічами, одна фіча, реалізація, аналіз. Наші кроки:
- Спочатку додали туторіал, який пояснював, що таке стрим, куди він стримиться, і що таке YouTube. Пояснення, які дозволи користувач дає нашому застосункові й для чого.
- Декілька разів змінювали UI/UX, змінюючи іконки, кнопки й міняючи їх місцями. Чимало користувачів не розуміли, як створити стрим з екрана телефона або як змінити камеру для стрима Front/Rear. Спочатку в нас була одна кнопка перемикання всього, яку можна було клікнути, свайпнути або довго тримати, щоб перемкнути ― це було не очевидно. Не допоміг навіть екран з підказками, який ми додавали. У кінці вставили три кнопки, кожна з яких активує інше джерело стриму.
- Додавання чату було однією з тих змін, які дали хоч і невеликий, але приріст часу користування.
- Також спробували додати фічу запису стриму у файл, але користувалися нею зовсім мало.
Через декілька таких ітерацій, ретеншен і кількість активних користувачів збільшилися.
Потім ми зробили редизайн. Зберігаючи мінімалістичний функціонал, зосередившись на нюансах взаємодії користувачів з нашим застосунком.
Додали онбординг і розділ допомоги для користувачів, а також декілька дрібніших фіч. Після цього кількість завантажень та активних користувачів зросла. Усе було стабільно.
Проблема
Ми почали роботу над перетворенням нашої демки на повноцінний продукт, призначений для обізнаних геймерів-стримерів.
Після публікації чергового оновлення в Google Play з багфіксами, ми дістали відмову. У процесі листування зі службою підтримки в одній із чергових відписок побачили натяк на іконку нашого застосунку (яку, до речі, не змінювали від першого релізу). В одному з листів було зазначено: «Your app currently contains assets related to the app YouTube for Android TV». Ми нічого такого не використовували, але найбільш схожою на матеріали з YouTube з усіх наших небагатьох матеріалів оформлення була іконка.
Violation of Impersonation policy
Поточна іконка:
Змінили іконку ― знову реджект.
Знову листування зі службою підтримки ― причина така сама. Змінили іконку, деякі ресурси в застосунку ― реджект. Знову листування зі службою підтримки ― причина знову та сама. Нова іконка, оновлення дизайну ― апдейт прийнято.
У такий спосіб приблизно три тижні ґуґл не приймав наші оновлення. Зрештою через незрозумілі причини, приблизно за три реджекти поспіль, кількість інсталяцій, без будь-яких підстав почала пропорційно падати в усіх країнах у рази (на графіку падіння з початку квітня).
Останнє оновлення вже не врятувало ситуацію. Причина так і залишилася для нас незрозумілою. Схоже, що в алгоритмах Google Play реджекти, кількість порушень впливають на ранжування застосунків у результатах пошуку. А можливо, це звичайний збіг і проблема зовсім в іншому.
Це був крах. Апка різко опустилася в результатах пошуку, ніякі наступні оновлення не мали результату.
Втрата доступу
У застосунку YouStream використовується YouTube API для створення й керування трансляцією на своєму каналі. Від початку ми створювали демку й правильно не зберігали всі доступи. Тому доступ до облікового запису, під яким було створено проект у Google Cloud Platform для YouStream, було втрачено назавжди.
Розробляючи Android-застосунки, ми зазвичай для нових потреб створюємо новий тестовий акаунт у ґуґлі, тому що занадто велика інтеграція із сервісами, якими користуєшся особисто, і це не зручно. А також, коли ще треба комусь передавати керування, то логін з паролем від особистої пошти віддавати не хочеться. Наш застосунок використовує YouTube API v3, а це означає, що потрібно створювати проект у GCP й прописати в ньому авторизаційні дані від клієнтського застосунку (ім’я пакета й хеш ключа, яким підписано застосунок). Коли ми ще не планували такого розвитку, використали один з тестових акаунтів. Коли за три роки побачили, що є зростання і варто подивитися на статистику, чи не досягли ми лімітів ― перевірили всі тестові акаунти, до яких мали доступ, але ніде так і не знайшли дані про YouStream.
Щоб з тобою спілкувалися живі люди в підтримці ґуґл, потрібно бути платним користувачем GCP. Ми активували бронзовий пакет і на два тижні стали VIP-користувачами, яким відповідає підтримка. Після дуже тривалого листування з Google Cloud нам так і не вдалося відновити доступ до проекту в клауді для застосунку YouStream. Ми мали на руках лише ім’я пакета, хеш ключа і всі права на сам застосунок, але цього виявилося недостатньо для служби підтримки. Листування тривало близько двох тижнів. Приблизно після десятого листа служба підтримки зрозуміла, чого ми від неї хочемо й відповіла, що це неможливо, і що вони фізично не можуть відшукати в себе в клауді хеш нашого застосунку. Хоча, я думаю, що все вони можуть, але їм заборонено про це розповідати.
Висновки
Сам проект AVLib живе й надалі, але повернути популярність цьому застосункові нам не вдалося. Ознайомитися з ним можна в Google Play, а з бібліотекою, яка була використана в ньому, — на GitHub.
З набутого досвіду ми робимо для себе такі висновки:
- Користувачам подобаються яскраві кольори. На старті будь-якого застосунку треба робити максимально красивий та яскравий дизайн, що привертає увагу. Красивий застосунок приємно мати у своєму телефоні. Також потрібна базова функційність, яку можна нарощувати в процесі. На прикладі YouStream після кожного етапу редизайну в нас зросли показники Visitors ― First-time installers.
- За всяку ціну й максимально швидко потрібно виправляти помилки й оновлювати застосунок у Google Play після реджектів і банів.
- Суворо дотримуйтеся правил у Google Play Market. Працюйте лише з досвідченими провайдерами або попросіть зробити аналіз когось із більшим досвідом публікування програм. Реджект застосунку може вбити органічний трафік і загрожувати вашій популярності.
- Максимально ізолюйте ваші експерименти від зовнішніх факторiв (країна, сезонність, час доби і т. д.). Одна і та ж фіча може бути по-різному прийнята в різних країнах, в різний час. Тому необхідно враховувати це в експерименті і під час перевірки чергової гіпотези. Наприклад, викатуючи чергову фічу в період свят у вашiй таргет-країні ви, найімовірніше, отримаєте дуже спотворений результат, який може повести вас в iнший бiк від обраної ранiше стратегії.
- Для того щоб ваш застосунок був популярний, він не обов’язково повинен бути складним. Радше навпаки: що простіший поріг входу користувачів, то ймовірніше, що користувач проведе в ньому більше часу. Безумовно, для цього потрібно, щоб ваш застосунок робив щось корисне.
- Треба берегти ваш ґуґл-акаунт, використовувати 2FA.
- Підтримка ґуґл, на жаль, відповідає дуже неохоче й без чітких рекомендацій, тому важливо покладатися на досвід і професіоналізм виконавців. В Інтернеті можна знайти чимало інформації про те, як підтримка реагує на стандартні запити й може через незрозумілі причини заборонити публікацію застосунку або примушувати розробників оновлювати старі застосунки, погрожуючи заблокувати весь ґуґл-акаунт. Тому тут ми не одинокі.