Перейти к содержанию

Кейс · Мобильные приложения, Веб и SaaS

IRK.Today обновлённое приложение городского издания

Приложение «Иркутск Сегодня» издания IRK.Today: новости Иркутска и Братска, афиша с покупкой билетов, погода и пробки. Мы перевели его на новый дизайн, починили вход и ссылки и выпустили новую версию в App Store, Google Play и RuStore.

8версий в App Store за 12 дней — от исправлений 5.4 до нового дизайна 6.0
640+автотестов приложения проходят
3магазина — App Store, Google Play и RuStore, выкладка одним скриптом

Паспорт проекта

Клиент
ООО «Иркутск Сегодня»
Отрасль
Медиа
Срок
17 дней
Команда
Команда E404 и ИИ-агенты

Стек

FlutterDartRiverpodSwiftKotlinWordPress REST APIFirebaseAppMetrica
Проект вживую ↗

Задача

IRK.Today — городское издание Иркутска. Есть у него и издание для Братска (Иркутская область): его лента — на отдельном сайте. Приложение «Иркутск Сегодня» в App Store с июля 2018 года, одно на оба города: город выбирают при первом запуске. Собрано оно было на шаблоне новостного приложения NewsPro, и от шаблона в коде осталось много лишнего.

Когда мы начали, в приложении было что чинить:

  • iOS-версия не собиралась: файлы входа через VK и Яндекс не были подключены к проекту Xcode;
  • ссылки на статьи — из мессенджеров и с других сайтов — открывались в браузере, а не в приложении;
  • из статей молча пропадали редакционные блоки «Справка», «Врезка» и «Прямая речь»;
  • вход для комментариев через VK и Яндекс заканчивался ошибкой.
Главная старой версии: новость дня, спецпроект, нижняя панель из пяти значковСтатья старой версии: обложка, заголовок, рубрики, справа плавающая панель «A+», «A−» и смена темы; подпись автора закрыта плашкойАфиша старой версии: вкладки рубрик, ближайшие события, кино
Было — версия 5.4: пять значков внизу с подписью только у выбранного, кнопки размера текста поверх статьи, прежняя афиша

Параллельно владелец издания хотел новый дизайн. По нашему описанию всех функций и экранов приложения получился макет из 14 разделов — от дизайн-системы до планшета. Условие было одно: читатель не должен получить наполовину перекрашенное приложение. Поэтому новый дизайн до готовности был выключен флагом сборки и вышел одной версией 6.0, а до неё в App Store выходили только исправления старой версии.

Оценки и скачивания копились в магазинах приложений годами (в App Store — с 2018 года), это не итог редизайна. Данных аналитики «до и после» у нас нет, поэтому аудиторию не сравниваем.

Что сделали

Новый дизайн всех экранов

Внизу четыре вкладки с подписями: Главная, Афиша, Город и Моё. «Пульс» живёт внутри главной: хроника, свежие комментарии, ближайшие события и топ недели. Искать можно сразу по новостям и афише. Шрифты — Raleway для интерфейса и Lora для текста статей. Есть тёмная тема и отдельная раскладка для планшета: от 768 точек экран делится на колонки.

Главная приложения «Иркутск Сегодня»: логотип, чипы «Сейчас 0 °C» и «Пробки 1 балл», поиск, вкладки рубрик, крупная новость дня и карточка спецпроектаВкладка «Пульс» на главной: подвкладки «Новости», «Комментарии», «Афиша», «Топ недели» и пронумерованный список статей с просмотрамиРезультаты поиска «байкал»: вкладки «Всё», «Новости», «Афиша», найденное событие и новости
Главная с погодой, пробками и поиском в шапке; в «Пульсе» — самое читаемое за неделю; поиск — сразу по новостям и афише

Цвет города задаётся в админке сайта, и приложение подхватывает его без нового выпуска. У Иркутска синий, у Братска — оранжевый.

Главная на iPad: шапка с погодой, пробками и поиском, вкладки рубрик, крупные новости, спецпроекты, справа — пронумерованный «Топ недели»
Главная на планшете: слева главное и спецпроекты, справа «Топ недели»

Чтение

Размер текста меняется в одно касание — пять ступеней от 16 до 24 пунктов. Фоторепортажи листаются на весь экран, как на сайте. Аудио играет во встроенном плеере, видео открывается по обложке. «Сохранить» скачивает материал: он откроется и без интернета.

Статья о снегопаде: фото дороги, хештеги рубрик, заголовок, дата, «1 мин чтения», просмотры и комментарии; подпись автора закрыта плашкойШторка «Размер текста» поверх статьи: кнопки от 16 до 24 пунктов, выбрано 18Список «Доступно без сети»: статьи с обложками и крестиком «убрать»
Статья с обложкой и счётчиками, размер текста в одно касание, сохранённое — без интернета
Фоторепортаж с конкурса «Директор года»: снимки мероприятия друг под другомФото на чёрном фоне на весь экран, вверху крестик и счётчик «32 / 32»
Фоторепортаж: снимки во всю ширину, по касанию — на весь экран и листание по всей галерее
Аудиоплеер крупно: круглая кнопка паузы, надпись «Аудио», полоса перемотки и «0:09 / 0:40»
Аудио в тексте статьи — свой плеер с перемоткой
Статья о матчах Суперлиги по хоккею с мячом на iPad: фото во всю ширину, рубрики, заголовок и текст узкой колонкой; подпись автора закрыта плашкой
Статья на планшете: обложка во всю ширину, текст — колонкой по центру

Афиша и покупка билета

Путь до билета:

  1. Афиша: подборки, вкладки рубрик, фильтры «Пушкинская карта», «Детям», «Бесплатно» и календарь.
  2. Событие: статус, место и кнопка «Билеты от …».
  3. Выбор сеанса — по дням и площадкам.
  4. Предупреждение, что откроется сайт кассы, — только при первой покупке. Событие сохраняется, и, если уведомления разрешены, за 2 часа до начала приходит напоминание.
  5. Касса — виджет Afisha.ru.
Афиша: вкладки рубрик, фильтры «Пушкинская карта», «Детям», «Бесплатно», карточки ближайших событий и киноСтраница фильма «Мастер Витя и Мотор»: дата, кинотеатр, «от 250 ₽», возраст 0+, сведения о фильме и сеансы с кнопками «Купить билет»Шторка «Выберите сеанс, шаг 1 из 2»: дни недели плитками, сеанс 10:00 за 250 ₽ и кнопка «Перейти к оплате · 250 ₽»
Афиша, страница события и выбор сеанса

Город

Погода сейчас и на 10 дней, пробки по шкале «Яндекс Пробок» и погода в городах области.

Вкладка «Город», раздел «Погода»: +2 °C, ясно, ветер, влажность, давление и прогноз по днямРаздел «Пробки»: круговая шкала с баллом «1», подпись «Дороги свободны», легенда шкалы и источник данных
Погода сейчас и на 10 дней; пробки в баллах — по данным «Яндекс Пробок»

Вход для комментариев

Отдельной регистрации в приложении нет: аккаунт появляется при первом входе. Чтобы написать комментарий, можно войти через VK ID, Яндекс ID, «Вход с Apple» на iPhone и iPad или по коду из письма, без пароля. Аккаунт удаляется прямо в настройках.

Настройки: «Вы читаете без входа», кнопка «Войти», уведомления, город, тема, размер текста и материалы без сетиШторка «Войти в IRK.Today»: кнопки «Вход с Apple», «Войти через ВКонтакте», «Войти через Яндекс», «Войти по почте» и «Не сейчас»Шторка «Вход по почте»: поле «Электронная почта», кнопка «Получить код» и пояснение про «Скрыть e-mail» из iCloud
Читать можно без входа; войти для комментариев — через Apple, ВКонтакте, Яндекс или по коду из письма

Выкладка в три магазина

Версию в App Store, Google Play и RuStore выкладывает один скрипт через API магазинов: проверить состояние, загрузить сборку, отправить на модерацию. Кнопку «Отправить на проверку» в App Store нажимает владелец.

Страница «Иркутск Сегодня» в App Store: иконка, «Новости, афиша, погода, пробки», оценка 4,5, скриншоты нового дизайна
Страница приложения в App Store с версией 6.0.3

Как устроено

Схема: скрипт выкладки отправляет сборки в App Store, Google Play и RuStore, оттуда приложение попадает к читателю на iPhone, iPad и Android. Приложение на Flutter получает пуши с тегом города, берёт ленту, погоду, пробки и настройки из REST API сайтов Иркутска и Братска, даёт войти для комментариев через VK ID, Яндекс ID, Apple или код из письма, ведёт к покупке билетов в кассе Afisha.ru и шлёт данные в аналитику. Редакция работает в админке; сайты — два WordPress в одной сети.
Как устроено приложение: откуда данные, вход, пуши и выкладка

Приложение написано на Flutter: один код для iPhone, iPad и Android, вход через VK и Яндекс — на Swift и Kotlin. Данные идут из REST API двух сайтов на WordPress, объединённых в сеть. Город, выбранный при первом запуске, определяет сайт; пуши приходят с тегом города.

В админку вынесено то, что должно меняться без нового выпуска: цвет города и флаги функций. Так, вход по почте и «Вход с Apple» включаются галочкой на сайте.

Отдельное приложение Братска «Твой Братск» больше не нужно: оба города живут в одном.

Инженерные решения

Блоки, которые пропадали из статей

Проблема. Редакция пишет статьи со своими блоками — «Справка», «Врезка», «Прямая речь». В приложении они исчезали без следа, вместе с подписью автора цитаты.

Что нашли. Обработчик HTML объявлял, что умеет рисовать любой div, а на деле узнавал только контейнер видео. Любой другой div получал пустой виджет — и пропадал со всем содержимым. Ошибка сидела в коде с самого начала и уже была в версии из магазинов.

Решение. Обработчик забирает только то, что умеет нарисовать, остальное отдаёт штатному рендеру. В новом дизайне «Прямая речь» стала цитатой с автором, а «Справка» и «Врезка» — врезками, а тест держит их на месте.

Падение при входе через Яндекс

Проблема. Вход через VK заработал, а Яндекс ронял приложение ровно в момент ответа — и на успехе, и на ошибке.

Что нашли. SDK Яндекса рассылает уведомления внутри синхронного блока на своей очереди, а наш наблюдатель снимал себя прямо из уведомления — вложенный sync на ту же последовательную очередь. Это гарантированная взаимная блокировка.

Решение. Снимать наблюдателя и отвечать во Flutter на следующем витке главного цикла: к этому моменту очередь уже свободна.

let observer = LoginObserver { outcome in
    // Снимать наблюдателя прямо здесь нельзя: SDK рассылает уведомления
    // внутри sync на своей очереди, а remove(observer:) делает sync на
    // ней же — взаимная блокировка.
    DispatchQueue.main.async {
        detach()
        switch outcome {
        case .success(let login):
            result(login.token)
        case .failure(let error):
            result(FlutterError(
                code: isCancellation(error) ? "USER_CANCELLED" : "SDK_ERROR",
                message: describe(error),
                details: nil
            ))
        }
    }
}

Прокрутка статьи подтормаживала

Проблема. Владелец заметил, что длинная статья листается рывками. Замер на симуляторе: сборка кадра в среднем 15,4 мс, треть кадров дольше 16 мс — это заметные рывки.

Что нашли. Полоска прогресса чтения обновляла всю страницу почти на каждом кадре. Вместе с шапкой заново собиралась статья: HTML разбирался дважды, абзацы и фото строились с нуля.

Решение. Прогресс и шапку слушают только те, кому они нужны. Разобранный HTML запоминается.

// Прогресс чтения и «шапка поверх обложки» меняются на каждом кадре.
// Слушают их только шапка, кнопка «назад» и цвет строки состояния.
final _progress = ValueNotifier<double>(0);
final _compact = ValueNotifier<bool>(false);

void _onScroll() {
  final p = _scroll.position;
  _progress.value = p.maxScrollExtent <= 0 ? 0.0 : (p.pixels / p.maxScrollExtent).clamp(0.0, 1.0);
  final top = MediaQuery.paddingOf(context).top;
  _compact.value = !_hasCover || p.pixels > IrkArticlePage.coverHeight + top - (top + IrkSize.appBar);
}
Симулятор, отладочная сборка, 6 быстрых прокруток фоторепортажа До правки После правки Перемер
Сборка кадра в среднем 15,4 мс 2,8 мс 2,7 мс
Кадров дольше 16 мс 137 из 415 0 из 457 1 из 457

Шаг «прокрутка» в автоматическом обходе экранов теперь не проходит, если медленных кадров больше 5 %.

Результат

За 12 дней в App Store вышло 8 версий: сначала исправления старого приложения, затем новый дизайн. Через восемь дней после начала работ версия 6.0 была в App Store и Google Play, а 6.0.3 вышла во всех трёх магазинах; в RuStore новый дизайн пришёл сразу с ней.

Что До После
Вкладок внизу 5, подпись только у выбранной 4, подписи у всех
Автотестов приложения 211 643

App Store Google Play RuStore


Два отказа Apple. Проверка App Store дважды вернула новую версию: сначала Apple потребовала вход не хуже, чем через VK и Яндекс, а затем не признала таким вход по почте и попросила рабочий демо-доступ. По журналам сайта мы увидели, что проверяющий ввёл верный код, но на шаге с именем остановился и запросил код заново. Мы добавили «Вход с Apple», а демо-аккаунт завели заранее — код из письма пускает в него сразу, без шага с именем. Следующая проверка прошла.

Комментарии

Писать можно, войдя через VK ID, через Яндекс ID или по коду из письма. У комментария — имя и фото из профиля VK или Яндекса либо имя, которое вы укажете при входе по почте. Как мы обращаемся с данными — в политике конфиденциальности.

Поделиться записью

TGVK