На современных телевизорах, как мы знаем, можно устанавливать разные приложения, для облегчения работы с какими-то ресурсами и контентом. В большинстве случаев, эти приложения под капотом это обычный браузер, на теликах это Chromium.
Так как это браузер, то ничего нам не мешало использовать React.js для разработки, что повлияло на некоторые проблемы с производительностью.
Я не буду рассказывать о том, как именно нужно делать с примерами кода, я расскажу о нюансах и решениях, которые были приняты.
Пройдемся по основным моментам:
- Ограниченные ресурсы
- Навигация
- Производительность стилей и рендеринга
- Видео плееры
- Backend
Ограниченные ресурсы
На телевизоре не так много памяти и производительности, как на наших компьютерах, поэтому первая проблема это ограничение ресурсов.
Например для приложения выделяется всего около 250 мегабайт на использование и мы столкнулись с такой проблемой, что при отображении грида с контентом (картинка, описание, рейтинг) могла расходоваться память на пределе, когда в гриде всего 1000 элементов и мы скроллим вниз, то размер картинок увеличивается и увеличивается и в какой-то момент приложение крэшится с надписью, что закончилась память.
Решение этой проблемы react-window
Он не хранит все элементы вне окна в DOM.
Навигация
Если на компьютере мы привыкли, что мы кликаем мышкой по элементам на сайте, то на телевизорах мы пользуемся пультом, который бывает и с возможностью использования как мышь, но в большинстве это кнопки. Отсюда вылазит проблема навигации, что мы должны обрабатывать нажатия кнопок пульта и навигировать по всему приложению без курсора, но, в то же время нам необходимо и обрабатывать нажатия на элементы с помощью «клика».
Некоторые коды кнопок на пультах LG и Samsung отличаются, как и отличаются от клавиатуры обычной, поэтому для каждой платформы у нас были захардкожены коды кнопок, которые мы обрабатываем.
Пример Tizen
Tizen
export default {
KEY_0: 48,
KEY_1: 49,
KEY_2: 50,
KEY_3: 51,
KEY_4: 52,
KEY_5: 53,
KEY_6: 54,
KEY_7: 55,
KEY_8: 56,
KEY_9: 57,
KEY_UP: 38,
KEY_DOWN: 40,
KEY_LEFT: 37,
KEY_RIGHT: 39,
KEY_OK: 13,
KEY_BACK: 10009,
KEY_CHANNEL_UP: 427,
KEY_CHANNEL_DOWN: 428,
KEY_MEDIA_FAST_FORWARD: 417,
KEY_MEDIA_PAUSE: 19,
KEY_MEDIA_PLAY: 415,
KEY_MEDIA_PLAY_PAUSE: 10252,
KEY_MEDIA_REWIND: 412,
KEY_MEDIA_STOP: 413,
KEY_DEBUG_TOGGLE_CONSOLE: 403,
KEY_DEBUG_TOGGLE_QUICK_EDIT: 404,
KEY_DEBUG_SET_FAVOURITES: 405,
KEY_DEBUG_CLEAR_FAVOURITES: 406,
KEY_SHOW_REMOTE_POINTER: 7777777, // not applicable
KEY_HIDE_REMOTE_POINTER: 7777777, // not applicable
};
WebOS
export default {
KEY_0: 48,
KEY_1: 49,
KEY_2: 50,
KEY_3: 51,
KEY_4: 52,
KEY_5: 53,
KEY_6: 54,
KEY_7: 55,
KEY_8: 56,
KEY_9: 57,
KEY_UP: 38,
KEY_DOWN: 40,
KEY_LEFT: 37,
KEY_RIGHT: 39,
KEY_OK: 13,
KEY_BACK: 461,
KEY_MEDIA_FAST_FORWARD: 417,
KEY_MEDIA_PAUSE: 19,
KEY_MEDIA_PLAY: 415,
KEY_MEDIA_PLAY_PAUSE: 10252,
KEY_MEDIA_REWIND: 412,
KEY_MEDIA_STOP: 413,
KEY_CHANNEL_UP: 33,
KEY_CHANNEL_DOWN: 34,
KEY_DEBUG_SET_EMAIL: 403,
KEY_DEBUG_TOGGLE_CONSOLE: 404,
KEY_DEBUG_TOGGLE_QUICK_EDIT: 405,
KEY_DEBUG_SET_FAVOURITES: 406,
KEY_DEBUG_CLEAR_FAVOURITES: 407,
KEY_SHOW_REMOTE_POINTER: 1536,
KEY_HIDE_REMOTE_POINTER: 1537,
};
Клавиатура
export default {
KEY_0: 48,
KEY_1: 49,
KEY_2: 50,
KEY_3: 51,
KEY_4: 52,
KEY_5: 53,
KEY_6: 54,
KEY_7: 55,
KEY_8: 56,
KEY_9: 57,
KEY_UP: 38,
KEY_DOWN: 40,
KEY_LEFT: 37,
KEY_RIGHT: 39,
KEY_OK: 13,
KEY_BACK: 8, // backspace
KEY_MEDIA_FAST_FORWARD: 70, // f
KEY_MEDIA_PLAY_PAUSE: 80, // p
KEY_MEDIA_REWIND: 66, // b
KEY_MEDIA_STOP: 83, // s
KEY_CHANNEL_UP: 70, // f
KEY_CHANNEL_DOWN: 71, // g
KEY_DEBUG_SET_EMAIL: 81, // q
KEY_DEBUG_TOGGLE_CONSOLE: 87, // w
KEY_DEBUG_TOGGLE_QUICK_EDIT: 69, // e
KEY_DEBUG_SET_FAVOURITES: 88, // w
KEY_DEBUG_CLEAR_FAVOURITES: 82, // r
KEY_SHOW_REMOTE_POINTER: 7777777, // not applicable
KEY_HIDE_REMOTE_POINTER: 7777777, // not applicable
};
Как можно заметить, на клавиатуре это кнопки с буквами (в комментариях указаны).
Для того, чтоб обрабатывать навигацию через нажатие кнопок и нажатие мышью, у нас результатом был всегда один event — mouseClick, тем самым мы одинаково обрабатывали все события.
Другой особенностью навигации является фокус, на каждом экране должен быть элемент в фокусе, потому что потеряв фокус, мы уже не сможем навигировать по экрану. Каждому элементу прописывались свойства focus и id фокуса. При навигации нужно было всегда это учитывать, но и к тому же, иногда возникает требование при возвращении назад восстанавливать состояние полностью предыдущего экрана, поэтому навигация была написана полностью кастомная.
Производительность стилей и рендера
Анимация на CSS работает медленно на телевизорах, особенно, когда DOM элементов, которые попадают в анимирование много, можно увидеть не плавное изменение а слайд-шоу. Один из вариантов решение этой проблемы — canvas. Отрисовка на нем, анимация, подсветка при навигировании ускоряют работу в разы, но, если у вас есть автоматизаторы, то им такая реализация может не понравиться, т.к им сложно по картинке проверять контент.
Много перерендереваний на странице — еще одна боль, все начинает тормозить, дергаться. Нужно было максимально контролировать этот процесс, после чего shouldComponentUpdate компонентов выглядит так:
В итоге переписали чувствительные части приложения на vanilla js, стало быстрее.
Видео плееры
У LG и Samsung разные видео плееры, что тоже создает дополнительные трудности при разработке. Для LG используется video-тег, для Samsung AVPlay sdk. Поэтому есть отличия в функциональности, нужно учитывать, что не все возможности одинаковы и могут отличаться от версии к версии ОС.
Также были проблемы с нагрузкой при запуске видео — решалось кэшированием, параллелизацией и откладыванием запросов, обработок.
Backend
На скорость работы влияет качество бэкенда, скорость обработки запросов и их количество. На стороне FE должно быть минимальное количество обработки данных. Если нужно подгружать большие объемы даных, можно использовать web workers.
Комментарии (19)
harry2019
19.09.2019 11:21В большинстве случаев, эти приложения под капотом это обычный браузер, на теликах это Chromium
Что понимается под «большинством случаев»? Например, на моем LG 32" (Smart) стоит именно Chrome, причем ну очень старенький, 28-ая версия.yantishko Автор
19.09.2019 11:31В спецификации либо WebKit, либо Chromium.
webostv.developer.lge.com/discover/specifications/web-engine
В статье имелось ввиду, что приложение может быть написано на .net, и это уже будет не браузер
leotada
19.09.2019 11:30Если позволите, еще дополню ссылками. В jsunderhood была неделя разработчика под смарт тв. Архива нет, но вот несколько веток с интересными особенностями такой разработки:
twitter.com/jsunderhood/status/1172215584303570945
про выкладывание в сторы
twitter.com/jsunderhood/status/1172224195536838656
про написание приложений под тв
twitter.com/jsunderhood/status/1172194802076663808
на что похожа разработка под смарт тв
pahonski
19.09.2019 12:17Подскажите, а какой плеер вы использовали для webOs, какой там SDK?
yantishko Автор
19.09.2019 12:33Для WebOS использовался HTML5 тег video и работа велась с ним.
Для взаимодействия с WebOS использовалась Web API webostv.developer.lge.com/api/webostvjs/webos
Для Tizen использовался AVPlay developer.samsung.com/tv/develop/guides/multimedia/media-playback/using-avplay
wrqqq
19.09.2019 12:57Маловато. Не очень понимаю в чем цель статьи?
Вы перечислили несколько проблем, ок. Но никаких выводов, никаких интересных поворотов.
Тоже что ли пойти написать статью как я вчера вебпак настраивал.
vitalets
19.09.2019 15:22Дополню еще ссылкой на подборку awesome-smart-tv, где собраны полезные библиотеки и фреймворки для смартов.
Кстати, в контексте статьи было бы интересно узнать, пробовали ли вы react-tv? Кажется там некоторые тв-специфичные проблемы должны быть решены.
yantishko Автор
20.09.2019 11:41Спасибо за ссылку.
На практике не пробовали react-tv, но есть и + и -, поддержка только webOS, ну и использование не проверенной библиотеки на enterprise проектах чревато. Когда разработка стартовала, на тот момент react-tv только появился и был сыроват.
А так да, он решает многие проблемы, может у кого был практический опыт использования react-tv?
i360u
19.09.2019 16:17Для меня главным ограничением в Tizen стала древняя версия Chromium, которая имеет проблемы с поддержкой многих вещей, к которым мы давно привыкли в современных браузерах. У Samsung все ОЧЕНЬ ПЛОХО с обновлениями SmartTV: большинство продающихся на рынке телевизоров работают на версии Tizen, которую не поддерживает их-же собственный SDK. И обновить их нельзя. Ну и React там, конечено, совсем не нужен.
technic93
19.09.2019 20:14Приставочку на андроид прикупить дешевле. Хотя на моем Самсунге Ютуб и нетфликс более менее работают из коробки.
some_x
После прочтения статьи появляется вопрос, почему для телевизоров пишут на web-технологиях, если там так мало ресурсов? Больше подошло бы что-то вроде Qt.
JustDont
Скорее уж появляется вопрос — почему на медленных и ресурсоёмких веб-технологиях? Реакт с его виртуальным DOM, серьезно? А между реактом и vanilla.js прям вообще ничего нет?
yantishko Автор
Тут приводится проблемы конкретно для React.js, это естественно не единственный способ реализации приложения для телевизоров :) А что между реактом и ванилой вы предлагаете?
leotada
svelte.dev
mustlab.ru/ru судя по докладам и статьям PaulMaly уже несколько лет успешно используют svelte для разработки под ТВ.
yantishko Автор
спасибо, почитаю
JustDont
Всё, что левее реакта. Там конечно далеко не всё предлагает высокую степень абстрагирования от деталей, но там много и высокоуровневых фреймворков. Да тот же даже preact намного быстрее и тоньше. И про svelte уже сказали — тут как раз отличный кейс для неё, да.
yantishko Автор
Tizen позволяет писать на .net, WebOS не вижу такой поддержки. Основная идея была — переиспользование кода между разными ОС теликов и использование общей sdk для web части