Деплой приложений на Samsung Smart TV: bash-скрипт, который экономит часы
После 9+ лет деплоя OTT-приложений на Tizen я написал скрипт, который превращает 15-шаговый ручной процесс в одну команду. Открытый код с интерактивным меню.

Если вы хотя бы раз деплоили веб-приложение на Samsung Smart TV, вы знаете эту боль. Подключиться через sdb, определить имя устройства, запаковать .wgt с нужным сертификатом, удалить старую версию, установить новую, запустить, помолиться, чтобы не упало. Каждый. Раз. После 9+ лет такого на десятках OTT-проектов — включая платформы на 80M+ зрителей — я не выдержал и написал скрипт, который автоматизирует весь процесс.
Делюсь им здесь, потому что хотел бы, чтобы кто-то поделился чем-то подобным со мной много лет назад. Если хотите понять, почему разработка под Smart TV — это вообще больно — древние браузеры, лимиты памяти, кошмар пространственной навигации — я писал об этом в статье Разработка приложений для Smart TV: о чём не предупреждают.
Что нужно подготовить заранее
Прежде чем скрипт сможет творить магию, нужно настроить три вещи на вашем компьютере и телевизоре.
1. Установите Tizen Studio. Скачайте с официальной страницы Tizen Studio. Нужны CLI-инструменты — конкретно sdb и утилита tizen. Скрипт ожидает их в ~/tizen-studio/tools/. После базовой установки откройте Package Manager, перейдите на вкладку Extension SDK и установите TV Extensions и Samsung Certificate Extension. Подробный процесс описан в гайде по установке Samsung TV SDK.
2. Создайте сертификат Samsung. Это место, где большинство спотыкается. Нужен подписной сертификат, чтобы упаковывать и устанавливать приложения на физический телевизор. Следуйте гайду Samsung по сертификатам: откройте Certificate Manager в Tizen Studio, создайте профиль именно Samsung-сертификата (не Tizen), авторизуйтесь через аккаунт Samsung Developer и зарегистрируйте DUID вашего телевизора как целевое устройство. Храните сертификат в надёжном месте — для обновлений приложения нужен тот же author-сертификат, иначе ТВ воспримет апдейт как совершенно новое приложение.
3. Включите Developer Mode на телевизоре. На самом ТВ зайдите в панель Apps, откройте App Settings и введите код 12345. Появится окно Developer Mode. Включите его, введите IP-адрес вашего компьютера и перезагрузите телевизор. После перезапуска увидите "Develop Mode" вверху панели приложений. Полный гайд — в документации Samsung по настройке устройства.
Также нужна Java 8. CLI-инструменты Tizen до сих пор зависят от Java 8, не от новых версий. На macOS установите через brew install --cask temurin8. Скрипт автоматически находит и переключается на Java 8 только для текущей сессии — системная Java остаётся нетронутой.
Что умеет скрипт
Скрипт даёт интерактивное меню на базе gum (тулкит для терминального UI, который автоматически установится, если его нет). Вам доступны 8 опций:
- Запустить все шаги — подключение, определение устройства, упаковка, удаление старой версии, установка и запуск. Один выбор — и готово.
- Подключиться к ТВ — устанавливает sdb-соединение с IP телевизора.
- Определить имя устройства — считывает идентификатор устройства из sdb, нужный для всех команд Tizen CLI.
- Упаковать приложение — подписывает директорию сборки как .wgt-файл вашим сертификатом. Автоматически чистит имя файла от пробелов.
- Удалить приложение — убирает текущую версию с ТВ (тихо игнорирует, если не установлено).
- Установить приложение — загружает .wgt на телевизор.
- Отладка приложения — запускает debug-сессию и пробрасывает порт для подключения Chrome DevTools.
- Запустить приложение — запускает в обычном режиме без отладки.
Можно также передать готовый .wgt-файл напрямую, и скрипт пропустит этап упаковки.
Конфигурация сохраняется: настроил раз — деплоишь всегда
При первом запуске скрипт спросит четыре вещи: IP телевизора, имя сертификата, package ID и путь к директории сборки (или .wgt-файлу). Package ID берётся из config.xml вашего проекта — это атрибут package из тега tizen:application, в формате AbCdEf1234.MyApp. Всё сохраняется в ~/.tizen_deploy_config, и каждый следующий запуск просто работает — без повторного ввода.
Переключились на другой проект или другой телевизор? Запустите скрипт с --clear-config, чтобы сбросить всё:
./tizen_deploy.sh --clear-config
Это удалит сохранённый конфиг и спросит всё заново.
Полный код скрипта
Вот полный исходный код. Сохраните как tizen_deploy.sh, сделайте исполняемым через chmod +x tizen_deploy.sh и запускайте.
#!/bin/bash
# PLATFORM DETECTION
OS_TYPE="$(uname -s)"
IS_MAC=false
IS_LINUX=false
IS_WIN=false
case "$OS_TYPE" in
Darwin*) IS_MAC=true ;;
Linux*) IS_LINUX=true ;;
MINGW*|MSYS*|CYGWIN*) IS_WIN=true ;;
esac
# CONFIG PATH
CONFIG_PATH="$HOME/.tizen_deploy_config"
$IS_WIN && CONFIG_PATH="$HOME/_tizen_deploy_config"
# --clear-config ARG HANDLING
if [[ "$1" == "--clear-config" ]]; then
echo "Clearing config at $CONFIG_PATH"
rm -f "$CONFIG_PATH"
fi
# INSTALL GUM IF NOT FOUND
install_gum() {
if command -v gum &>/dev/null; then return; fi
echo "'gum' is not installed. Installing..."
if $IS_MAC; then
if ! command -v brew &>/dev/null; then
echo "Homebrew is required on macOS." >&2
exit 1
fi
brew install charmbracelet/tap/gum
elif $IS_LINUX; then
if command -v apt &>/dev/null; then
sudo apt update && sudo apt install -y gum
elif command -v dnf &>/dev/null; then
sudo dnf install -y gum
elif command -v pacman &>/dev/null; then
sudo pacman -Sy gum
else
echo "Unsupported package manager." >&2
exit 1
fi
elif $IS_WIN; then
echo "On Windows, install gum manually:"
echo " scoop install gum"
read -p "Press Enter when installed..."
fi
}
if ! command -v tizen &>/dev/null; then
echo "Tizen CLI not found. Install Tizen Studio first."
exit 1
fi
install_gum
# FORCE JAVA 8 FOR TIZEN
if command -v /usr/libexec/java_home &>/dev/null; then
JAVA_8_HOME=$(/usr/libexec/java_home -v 1.8 2>/dev/null)
if [[ -z "$JAVA_8_HOME" ]]; then
echo "Java 8 is required. Install: brew install --cask temurin8"
exit 1
fi
export JAVA_HOME="$JAVA_8_HOME"
export PATH="$JAVA_HOME/bin:$PATH"
fi
# LOAD / PROMPT CONFIGURATION
prompt_or_load() {
local var_name=$1
local prompt_msg=$2
local current_value=$(grep "^$var_name=" "$CONFIG_PATH" 2>/dev/null | cut -d'=' -f2-)
if [ -n "$current_value" ]; then
eval "$var_name="$current_value""
else
read -p "$prompt_msg: " user_input
echo "$var_name="$user_input"" >> "$CONFIG_PATH"
eval "$var_name="$user_input""
fi
}
prompt_or_load TV_IP "Enter TV IP address"
prompt_or_load CERTIFICATE_NAME "Enter Certificate/Profile name"
prompt_or_load PACKAGE_ID "Enter PACKAGE_ID (e.g., abc123.MyApp)"
prompt_or_load INPUT_PATH "Enter build dir or .wgt file path"
# Derive behavior based on INPUT_PATH
if [[ "$INPUT_PATH" == *.wgt ]]; then
BUILD_DIR="$(dirname "$INPUT_PATH")"
APP_NAME="$(basename "$INPUT_PATH")"
SKIP_PACKAGE=true
else
BUILD_DIR="$INPUT_PATH"
APP_NAME="$(echo "$PACKAGE_ID" | cut -d. -f2).wgt"
SKIP_PACKAGE=false
fi
SDB="$HOME/tizen-studio/tools/sdb"
TIZEN_CLI="$HOME/tizen-studio/tools/ide/bin/tizen"
TV_PORT="26101"
DEVICE_NAME=""
DEBUG_PORT=""
# STEP FUNCTIONS
connect() {
echo "Connecting to $TV_IP:$TV_PORT..."
CONNECT_OUTPUT=$($SDB connect "$TV_IP:$TV_PORT" 2>&1)
echo "$CONNECT_OUTPUT" | grep -Eq "connected to|is already connected" && echo "Connected." || { echo "Failed."; echo "$CONNECT_OUTPUT"; exit 1; }
}
resolve_device() {
DEVICE_NAME=$($SDB devices | grep "$TV_IP:$TV_PORT" | awk '{print $3}')
[[ -z "$DEVICE_NAME" ]] && { echo "Could not resolve device."; exit 1; }
echo "Device: $DEVICE_NAME"
}
package_app() {
$SKIP_PACKAGE && { echo "Skipping packaging (.wgt provided)"; return; }
PACKAGE_OUTPUT=$($TIZEN_CLI package -s "$CERTIFICATE_NAME" -t wgt -- "$BUILD_DIR" 2>&1)
if echo "$PACKAGE_OUTPUT" | grep -q "Package File Location"; then
PKG_FILE=$(echo "$PACKAGE_OUTPUT" | grep "Package File Location" | sed -E 's/.*:s*//' | xargs)
NEW_BASENAME=$(basename "$PKG_FILE" | tr -d ' ')
mv "$PKG_FILE" "$(dirname "$PKG_FILE")/$NEW_BASENAME" 2>/dev/null
APP_NAME="$NEW_BASENAME"
echo "Packaged: $APP_NAME"
else
echo "Packaging failed."; echo "$PACKAGE_OUTPUT"; exit 1
fi
}
uninstall_app() {
$TIZEN_CLI uninstall -t "$DEVICE_NAME" -p "$PACKAGE_ID" 2>&1 | grep -q "uninstall completed" && echo "Uninstalled." || echo "Not installed, skipping."
}
install_app() {
INSTALL_OUTPUT=$($TIZEN_CLI install --name "$APP_NAME" -t "$DEVICE_NAME" -- "$BUILD_DIR" 2>&1)
echo "$INSTALL_OUTPUT" | grep -q "successfully installed" && echo "Installed." || { echo "Install failed."; echo "$INSTALL_OUTPUT"; exit 1; }
}
debug_app() {
DEBUG_OUTPUT=$($SDB shell 0 debug "$PACKAGE_ID" 2>&1)
DEBUG_PORT=$(echo "$DEBUG_OUTPUT" | grep -oE "port: [0-9]+" | awk '{print $2}')
[[ -z "$DEBUG_PORT" ]] && { echo "Debug failed."; echo "$DEBUG_OUTPUT"; exit 1; }
$SDB forward "tcp:$DEBUG_PORT" "tcp:$DEBUG_PORT" 2>&1
echo "Debug on port $DEBUG_PORT"
}
run_app() {
RUN_OUTPUT=$($TIZEN_CLI run -t "$DEVICE_NAME" -p "$PACKAGE_ID" 2>&1)
echo "$RUN_OUTPUT" | grep -q "successfully launched" && echo "Launched." || { echo "Launch failed."; echo "$RUN_OUTPUT"; exit 1; }
}
run_all() { connect; resolve_device; package_app; uninstall_app; install_app; run_app; }
# INTERACTIVE MENU
choice=$(gum choose "Run All Steps (1-5, 7)" "1. Connect to TV" "2. Resolve device name" "3. Package app" "4. Uninstall app" "5. Install app" "6. Debug app + forward port" "7. Run app (non-debug)" "8. Disconnect from TV")
case "$choice" in
"Run All Steps (1-5, 7)") run_all ;;
"1. Connect to TV") connect ;;
"2. Resolve device name") resolve_device ;;
"3. Package app") package_app ;;
"4. Uninstall app") resolve_device && uninstall_app ;;
"5. Install app") resolve_device && install_app ;;
"6. Debug app + forward port") resolve_device && debug_app ;;
"7. Run app (non-debug)") resolve_device && run_app ;;
"8. Disconnect from TV") disconnect ;;
*) echo "Invalid selection." && exit 1 ;;
esac
echo "Done."
Как дебажить приложение через Chrome DevTools
Одна из самых полезных возможностей скрипта — удалённая отладка. Вот как подключить Chrome DevTools к приложению, работающему на телевизоре.
Шаг 1: Закройте приложение на ТВ. Если приложение уже запущено — сначала закройте его. Debug-сессия должна сама запустить приложение, она не подключится к уже работающему.
Шаг 2: Запустите debug-команду. Запустите скрипт и выберите "Debug app + forward port" из меню. Скрипт выведет номер порта — скопируйте его.
Шаг 3: Откройте Chrome DevTools для устройств. В Chrome перейдите на chrome://inspect/#devices. Убедитесь, что "Discover network targets" отмечен, затем нажмите Configure...
Шаг 4: Добавьте debug-порт. В диалоге Target discovery settings добавьте localhost:{port}, где {port} — номер, который вернул скрипт. Нажмите Done.
Шаг 5: Inspect. Ваше ТВ-приложение появится под Remote Target. Нажмите inspect на первом элементе в списке — откроется полноценное окно Chrome DevTools, подключённое к приложению на телевизоре. Можно инспектить DOM, дебажить JavaScript, профилировать производительность и смотреть сетевые запросы — точно как на обычной веб-странице.
Важные замечания и ограничения
Несколько вещей, которые стоит иметь в виду:
- Тестировано на macOS. В скрипте есть определение платформы для Linux и Windows (Git Bash), но я полноценно тестировал только на macOS. Linux должен работать с минимальными корректировками. Windows через Git Bash/MSYS — экспериментально, результат не гарантирован.
- Java 8 обязательна. Tizen CLI отказывается работать с Java 11+. Скрипт решает это переключением
JAVA_HOMEтолько для текущей сессии — системная Java остаётся как есть. - Проблемы с сертификатами — причина номер один всех ошибок. Если установка падает с ошибкой подписи, проверьте три вещи: имя сертификатного профиля должно совпадать точно, DUID телевизора должен быть зарегистрирован в distributor-сертификате, и тип сертификата имеет значение — нужен именно Samsung-сертификат (не Tizen), а уровень привилегий должен быть правильным (Partner для приложений с привилегированными API, Public для базовых приложений).
- gum устанавливается автоматически. Интерактивное меню использует gum от Charm. Если не установлен — скрипт поставит через Homebrew (macOS), apt/dnf/pacman (Linux) или попросит установить вручную (Windows).
Разрабатываете приложение для Samsung TV?
Этот скрипт — лишь малая часть того, что нужно для выпуска продакшен-приложений на Samsung Smart TV. Настоящие вызовы — пространственная навигация, управление памятью, древние браузерные движки, интеграция DRM — вот где 9+ лет опыта разработки OTT делают разницу. Я строил стриминговые платформы на 80M+ зрителей для Tizen, WebOS, Android TV и других. Если вы делаете OTT-приложение или любой продукт для Smart TV и хотите человека, который уже решил все сложные задачи — запишитесь на бесплатный 30-минутный звонок или попробуйте калькулятор проекта для быстрой оценки.
Есть проект?
Запишитесь на бесплатный 30-минутный звонок или попробуйте калькулятор для быстрой оценки.

Александр Саков
Основатель SunDr. 9+ лет разработки OTT-стриминговых платформ, мобильных приложений и веб-продуктов. Платформы, которые я построил, обслуживают 80M+ зрителей на 15+ типах устройств.