WebApp API: жизненный цикл
Жизненный цикл WebApp API определяет, как ваше приложение запускается, взаимодействует с Telegram и завершает работу. Как и у мобильных приложений, у Mini App есть состояния (foreground, background, closed), и правильная обработка переходов между ними критична для пользовательского опыта.
Каждое Mini App проходит через строго определённый жизненный цикл — от момента нажатия кнопки до закрытия приложения. Понимание этого цикла критично для корректной работы приложения.
Интерактивная диаграмма
Нажимайте на шаги, чтобы увидеть детали каждой фазы жизненного цикла:
Фазы жизненного цикла
Фаза 1: Запуск (Launch)
Mini App запускается одним из четырёх способов:
| Способ | Описание | Контекст |
|---|---|---|
| Menu button | Кнопка в чате бота | chat_type, chat_instance |
| Inline button | Кнопка в сообщении бота | chat_type, chat_instance |
| Direct link | t.me/botname/appname | start_param (опционально) |
| Keyboard button | В клавиатуре бота | chat_type, chat_instance |
Каждый способ запуска предоставляет разный контекст в initData. Direct link, например, позволяет передать start_param для deep linking.
Фаза 2: Загрузка (Loading)
- Telegram открывает URL Mini App в WebView
- Автоматически инъектирует
telegram-web-app.js - Показывает placeholder загрузки (спиннер) пользователю
- Ваше приложение начинает загружаться
Вызывайте ready() как можно раньше
Telegram показывает спиннер до вызова WebApp.ready(). Если ваше приложение долго грузится — пользователь видит только крутящийся индикатор. Вызовите ready() сразу после базовой инициализации, не дожидаясь загрузки всех данных.
Фаза 3: Инициализация (Init)
После инъекции скрипта становится доступен объект window.Telegram.WebApp:
// Объект WebApp уже доступен
const webApp = window.Telegram.WebApp;
// Ключевые данные:
webApp.initData; // строка для серверной валидации
webApp.initDataUnsafe; // распарсенные данные
webApp.themeParams; // цвета темы
webApp.platform; // "ios", "android", "tdesktop"
webApp.version; // версия Bot API
Фаза 4: Ready
Вызов ready() сигнализирует Telegram, что приложение готово:
// Минимальная инициализация
WebApp.ready(); // спиннер исчезает, Mini App становится видимым
Фаза 5: Взаимодействие (Interaction)
Приложение работает: обрабатывает события, показывает UI-контроллы, взаимодействует с хранилищем.
Фаза 6: Закрытие (Teardown)
WebApp.close(); // сессия завершается
Также пользователь может закрыть Mini App свайпом вниз (на мобильных).
initData: авторизация через Telegram
initData — это base64-кодированная строка в формате query string, содержащая данные о пользователе, чате и авторизации:
query_id=AAHdF6IQAAAAAAN8GCAAAADh&
user=%7B%22id%22%3A12345%2C%22first_name%22%3A%22John%22%7D&
auth_date=1234567890&
hash=abcdef123456...
Ключевые поля:
| Поле | Описание |
|---|---|
user | JSON с id, first_name, last_name, username, language_code |
chat | JSON с информацией о чате (если запущено из чата) |
auth_date | UNIX-timestamp авторизации |
query_id | Идентификатор для ответа через Bot API |
hash | HMAC-SHA256 подпись для серверной валидации |
НИКОГДА не доверяйте initDataUnsafe на сервере
initDataUnsafe — это распарсенные данные на стороне клиента. Они могут быть подделаны. Для серверной авторизации всегда используйте initData и валидируйте hash через HMAC-SHA256.
Серверная валидация initData
Валидация initData — обязательный шаг для любого продакшен-приложения. Алгоритм:
1. Распарсить initData как query string
2. Извлечь hash (значение параметра "hash")
3. Из оставшихся параметров (без hash) создать data_check_string:
- Сортировать пары key=value по алфавиту
- Объединить через \n
4. Вычислить секретный ключ:
secret_key = HMAC-SHA256("WebAppData", bot_token)
5. Вычислить хеш:
computed_hash = HMAC-SHA256(data_check_string, secret_key)
6. Сравнить computed_hash с полученным hash
Пример (Node.js pseudocode):
const crypto = require('crypto');
function validateInitData(initData, botToken) {
const params = new URLSearchParams(initData);
const hash = params.get('hash');
params.delete('hash');
// Сортировка и формирование строки
const dataCheckString = [...params.entries()]
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}=${v}`)
.join('\n');
// Вычисление HMAC
const secretKey = crypto
.createHmac('sha256', 'WebAppData')
.update(botToken)
.digest();
const computedHash = crypto
.createHmac('sha256', secretKey)
.update(dataCheckString)
.digest('hex');
return computedHash === hash;
}
Проверяйте auth_date
Кроме валидации хеша, всегда проверяйте auth_date — если он слишком старый (например, более часа), данные могут быть перехвачены и воспроизведены (replay attack).
Жизненный цикл в коде
Типичная инициализация Mini App с использованием @telegram-apps/sdk-react:
import { useEffect } from 'react';
import { init, miniApp, backButton } from '@telegram-apps/sdk-react';
function App() {
useEffect(() => {
// 1. Инициализация SDK
init();
// 2. Настройка UI
backButton.mount();
miniApp.mount();
// 3. Сигнал готовности
miniApp.ready();
// 4. Очистка при размонтировании
return () => {
backButton.unmount();
};
}, []);
return <div>Mini App готово!</div>;
}
Итоги
| Фаза | Действие | Ключевой метод |
|---|---|---|
| Запуск | Пользователь нажимает кнопку | — |
| Загрузка | Telegram открывает WebView | — |
| Инициализация | WebApp object доступен | initData, initDataUnsafe |
| Ready | Приложение готово | WebApp.ready() |
| Взаимодействие | Работа с UI и данными | События, MainButton |
| Закрытие | Сессия завершена | WebApp.close() |
В следующем уроке разберём тему и элементы управления — CSS-переменные, MainButton и BackButton.
Частые ошибки
- Не слушают событие viewportChanged: при открытии клавиатуры или повороте устройства размеры viewport меняются, и UI должен адаптироваться.
- Забывают вызвать expand() для полноэкранного режима: без этого Mini App открывается в свёрнутом виде, занимая половину экрана.
- Не обрабатывают событие backButtonClicked, полагаясь на браузерную навигацию, хотя в Telegram кнопка «назад» управляется через WebApp API.
- Используют window.close() вместо Telegram.WebApp.close(): это нарушает жизненный цикл и может привести к ошибкам в Telegram-клиенте.
Проверка знанийПочему initData необходимо валидировать на сервере через HMAC-SHA256, а не доверять initDataUnsafe?
Проверьте понимание
Закончили урок?
Отметьте его как пройденный, чтобы отслеживать свой прогресс
Войдите чтобы оценить урок