Создание telegram web apps и взаимодействие с ними в телеграм ботах
the MatrixВ обновлении Bot API 6.0 телеграм-боты получили много новых функций. Из них для разработчиков самая примечательная - Telegram Web Apps (Веб-приложения внутри телеграм). С этим нововведением разработчики могут подключать к своим ботам web-приложения, которые открываются в дополнительном окне, что сильно расширяет инструментарий, а, следовательно и функционал ботов в телеграм.


Вот и все. В целом, если у вас есть адаптивный сайт и вы хотели просто добавить его в бота, тут можете остановиться.
Только при добавлении кнопки этим способом мы можем получить информацию о пользователе.
2. В коде бота - клавиатурные кнопки.
Запуск бота с inline-кнопки даёт суть тоже самое, что и предидущий вариант. Однако, запуск с keyboard button дает возможность отправлять данные из веб-приложения в бота.
Покажу на примере pytelegrambotapi - я понимаю, что это не самая популярная библиотека для написания телеграмм-ботов, но так получилось, что я пишу именно на ней. Если вы пользуетесь другой библиотекой/языком, думаю, вам не составит труда действовать по аналогии. Вы можете сразу посмотреть пример или перейти в репозиторий и посмотреть код с комментариями:
2.1. Делаем все стандартные штуки для запуска бота - импорт библиотеки, ввод токена, infinity_polling, обработчик команды start. Если вы не понимаете о чем я, вам сюда.
2.2. Создаем функцию, которая вернет нам клавиатуру с нужной кнопкой.
Для того, чтобы создать кнопку, нужно сначала создать WebAppInfo-объект внутри которого будет url на наш сайт.
def webAppKeyboard(): #создание клавиатуры с webapp кнопкой keyboard = types.ReplyKeyboardMarkup(row_width=1) #создаем клавиатуру webAppTest = types.WebAppInfo("https://telegram.mihailgok.ru") #создаем webappinfo - формат хранения url one_butt = types.KeyboardButton(text="Тестовая страница", web_app=webAppTest) #создаем кнопку типа webapp keyboard.add(one_butt) #добавляем кнопки в клавиатуру return keyboard #возвращаем клавиатуру
2.3. Отправляем сообщение с нашей клавиатурой при отправке команды или любом другом действии:
bot.send_message( message.chat.id, 'Привет, я бот для проверки телеграмм webapps!)', reply_markup=webAppKeyboard())
Готово. Кнопки у нас есть.
Тут можно вообще закончить, если вы просто хотели, чтобы пользователь мог открыть ваш сайт из бота (зачем-то). Работать это будет вот так:

Теперь идем в наше веб-приложение. На момент написания статьи открывается любая ссылка, даже на codepen.
Инициализация
Чтобы взаимодействовать с телеграм подключаем скрипт:
<script src="https://telegram.org/js/telegram-web-app.js"></script>
После этого нам будет доступен объект: window.Telegram.WebApp
Записываем его в переменную и начинаем нашу работу.
let tg = window.Telegram.WebApp;
Что же мы теперь можем? Не так много, как хотелось бы, но и не мало. Приложение состоит из: основной кнопки (telegram-объект) и самой страницы, которая загрузилась по ссылке. Остальные элементы telegram-интерфейса нам не доступны. Однако, доступны цвета темы пользователя:

Цвета
Они доступны в формате hex как css-переменные:
var(--tg-theme-bg-color)
var(--tg-theme-text-color)
var(--tg-theme-hint-color)
var(--tg-theme-link-color)
var(--tg-theme-button-color)
var(--tg-theme-button-text-color)
Или как объект ThemeParams в js (вместо window.Telegram.WebApp я использую переменную tg):
tg.ThemeParams.bg_color
tg.ThemeParams.text_color
tg.ThemeParams.hint_color
tg.ThemeParams.link_color
tg.ThemeParams.button_color
tg.ThemeParams.button_text_colorString
Но будьте осторожны, цвета - необязательный параметр, поэтому стоит проверять, есть ли они, перед тем как использовать.
Также имеется обработчик события изменения цветовой схемы:
Telegram.WebApp.onEvent(themeChanged, function(){});
При изменении цветовой схемы или размеров окна можно поменять что-то и в нашем веб-приложении.
Основные возможности
С цветами разобрались - теперь к другим основным параметрам:
tg.initData //получаем данные от пользователя в виде строки (работает только при запуске из меню команд бота). tg.initDataUnsafe // получаем данные от пользователя в виде объекта (работает только при запуске из меню команд бота). tg.isExpanded // возвращает true, если приложение открыто на всю высоту, false - если нет. tg.viewportHeight // вернёт ширину окна.tg.sendData(data) // отправляет данные боту в строковом виде, после чего закрывает приложение (работает только если приложение запущено с keyboard button). tg.ready() // метод позволяет отследить, когда приложение готово к отображению.tg.expand() // метод позволяет растянуть окно на всю высоту.tg.close() // метод закрывает приложение.
Main button
Мы можем взаимодействовать с кнопкой внизу приложения. Изменять ее текст, цвет фона и текста, показывать/скрывать, делать активной и деактивировать:
tg.MainButton.text // текст кнопки, по умолчанию: "Continue"tg.MainButton.color // цвет текстаtg.MainButton.textColor // цвет подложкиtg.MainButton.isVisible // видна ли кнопка (по умолчанию false) tg.MainButton.isActive // активна ли кнопка (по умолчанию true)tg.MainButton.setText(text) // метод для задания текстаtg.MainButton.onClick(callback) // метод при нажатии на кнопкуtg.MainButton.show() // показать кнопку tg.MainButton.hide() // скрыть кнопкуtg.MainButton.enable() // сделать активной tg.MainButton.disable() // сделать неактивной tg.MainButton.setParams(params) // задает параметры в виде объекта

Web App User
И еще информация о пользователе, мы можем разобрать строку tg.initData
или использовать tg.initDataUnsafe
объект:
tg.initDataUnsafe.user.id // уникальный идентификатор пользователяtg.initDataUnsafe.user.isBot // бот ли пользователь (true/false)tg.initDataUnsafe.user.first_name // имя пользователяtg.initDataUnsafe.user.last_name // "фамилия" пользователяtg.initDataUnsafe.user.username // username пользователяtg.initDataUnsafe.user.language_code // код языка пользователя
Пишем веб-приложениеС этой информацией мы можем написать небольшое приложение, которое наглядно отобразит основные возможности.
Не забудьте подключить скрипт:
<script src="https://telegram.org/js/telegram-web-app.js"></script>
1. Создадим небольшую html-основу:
<body> <div id="usercard"> <!--Карта профиля, человека, который к нам обратился--> </div> <p>Just text</p> <!--Просто текст для проверки--> <a class="link" href="https://mihailgok.ru">Link</a> <!--Просто ссылка для проверки--> <p class="hint">Some little hint</p> <!--Просто текст-подсказка для проверки--> <button id="btn" class="button">Show/Hide Main Button</button> <!--Кнопка, чтобы скрыть / показать основную кнопку--> <button id="btnED" class="button">Enable/Disable Main Button</button> <!--Кнопка, чтобы сделать кнопку активной/неактивной--></body>
2. Пропишем изменения текста основной кнопки и изменение цвета:
let tg = window.Telegram.WebApp; //получаем объект webapp телеграма tg.expand(); //расширяем на все окно tg.MainButton.text = "Changed Text"; //изменяем текст кнопки tg.MainButton.setText("Changed Text1"); //изменяем текст кнопки иначеtg.MainButton.textColor = "#F55353"; //изменяем цвет текста кнопкиtg.MainButton.color = "#143F6B"; //изменяем цвет бэкграунда кнопкиtg.MainButton.setParams({"color": "#143F6B"}); //так изменяются все параметры
3. Далее повесим обработчик события на первую html-кнопку и при нажатии будем показывать/скрывать основную telegram-кнопку:
btn.addEventListener('click', function(){ //вешаем событие на нажатие html-кнопки if (tg.MainButton.isVisible){ //если кнопка показана tg.MainButton.hide() //скрываем кнопку } else{ //иначе tg.MainButton.show() //показываем }});
4. Еще один обработчик события на вторую html-кнопку, при нажатии которой будем активировать/деактивировать основную telegram-кнопку:
let btnED = document.getElementById("btnED"); //получаем кнопку активировать/деактивироватьbtnED.addEventListener('click', function(){ //вешаем событие на нажатие html-кнопки if (tg.MainButton.isActive){ //если кнопка показана tg.MainButton.setParams({"color": "#E0FFFF"}); //меняем цвет tg.MainButton.disable() //скрываем кнопку } else{ //иначе tg.MainButton.setParams({"color": "#143F6B"}); //меняем цвет tg.MainButton.enable() //показываем }});
5. В итоге отправляем данные при нажатии на основную telegram-кнопку:
Telegram.WebApp.onEvent('mainButtonClicked', function(){ tg.sendData("some string that we need to send"); //при клике на основную кнопку отправляем данные в строковом виде});
Благодаря этому методу мы можем получить данные из веб-приложения в боте.
6. Также выведем всю информацию о пользователе (будет доступна только при запуске с кнопки, добавленной с помощью @botfather).
Нам доступно: id / isBot / first_name / last_name / username / language_code
let usercard = document.getElementById("usercard"); //получаем блок usercard let profName = document.createElement('p'); //создаем параграфprofName.innerText = `${tg.initDataUnsafe.user.first_name}${tg.initDataUnsafe.user.last_name}${tg.initDataUnsafe.user.username} (${tg.initDataUnsafe.user.language_code})`;//выдем имя, "фамилию", через тире username и код языкаusercard.appendChild(profName); //добавляем let userid = document.createElement('p'); //создаем еще параграф userid.innerText = `${tg.initDataUnsafe.user.id}`; //показываем user_idusercard.appendChild(userid); //добавляем
7. И добавляем стили, используя telegram-css переменные:
body{ color: var(--tg-theme-text-color); background: var(--tg-theme-bg-color); display: flex; flex-direction: column; align-items: center; font-size: 18px;}.hint{ color: var(--tg-theme-hint-color);}.link{ color: var(--tg-theme-link-color);}.button{ background: var(--tg-theme-button-color); color: var(--tg-theme-button-text-color); border: none; font-size: 18px;}.button:not(:last-child){ margin-bottom: 20px}#usercard{ text-align: center;}
В итоге получаем такое веб-приложение:

Оно отображает основные возможности - получение информации о пользователе, задействование цветов его темы и управление главной кнопкой приложения.
Получаем данные от веб-приложения в ботеТеперь вешаем обработчик событий на сообщение, которое посылает веб-приложение в методе send (работать будет только с keyboard button):
@bot.message_handler(content_types="web_app_data") #получаем отправленные данные def answer(webAppMes): print(webAppMes) #вся информация о сообщении print(webAppMes.web_app_data.data) #конкретно то что мы передали в бота bot.send_message(webAppMes.chat.id, f"получили инофрмацию из веб-приложения: {webAppMes.web_app_data.data}") #отправляем сообщение в ответ на отправку данных из веб-приложения
И все - теперь мы можем получать информацию с сайта и отвечать на нее.
Есть и другие способы - но это уже немного другая история.
Исходники: github, codepen
Бот-пример
Источник
Наши проекты:
- Кибер новости: the Matrix
- Хакинг: /me Hacker
- Кодинг: Minor Code