Ввиду живого интереса к прошлой статье о библиотеке Smartbox, которая призвана стать основой для любого кроссплатформенного SmartTv приложения, я решили описать, как же создать такое приложение разом для трёх вендоров SmartTv устройств:
Итак, в этой статье вы найдёте много полезного, если вы:
- Начинающий Smart'ист но имеете опыт в классических js/html приложениях
- Продвинутый js/html разработчик и ищите платформу для кроссплатформенного SmartTV решения
- Начинающий js/html разработчик и хотите начать с «Хардкора»
- Тестировщик которому нужно запустить приложения, разработанные третьими лицами
Статья получилась «пухлой» и с кучей спойлеров — потому оглавление:
- Тестирование приложения
- Запуск в эмуляторах вендоров(и удалённых устройствах)
- Запуск на SmartTv телевизорах
- Разработка приложения
- Ссылки на ресурсы для разработчиков
- Библиотека Smartbox
* Из-за того что, эта статья предназначена не только для разработчиков — первыми и, как показалось нашей команде, более интересными, идут пункты о запуске приложений в эмуляторах и конечных устройствах.
Тестирование приложения
Окунувшись в разработку SmartTv приложений, вы в конечном итоге будите вынужденны так или иначе тестировать своё творение. Дао тестирования для SmartTv состоит из последовательных пунктов:
- Тестирование в браузере
- Тестирование в эмуляторах вендоров
- Тестирование на конечных устройствах
Далее мы рассмотрим, два последних шага на пути тестировщика. Первый пункт не является специфичным, а потому Вы сами найдете много интересного, просто запустив приложение и нажав клавишу F12
в браузере. Еще одним «хаком» в тестировании является автоматизация этого процесса. В библиотеке, например, используется jasmine для тестов в среде запуска.
Запуск в эмуляторах вендоров
Далеко, как мы выяснили, не соответствующее реальности — это эмуляторы, поставляемые с каждым SDK. (Samsung, LG, Philips) В конечном итоге, запуски на эмуляторах должны стать для Вас не более чем самопроверкой. И работоспособное приложение в эмуляторе не может считаться заведомо работоспособным на устройстве. И напротив, если у Вас что-то не работает в эмуляторе, не факт что это фиаско.
Apps
с соблюдением регистра. На скриншотах вы найдёте пояснения.
(картинки кликабельны)
Дальнейший шаг в тестировании приложений сделала компания Samsung, запустив лабораторию на удалённых устройствах. Фактически, это реальные девайсы, позволяющие проверить все функции вашего детища, которые невозможно лицезреть в эмуляторах (например, работа плеера со всеми форматами, взаимодействие с системами DRM).
Для запуска нашего приложения, необходимо выбрать устройство на сайте лаборатории и следовать инструкциям:
Запуск на SmartTv телевизорах
Мы рассмотрим самый простой, на мой взгляд, способ установки и проверки приложений на конечных пользовательских устройствах. Для этого нам понадобится:
- Http сервер, с поддержкой php — для LG.
Я разместил приложение по адресу http://paunin.com/content/demoApp/index.html - Само приложение, его можно взять в репозитрии библиотеки Smartbox, в директории
demo/demoApp
;
Можно использовать адрес публичного демо http://immosmart.github.io/smartbox/demo/demoApp/, если у вас по какой-то причине нет HTTP сервера для публикации приложения. Однако, хочу заметить, что для возможности экспериментирования, и разработки приложения HTTP сервер необходим (если вы, конечно, не будите использовать альтернативные методы инсталляции, описанные в документации вендоров)
Краткая инструкция по всем вендорам(выжимка)
- Пользователь производит вход в аккаунт (кнопка А на пульте)
- Набирает в поле Уч.зап. Samsung: develop
- В поле пароль: 123456 (любой другой тоже должен подходить)
- Выбирает «Вход»
- Нажимает на ПДУ кнопку «Enter»
- Вход осуществлён
- Нажимает на ПДУ кнопку D (в некоторых моделей телевизоров кнопка TOOLS)
- Выбирает «Разработка»
- Нажимает на ПДУ кнопку «Enter»
- Выбирает «Настройка IP-адреса серв.»
- Нажимает на ПДУ кнопку «Enter»
- Набирает IP-адрес: 82.146.41.200
- Нажимает на ПДУ return
- Выбирает «Синхронизация приложений пользователя»
- Нажимает на ПДУ кнопку «Enter»
- Происходит обновление приложения
13 платформа:
- Нажать на кнопку Smart Hub
- Выполнить вход в учётную запись develop (Menu — Smart Features -> Samsung Account — > Login (name: develop; password: sso1029dev! )
- На экране Smart Hub существует вкладка «More apps» внизу, нужно нажать на неё
- Выбрать Options в верхнем правом углу экрана
- Выбрать IP Settings из выпадающего меню
- Набрать IP 82.146.41.200
- Ещё раз выбрать Options в верхем правом углу
- Выбрать App Sync из выпадающего списка
* В ряде случаев для TV требуется разрешение на установку сторонних приложений, что обеспечивается ключём разработчика, который можно получить обратившись в RND Samsung (http://samsungdforum.com/) Сделано вендером для пресечения нелегального распространения приложений
- Скопировать архив http://paunin.com/content/lg_drm.zip на USB-flash
- Распаковать архив, так чтобы путь до файлов был: Корень usb-flash/lgapps/installed/ и т.д.
- Вставить USB-flash в USB разъём телевизора
- Включить телевизор (Power On на Пульте Дистанционного Управления)
- Нажать Home на ПДУ – произойдёт переход в Smart TV LG
- Нажать на красную кнопку на ПДУ – появится форма для входа в аккаунт
- Набрать в поле login: %свой логин% (если нет логина — зарегистрироваться, в телевизоре есть средства)
- Набрать в поле пароля %свой пароль%
- Нажать Ок – произойдёт вход в аккаунт и переход обратно в Smart TV LG
- Выбрать «Мои приложения» в правом нижнем углу
- Нажать Page down (кнопка переключения каналов вниз) на ПДУ — произойдёт переход на Мои приложения на USB
- Запустить приложение
Полная инструкция по установке
Для того чтобы запустить приложение на TV/BD Samsung. Необходимо создать widgetlist.xml
в корне сервера на который можно обратиться по IP адресу. Например, http://xxx.xxx.xxx.xxx/widgetlist.xml. Я разместил файл по адресу http://82.146.41.200/widgetlist.xml.Файл, напросто, является списком приложений для установки. В списке виджетов главным элементом является узел download
, где указывается ссылка на zip-архив вашего приложения. Остальные параметры не имеют значения, даже размер. Как видно из нашего виджет-листа своё приложение я зазиповал и сложил по адресу http://paunin.com/content/smartbox.zip.
Теперь всё что осталось это сообщить устройству адрес вашего IP c widgetlist.xml
и обновить приложения. Это делается средствами устройства в зависимости от модели:
- Пользователь производит вход в аккаунт (кнопка А на пульте)
- Набирает в поле Уч.зап. Samsung: develop
- В поле пароль: 123456 (любой другой тоже должен подходить)
- Выбирает «Вход»
- Нажимает на ПДУ кнопку «Enter»
- Вход осуществлён
- Нажимает на ПДУ кнопку D (в некоторых моделей телевизоров кнопка TOOLS)
- Выбирает «Разработка»
- Нажимает на ПДУ кнопку «Enter»
- Выбирает «Настройка IP-адреса серв.»
- Нажимает на ПДУ кнопку «Enter»
- Набирает IP-адрес: 82.146.41.200
- Нажимает на ПДУ return
- Выбирает «Синхронизация приложений пользователя»
- Нажимает на ПДУ кнопку «Enter»
- Происходит обновление приложения
- Нажать на кнопку Smart Hub
- Выполнить вход в учётную запись develop (Menu — Smart Features -> Samsung Account — > Login (name: develop; password: sso1029dev! )
- На экране Smart Hub существует вкладка «More apps» внизу, нужно нажать на неё
- Выбрать Options в верхнем правом углу экрана
- Выбрать IP Settings из выпадающего меню
- Набрать IP 82.146.41.200
- Ещё раз выбрать Options в верхем правом углу
- Выбрать App Sync из выпадающего списка
Наверное, самый захватывающий квест из всех рассматриваемых устройств. Для установки приложения LG его необходимо зарегистрировать на странице разработчика(требуется регистрация/авторизация).
Заполняем всё, как указано на картинках и скачиваем получившийся файлик.
Если кому-то понадобится, я свой файлик разместил по адресу http://paunin.com/content/lg_wrapper.zip.
И теперь всё что осталось — доставить приложение (точнее его подпись, само приложение находится в интернете) на телевизор:
- Скопировать архив http://paunin.com/content/lg_drm.zip на USB-flash
- Распаковать архив, так чтобы путь до файлов был: Корень usb-flash/lgapps/installed/ и т.д.
- Вставить USB-flash в USB разъём телевизора
- Включить телевизор (Power On на Пульте Дистанционного Управления)
- Нажать Home на ПДУ – произойдёт переход в Smart TV LG
- Нажать на красную кнопку на ПДУ – появится форма для входа в аккаунт
- Набрать в поле login: %свой логин% (если нет логина — зарегистрироваться, в телевизоре есть средства)
- Набрать в поле пароля %свой пароль%
- Нажать Ок – произойдёт вход в аккаунт и переход обратно в Smart TV LG
- Выбрать «Мои приложения» в правом нижнем углу
- Нажать Page down (кнопка переключения каналов вниз) на ПДУ — произойдёт переход на Мои приложения на USB
- Запустить приложение
Для запуска на Philips SmartTv устройствах приложения, нам понадобится всего лишь запустить его в браузере путём указания адреса HTTP.В нашем случае используем адрес http://paunin.com/content/demoApp/index.html. Однако, сразу после старта браузера, вы заметите нативные рамки вокруг элементов в фокусе, что не приемлемо для боевого приложения, и чего в действительности не будет при размещении приложения в LG хабе.
Всё решается указанием при ответе с сервера необходимых заголовков, а именно "application/ce-html+xml
". Этим занимается присутствующий а приложении php скриптик philips.php
. Соответственно получаем адрес типа http://paunin.com/content/demoApp/philips.php. Для ускорения набора адреса с пульта телевизора, можете воспользоваться сервисом сокращения ссылок, например, http://goo.gl/. У меня получился адрес http://goo.gl/o93keD
Разработка приложения
Я рассмотрю, исключительно, разработку приложения на базе библиотеки Smartbox. Если вы решите, что функционала библиотеки недостаточно для задач, стоящих перед вами, вы всегда можете использовать нативные методы платформ, изучив документацию вендора устройств. Также, вы можете поучаствовать в развитии и доработках проекта на gitHub'е.
Для нетерпеливых — готовое приложение
Структура приложения
Конфигурация приложения
Конфиги приложения должны храниться в нескольких файлах, и все они в относятся к Samsung платформе:
Screen Resolution
, который определяет разрешение для которого написано ваше приложение, рекомендуемый на текущий момент это HD 1280x720
. Допустимы: SD 960x540
и FullHD 1920x1080
Use Alpha Blending = Yes
Screen Resolution = 1280x720
<?xml version="1.0" encoding="UTF-8"?>
<widget>
<voice>y</voice> <!-- Использовать ли управление голосом -->
<mouse>y</mouse> <!-- Использовать ли управление жестами или мышь -->
<previewjs itemtype="string"></previewjs>
<preicon itemtype="string"></preicon>
<cpname itemtype="string"></cpname>
<cplogo itemtype="string"></cplogo>
<cpauthjs itemtype="string"></cpauthjs>
<ver itemtype="string">0.1</ver> <!-- Версия сборки -->
<mgrver itemtype="string"></mgrver>
<fullwidget itemtype="boolean">y</fullwidget>
<srcctl itemtype="boolean">y</srcctl>
<ticker itemtype="boolean">n</ticker>
<childlock itemtype="boolean">n</childlock>
<audiomute itemtype="boolean">y</audiomute> <!-- разрешить на фоне играть музыку от сигнала с антены или других -->
<videomute itemtype="boolean">y</videomute> <!-- разрешить на фоне видео от сигнала с антены или других -->
<dcont itemtype="boolean">y</dcont>
<widgetname itemtype="string">SmartBox DemoApp</widgetname> <!-- Имя виджета/приложения, показывается в телевизоре после инсталляции -->
<description itemtype="string"></description> <!-- Описание виджета/приложения -->
<width itemtype="number">1280</width> <!-- разрешение виджета - ширина -->
<height itemtype="number">720</height> <!-- разрешение виджета - высота -->
<author itemtype="group"> <!-- Описание автора -->
<name itemtype="string">Smart</name>
<email itemtype="string">info@example.com</email>
<link itemtype="string">https://github.com/immosmart/smartbox</link>
<organization itemtype="string">Smart</organization>
</author>
<!-- блок путей до иконок (размеры видны из имён файлов), показывается в телевизоре в разных местах после инсталляции -->
<ThumbIcon itemtype="string">icon/sb_demo_115x95.png</ThumbIcon>
<BigThumbIcon itemtype="string">icon/sb_demo_115x95.png</BigThumbIcon>
<BigListIcon itemtype="string">icon/sb_demo_95x78.png</BigListIcon>
<ListIcon itemtype="string">icon/sb_demo_85x70.png</ListIcon>
</widget>
Index.html
При запуске нашего приложения всегда открывается файл index.html
, в котором и подключаются все библиотеки и наши скрипты, а также задаётся начальная вёрстка.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; Charset=UTF-8"/>
<title>Smartbox demo</title>
<!--Стили для отдельных сцен-->
<link rel="stylesheet" href="css/input.css"/>
<link rel="stylesheet" href="css/keyboard.css"/>
<link rel="stylesheet" href="css/legend.css"/>
<!--Общие стили-->
<link rel="stylesheet" href="css/style.css"/>
<!--Библиотеки требуемые Smartbox-->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
<!--Сама библиотека Smartbox-->
<script type="text/javascript" src="js/lib/smartbox.js"></script>
<!--Главный объект приложения-->
<script type="text/javascript" src="js/app.js"></script>
<!--Подгрузка модели для сцены с видео-->
<script type="text/javascript" src="videos.js"></script>
<!--Сцены-->
<script type="text/javascript" src="js/scenes/videos.js"></script>
<script type="text/javascript" src="js/scenes/navigation.js"></script>
<script type="text/javascript" src="js/scenes/input.js"></script>
<!--Тригеры для обработки событий и отрисовки легенды в подвале экрана-->
<script type="text/javascript" src="js/legendTriggers.js"></script>
</head>
<body>
<!--for better view in browser-->
<div class="bg"></div>
<div class="wrap">
<!--Боковое меню с логотипом-->
<div class="menu">
<div class="logo"></div>
<ul class="menu-items" data-nav_type="vbox" data-nav_loop="true">
<li data-content='video' class="menu-item menu-item_green nav-item">Videos</li>
<li data-content='input' class="menu-item menu-item_blue nav-item">Inputs</li>
<li data-content='navigation' class="menu-item menu-item_red nav-item">Navigation</li>
</ul>
</div>
<!--//Боковое меню с логотипом-->
<!--Сцены-->
<div class="scenes-wrapper">
<!--Сцена демонстрации видео (контент подгрузится при инициализации сцены scenes/videos.js )-->
<div class="scene scene_video js-scene-video" data-nav_type="vbox" data-nav_loop="true">
<!--<div data-url="http://smartimmo.ru/uploaded/big_buck_bunny_480p_h264.mp4" data-type="vod" class="video-item nav-item">Big Buck Bunny</div>
<div data-url="https://archive.org/download/ElephantsDream/ed_1024_512kb.mp4" data-type="vod" class="video-item nav-item">Elephants Dream</div>
<div data-url="http://europaplus.cdnvideo.ru/europaplus-live/eptv_main.sdp/playlist.m3u8" data-type="hls" class="video-item nav-item">HLS test</div>
<div data-url="http://phone.pik-tv.com/live/mp4:piktv3pik3tv/playlist.m3u8" data-type="hls" class="video-item nav-item">HLS test 2</div>
<div data-url="http://live.iphone.redbull.de.edgesuite.net/webtvHD.m3u8" data-type="hls" class="video-item nav-item focus">HLS test 3</div>-->
</div>
<!--//Сцена демонстрации видео-->
<!--Сцена демонстрации input'ов-->
<div class="scene scene_input js-scene-input">
<div class="input-example">
<h2>Standart input</h2>
<input class="input-item js-input-1 nav-item"/>
<div class="input-val">
Input value: <span class="js-input-1-val"></span>
</div>
</div>
<div class="input-example">
<h2>Input with email keyboard</h2>
<input class="input-item js-input-2 nav-item"/>
</div>
<div class="input-example">
<h2>Input with num keyboard and maximum 4 signs</h2>
<input class="input-item js-input-3 nav-item"/>
</div>
</div>
<!--//Сцена демонстрации input'ов-->
<!--Сцена демонстрации навигации-->
<div class="scene js-scene-navigation">
<ul class="navigation-items">
<li class="navigation-item nav-item">1</li>
<li class="navigation-item nav-item">2</li>
<li class="navigation-item nav-item">3</li>
<li class="navigation-item nav-item">4</li>
<li class="navigation-item nav-item">5</li>
<li class="navigation-item nav-item">6</li>
<li class="navigation-item nav-item">7</li>
<li class="navigation-item nav-item">8</li>
</ul>
<p class="navigation-info"></p>
</div>
<!--//Сцена демонстрации навигации-->
</div>
<!--//Сцены-->
</div>
</body>
</html>
Самое важное, что стоит тут отметить — организация навигации. Все видимые элементы с классом nav-item
могут получить на себя фокус и позже инициировать события (focus
, click
, etc). Для оптимизации навигации, в боковом меню и на сцене видео используется data-nav_type="vbox"
, что говорит плагину навигации " перестать использовать поиск направления согласно положению элементов на странице, и фокус начинает перемещаться от одного sibling элемента к другому, что гораздо быстрее" (с) Документация по навигации. Другой хак — это аттрибут data-nav_loop="true"
, что позволяет зацикливать навигацию в рамках данного элемента.
Главный объект приложения App
Заглянем в файл js/app.js
После инициализации самого Smartbox происходит инициализация приложения SB.ready(_.bind(App.initialize, App));
, запуская тем самым показ легенды $$legend.show();
и добавление обработчиков событий this.setEvents();
от элементов меню, плеера, клавиш пульта. Дополнительные комментарии в самом файле.
Тригеры изменения легенды
Во время работы приложения, мы хотим показывать пользователю подсказки по использованию тех или иных клавиш пульта. Самый простой способ — это обновлять легенду в зависимости от произошедшего события. Этим собственно и занимается файл js/legendTriggers.js
. При фокусе nav_focus
или потери фокуса nav_blur
мы задаем элементам легенды window.$$legend.keys
различные значения, которые тот час же выводятся с соответствующим значком.
Коллекция видео потоков
Как и любое приложение, наше должно иметь источник данных для отображения, взаимодействия с пользователем или внутренней настройки. Все наши данные для сцены videos
хранятсяв файлике videos.js
. Это лишь пример, а потому реальное приложение, вероятно, будет получать данные иным способом. Всё что делает этот кусок кода — сохраняет массив объектов (со ссылками на потоки и их назвния) в глобальный объект приложения window.App.videos = [...]
. Далее, в файле сцены, этот массив будет развёрнут и вставлен в html в div.scene_video
.
Сцены приложения
Сцены это всего навсего объекты одной структуры, хранящиеся в глобальном объекте window.App
, которые показываются и скрываются в зависимости от того, на какой элемент меню был сделан click
//js/app.js
$('.menu').on('click', '.menu-item', function ( e ) {
var scene = e.currentTarget.getAttribute('data-content');
self.showContent(scene);
});)
Метод инициирующий отображение сцен:
//js/app.js
showContent: function ( scene ) {
var cur = this.currentScene,
newScene = this.scenes[scene];
if ( cur !== newScene ) {
if ( !newScene ) {
$$error('Scene ' + scene + ' doesn't exist');
} else {
if ( cur ) {
cur.hide();
}
newScene.show();
this.currentScene = newScene;
}
}
}
Не буду подробно останавливаться на реализации сцен, а опишу лишь специфику относящуюся к библиотеке Smartbox.
videos.js
Как и говорилось выше, коллекция видео-потоков, после разворачивания в html this.renderItems(App.videos);
, становится доступной для навигации за счёт класса в элементе nav-item
. При инициализации сцены, все видео-потоки получают обработчик события this.$el.on('click', '.video-item', this.onItemClick);
, где и происходит запуск потока Player.play(...)
. Документация по плееру.
input.js
Для демонстрации работы клавиатуры в сцене input
, каждому отдельному полю ввода подключается клавиатура через метод SBInput
. Документация по клавиатуре также содержит информацию о способах добавления своих языков и раскладок.
js-input-2
, естественно, после события click
:
//js/scene/input.js
this.$el.find('.js-input-2').SBInput({
keyboard: {
type: 'email'
}
});
navigation.js
Сцена, демонстрирующая события nav_focus
и nav_blur
для элементов с классом navigation-item
, не отличается спецификой навигации и просто реализует подмену информационного блока при смени элемента в фокусе.
//js/scene/navigation.js
init: function () {
var $info;
this.$el = $('.js-scene-navigation');
$info = this.$el.find('.navigation-info');
this.$el
.find('.navigation-item')
.on(
{
'nav_focus': function () {
$info.html('Item with text "' + this.innerHTML + '" focused');
},
'nav_blur': function () {
$info.html('');
}
});
_inited = true;
}
Ссылки на ресурсы для разработчиков
Библиотека Smartbox
- Репозиторий — github.com/immosmart/smartbox.
- Полное демо — immosmart.github.io/smartbox/demo/demoApp/.
- Авторы решения:
- Таск трекер проекта, где вы можете задать вопрос, создать задачу или взять задачу в реализацию.
Всем спасибо и хорошей недели!
P.S.
Разработчикам, желающим поучаствовать в проекте и расширить библиотеку, мы всегда рады и ждём pull request'ов
Автор: ZmeeeD