Подключение обновлений к программе

Инструкция к «Набору ТБП Обновления» 1.1.0 для программиста.

Этот набор нужен, чтобы программа сама находила новые версии на сервере «Техно без паники», спрашивала пользователя и обновлялась. Механизм обновления уже готов: его нужно только подключить.

Подключение занимает три шага:

  1. Положить два файла из набора рядом с главным файлом программы.
  2. Добавить одну строку в код, которая выполняется при запуске программы.
  3. Выпускать версии в админке или скриптом. Программа сама их найдёт.

Это общая инструкция. В админке на странице каждой программы есть кнопка «Набор для программиста». Скачанный набор уже заполнен настройками этой программы, и в его инструкции указаны её названия.

Подключаете с ИИ-помощником (Claude, Codex, Cursor, Copilot и другие)? Распакуйте набор в папку проекта и скажите помощнику: «Подключи обновления по набору из папки tbp-update-kit-…». Задание для него лежит в наборе в файле AGENTS.md. В конце помощник напишет, какую папку набора взял и что осталось сделать вам.

Содержание

Что в наборе

Папка или файл Что это
README.html, README.md эта инструкция
AGENTS.md, CLAUDE.md задание для ИИ-помощника: то же самое коротко, по шагам
windows/ всё для платформы «Windows»: tbp-updater.exe и tbp-update.json
windows-portable/ всё для платформы «Windows (без установки)»: tbp-updater.exe и tbp-update.json
android/ всё для платформы «Android»: библиотека tbp-updater.aar, tbp-update.json и store/tbp-update.json для сборок RuStore и Google Play
linux/ всё для платформы «Linux»: tbp-updater (x64), tbp-updater-arm64 (ARM) и tbp-update.json
examples/ готовые примеры подключения для разных языков
publish/ скрипты автоматического выпуска версий: publish.ps1 для Windows, publish.sh для Linux

Главное правило: файлы tbp-updater и tbp-update.json лежат в одной папке с главным файлом программы, а их имена не меняются.

Какую папку брать

Каждая папка набора — это одна платформа в админке, то есть отдельный поток обновлений. Берите папку той платформы, под которой эта сборка будет выпускаться в админке. Если взять не ту, программе будут приходить обновления, предназначенные для другой сборки.

Как раздаётся программа Папка набора
Windows, установщик (exe, msi) windows/
Windows (без установки): zip или один exe windows-portable/
Android: APK файлом, RuStore, Google Play android/
Linux: DEB, RPM, AppImage или архив linux/

Если программа раздаётся в нескольких видах, например установщиком и zip-архивом, в каждую сборку кладётся свой tbp-update.json из своей папки. Какие платформы есть и как они называются, видно в админке: «Платформы».

Настройки программы

Файл tbp-update.json уже заполнен. Вписывать в него ничего не нужно.

{
  "kit": "1.1.0",
  "server": "https://updates.technobezpaniki.ru",
  "app": "kod-programmy",
  "name": "Ваша программа",
  "platform": "windows",
  "channel": "stable",
  "public_key": "+QpN0ZeOt6U5tBsxABczTrxjnXnQ3axflzcjdpkP6EQ=",
  "page": "https://technobezpaniki.ru/programs/kod-programmy/"
}
Поле Значение
server адрес сервера обновлений
app код программы на сервере
name название программы в окнах обновления
platform код платформы. В каждой папке набора он свой, поэтому файлы из папок не смешивают
channel stable — обычные версии, beta — ещё и бета-версии. Это единственное поле, которое можно менять: например, для тестовых сборок
public_key открытый ключ подписи. По нему проверяется, что файл обновления выпущен вами и не подменён
page страница программы на сайте

Код программы и коды платформ появляются в адресах обновлений. После выпуска программы менять их нельзя.

Windows

Куда положить файлы

Скопируйте оба файла из папки набора, которая подходит этой сборке (см. Какую папку брать): windows/ — «Windows», windows-portable/ — «Windows (без установки)». Файлы кладутся в папку программы:

C:\Program Files\Ваша программа\   ← папка программы (любая)
├─ program.exe          ← ваша программа
├─ tbp-updater.exe          ← из набора
└─ tbp-update.json          ← из набора

Эти два файла должны входить в каждую версию: в установщик или в архив, как обычные файлы программы. Отдельно их никто не ставит.

Одна строка при запуске программы

Запустите tbp-updater.exe из папки программы и передайте номер текущей версии. Ждать его завершения не нужно: он сразу уходит в фон и не задерживает запуск.

C# (Program.cs, до Application.Run или в App.OnStartup):

System.Diagnostics.Process.Start(
    System.IO.Path.Combine(AppContext.BaseDirectory, "tbp-updater.exe"), "--version 1.4.2");

C++ (WinAPI):

ShellExecuteW(nullptr, L"open", L"tbp-updater.exe", L"--version 1.4.2", exeFolder, SW_HIDE);

Python (в том числе собранный PyInstaller):

import os, subprocess, sys
folder = os.path.dirname(sys.executable if getattr(sys, "frozen", False) else os.path.abspath(__file__))
subprocess.Popen([os.path.join(folder, "tbp-updater.exe"), "--version", "1.4.2"])

Готовые примеры для C#, C++, Qt, Delphi, Python, Electron и Java лежат в папке examples/.

Номер версии на Windows можно не передавать. Тогда tbp-updater прочитает его из свойств exe-файла программы (поле «Версия продукта»). Но надёжнее передавать явно и брать из того же места, откуда берётся номер для сборки.

Ещё три правила запуска:

  • Запускайте tbp-updater прямо из программы, а не через cmd /c, bat-файл или отдельный запускатель. По процессу, который его запустил, tbp-updater узнаёт, какую программу закрыть перед установкой и запустить после. Если по-другому нельзя, передайте номер процесса программы: --pid 1234. Программа на Python, запущенная скриптом, передаёт --pid всегда (так сделано в examples/python/).
  • Путь к tbp-updater берите от папки программы, а не от текущей папки: программу могут запустить из любой папки.
  • Если tbp-updater не нашёлся или не запустился, программа работает дальше как обычно. Ошибку достаточно записать в журнал, пользователю её не показывают.

Номер версии в файлах, которые вы выпускаете

Сервер сам читает номер версии из загружаемого файла. Он должен совпадать с номером, который программа передаёт в --version.

Что выпускаете Откуда сервер берёт номер
Установщик .exe «Версия продукта» в свойствах файла. Inno Setup: AppVersion и VersionInfoVersion; NSIS: VIProductVersion и VIAddVersionKey ProductVersion
.msi из имени файла: program-1.4.2.msi
Архив .zip из имени файла: program-1.4.2-windows.zip

Номер можно и вписать вручную при выпуске.

Как ставится обновление

Способ выбирается по типу файла. При необходимости его можно поменять в админке: при выпуске версии раздел «Установка у пользователя».

  • Установщик (exe, msi). Программа закрывается, установщик запускается как при обычной установке. Если нужны права администратора, Windows спросит. После установки программа запускается снова, если установщик не сделал этого сам. Установщик должен ставиться поверх прежней версии в ту же папку, без удаления старой. В Inno Setup для этого нужен тот же AppId и CloseApplications=yes. Чтобы установщик прошёл без вопросов, укажите в админке «Параметры установщика»: Inno Setup — /SILENT или /VERYSILENT /SUPPRESSMSGBOXES, NSIS — /S, MSI — /passive.
  • Без установки (zip). Программа закрывается, архив распаковывается поверх папки программы, и программа запускается снова. Файлы в архиве лежат в корне или в одной папке, как в папке программы. Старые файлы, которых нет в архиве, не удаляются. При сбое всё возвращается как было. Если папка программы в Program Files, Windows спросит права администратора.
  • Один exe-файл без архива. Выберите в админке способ «Заменить файл программы».
  • Архив со своим установщиком (например, в архиве исходники и Install.ps1, который собирает и ставит программу). Выберите способ «Архив со своим установщиком» и в «Параметрах установщика» укажите имя файла в архиве и его параметры, например Install.ps1 -Update -Quiet. tbp-updater распакует архив, запустит установщик без окна консоли и дождётся его. Установщик должен сам закрыть работающую программу, поставить новую версию и запустить её, а при ошибке — вернуть код выхода не 0. Годятся .ps1, .cmd, .bat, .exe (на Linux — .sh). Скриптом выпуска: -Install script -InstallArgs "Install.ps1 -Update -Quiet".

Пример скрипта Inno Setup: examples/windows/inno-setup/setup.iss.

Linux

Куда положить файлы

/opt/program/
├─ program              ← ваша программа
├─ tbp-updater          ← из папки linux/ набора (для ARM — tbp-updater-arm64, переименуйте в tbp-updater)
└─ tbp-update.json      ← из папки linux/ набора

У tbp-updater должен быть признак исполняемого файла: chmod 755 tbp-updater.

Одна строка при запуске программы

На Linux номер версии обязателен:

subprocess.Popen(["/opt/program/tbp-updater", "--version", "1.4.2"])

Лучше брать путь к папке от самой программы, а не писать его жёстко. Примеры есть в examples/python/ и examples/qt/. Правила запуска те же, что на Windows: запускать прямо из программы, не ждать завершения, а если tbp-updater не запустился — работать дальше как обычно.

Форматы выпуска

Формат Откуда номер версии Как ставится обновление
DEB (рекомендуется) поле Version: в DEBIAN/control через apt-get; система спросит пароль администратора (pkexec)
RPM из имени файла через dnf или zypper, тоже с паролем
AppImage из имени файла: program-1.4.2-x86_64.AppImage заменяется сам файл .AppImage; положите tbp-updater и tbp-update.json внутрь, рядом с программой (usr/bin/)
Архив .tar.gz / .tar.xz из имени файла распаковывается поверх папки программы
Архив со своим install.sh из имени файла распаковывается во временную папку, запускается install.sh (способ «Архив со своим установщиком», см. раздел Windows)

Для DEB-пакета добавьте в control строку Recommends: zenity | kdialog, pkexec. Тогда у обновления будут нормальные окна. Пример: examples/linux/deb/.

Окна показываются через zenity (GNOME, Cinnamon, MATE, XFCE) или kdialog (KDE). Если их нет, вопрос задаётся в терминале, если программа запущена из него, а иначе показывается только уведомление о новой версии.

Android

Подключение

  1. Скопируйте android/tbp-updater.aar в папку app/libs/ проекта.
  2. В app/build.gradle.kts добавьте зависимость: kotlin dependencies { implementation(files("libs/tbp-updater.aar")) }
  3. Скопируйте android/tbp-update.json в app/src/main/assets/tbp-update.json.
  4. Добавьте одну строку в onCreate главной Activity: kotlin TbpUpdater.check(this) // Kotlin java TbpUpdater.check(this); // Java Импорт: ru.technobezpaniki.updater.TbpUpdater.

Номер версии библиотека берёт сама из versionName в build.gradle.kts. Он должен совпадать с номером, под которым APK выпускается на сервере: сервер читает его из APK. versionCode должен расти с каждой версией.

Разрешения INTERNET и REQUEST_INSTALL_PACKAGES библиотека добавляет сама. При первом обновлении Android спросит пользователя, можно ли этому приложению устанавливать программы. Это нормально, так спрашивает сама система.

Минимальная версия Android — 5.0 (minSdk 21).

APK всегда подписывайте одним и тем же ключом. Если ключ подписи сменится, Android откажется ставить обновление поверх старой версии. Ключ (.jks) храните в надёжном месте и не теряйте.

RuStore и Google Play

Google Play запрещает приложениям обновлять себя в обход магазина. Поэтому для магазинов делается отдельная сборка (flavor), в которой библиотека с нашего сервера не обновляется, а обновлением занимается магазин.

  1. В build.gradle.kts заведите варианты сборки direct (файлом с сайта), rustore и googleplay (пример: examples/android/build.gradle.kts).
  2. Для rustore и googleplay положите файл android/store/tbp-update.json из набора в app/src/rustore/assets/ и app/src/googleplay/assets/. Он отличается одним полем: "mode": "store".
  3. Для них же уберите разрешение на установку. Файл app/src/rustore/AndroidManifest.xml есть в examples/android/store/.

Код приложения при этом одинаковый: строка TbpUpdater.check(this) остаётся, а в сборке для магазина она ничего не делает.

Пока приложения нет в магазинах, раздаётся только вариант direct. Варианты для магазинов можно завести сразу или позже, когда приложение туда выйдет.

Что увидит пользователь

При запуске программы, а если она открыта долго — раз в сутки, tbp-updater спрашивает сервер о новой версии. Если она есть, появляется окно:

Вышла новая версия Установлена версия 1.4.2, новая — 1.4.3. Что нового: … [Обновить] [Позже] [Пропустить эту версию]

  • Обновить. Файл скачивается с полосой прогресса, затем проверяются контрольная сумма и цифровая подпись. Программа закрывается, как будто пользователь нажал «крестик», поэтому она успевает сохранить данные. Ставится новая версия, и программа запускается снова.
  • Позже. Программа спросит при следующем запуске или через сутки.
  • Пропустить эту версию. Про эту версию программа больше не спрашивает, а про следующие спросит.

Если в админке у версии стоит галочка «Обязательное обновление», у окна только две кнопки: «Обновить» и «Закрыть программу». Пока открыто это окно, программой на Windows пользоваться нельзя. Если интернета нет, проверка просто не выполняется, и программа работает как обычно.

Текст «Что нового» берётся из поля «Что нового» у версии в админке.

Проверка перед первым выпуском

  1. Соберите программу с версией 1.0.0, установите её и запустите. Окна быть не должно.
  2. В админке выпустите версию 1.0.1 для той же платформы: загрузите файл и нажмите «Сохранить». Для проверки удобно выпустить её в канал «Бета» и в тестовой сборке указать "channel": "beta": тогда обычные пользователи её не увидят.
  3. Запустите установленную 1.0.0. Должно появиться окно «Вышла новая версия». Нажмите «Обновить».
  4. Программа должна закрыться, обновиться и запуститься уже версией 1.0.1. Окно больше не появляется.

Проверить без окна из командной строки (Windows — PowerShell в папке программы):

.\tbp-updater.exe check --version 1.0.0 | Out-String
./tbp-updater check --version 1.0.0

Ответ — JSON, например "update_available": true. Команда tbp-updater about показывает настройки и путь к журналу.

Журнал всех проверок и установок: - Windows: %LOCALAPPDATA%\TBP\Updater\<код программы>\updater.log - Linux: ~/.local/state/tbp-updater/<код программы>/updater.log - Android: adb logcat -s TbpUpdater

Выпуск версий

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

Автоматически из сборки: скрипты в папке publish/. Нужен ключ API: админка → «Ключи API (автоматизация)» → «Создать ключ». Ключ показывается один раз. Передайте его скрипту через переменную окружения TBP_API_TOKEN, в код ключ не записывайте.

$env:TBP_API_TOKEN = "tbp_…"
.\publish\publish.ps1 -File dist\setup.exe -Platform windows -Notes "- Исправлены ошибки"
export TBP_API_TOKEN=tbp_…
./publish/publish.sh --file dist/program_1.4.3_amd64.deb --platform linux --notes-file CHANGES.md

-Platform обязателен: это имя папки набора, из которой взят tbp-update.json этой сборки. Если программа раздаётся в нескольких видах, каждый файл выпускается со своим -Platform.

Полезные параметры (в publish.sh они пишутся так же, но строчными через дефис: --channel beta): - -Channel beta — бета-версия; - -Mandatory — обязательное обновление; - -Draft — загрузить, но не публиковать: опубликуете галочкой в админке после проверки; - -InstallArgs "/SILENT" — параметры установщика; следующие версии получат их сами; - -Version 1.4.3 — номер версии, если его не удаётся прочитать из файла.

Обязательные требования

  1. Данные пользователя хранятся не в папке программы: на Windows в %APPDATA% или %LOCALAPPDATA%, на Linux в ~/.config или ~/.local/share. При обновлении файлы в папке программы заменяются.
  2. Номер версии в программе совпадает с номером выпущенного файла. Иначе программа после обновления будет считать себя старой.
  3. Каждая новая версия получает больший номер: 1.4.2 → 1.4.3. Сравниваются числа, поэтому 1.10 новее 1.9. Бета-версии обозначаются 1.5.0-beta.1.
  4. Программа нормально закрывается по «крестику» (на Linux — по сигналу SIGTERM). Именно так её закрывает tbp-updater перед установкой.
  5. Установщик ставится поверх старой версии, в ту же папку.
  6. Android: APK подписывается всегда одним ключом, а versionCode растёт.
  7. tbp-update.json и tbp-updater не переименовываются, а настройки в файле не правятся (кроме channel).
  8. Своя проверка обновлений не пишется. Проверку, скачивание, проверку подписи и установку делает tbp-updater или библиотека Android.

Что делает только человек

Это не делают ни программист в коде, ни ИИ-помощник:

  • Решает, как раздаётся программа (установщик, zip, DEB, APK, магазины). От этого зависит папка набора.
  • Создаёт ключ API в админке для скриптов выпуска и передаёт его через переменную окружения TBP_API_TOKEN или секрет сборочного сервера. В код и в репозиторий ключ не попадает.
  • Выпускает версии в админке или запускает скрипт выпуска. Решает, какая версия бета, какая обязательная.
  • Android: создаёт и хранит ключ подписи APK (.jks) и пароли к нему. Ключ не теряется и не меняется.
  • Проверяет обновление по-настоящему перед первым выпуском: см. Проверка перед первым выпуском.

Частые ошибки

Что происходит Почему Что сделать
Окно обновления не появляется нет файла tbp-update.json рядом с tbp-updater, или на сервере нет версии новее tbp-updater about и tbp-updater check --version …, журнал
После обновления снова предлагает то же обновление программа передаёт старый номер версии исправить номер в программе (требование 2)
Уже скачанная раньше версия не обновляется в ней ещё не было tbp-updater такие пользователи один раз скачивают новую версию с сайта, дальше она обновляется сама. Первую версию с обновлениями выпускайте с новым номером
Пришло обновление от другой сборки (например, установщик вместо zip) tbp-update.json взят не из той папки набора или версия выпущена не на ту платформу см. Какую папку брать, в скрипте выпуска — свой -Platform
«Подпись не сходится» tbp-update.json взят из набора другого сервера или другой программы взять файл из набора этой программы
«Программа не закрывается» программа не реагирует на «крестик» обработать закрытие окна / SIGTERM
Android: «Приложение не установлено» APK подписан другим ключом подписывать тем же ключом, что и первую версию
Windows: «Неизвестный издатель» у программ нет цифровой подписи кода со временем купить сертификат подписи кода и подписывать exe

Своё окно обновления вместо стандартного

Если программа хочет показывать своё окно, используйте команды:

tbp-updater check --version 1.4.2

Выводит JSON, ничего не показывая: update_available, mandatory, version, notes. Код выхода: 0 — обновлений нет, 10 — есть, 11 — есть обязательное, 1 — ошибка.

tbp-updater install --version 1.4.2

Сразу скачивает и ставит новую версию без вопроса: полоса прогресса, закрытие программы, установка, запуск.

tbp-updater --version 1.4.2 --once

Одна проверка со стандартным окном «Обновить / Позже / Пропустить», без повторов раз в сутки. Удобно, если программа сама решает, когда проверять (например, по своему таймеру и с выключателем в настройках).

Все три команды запускаются из процесса программы без ожидания, кроме check: его вывод программа читает. В ответе check есть и skipped — пользователь уже нажал «Пропустить эту версию». Если программа сама запускает проверки, не запускайте ещё и обычный фоновый tbp-updater --version …: он держит проверку за собой, пока программа открыта, и install тогда ничего не сделает.

Как устроен обмен с сервером (адреса, формат ответа, проверка подписи), описано на странице https://technobezpaniki.ru/developers/.