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

Приложения Telegram известны своей скоростью, плавностью и кросс-платформенным дизайном. Ваше веб-приложение в идеале должно соответствовать этим принципам.

- Все элементы должны быть отзывчивыми и спроектированы с учетом мобильной ориентации устройств.
- Интерактивные элементы должны имитировать стиль, поведение и назначение уже существующих компонентов пользовательского интерфейса.
- Все анимации должны быть плавными, в идеале 60 кадров в секунду.
- Все input и изображения должны содержать label для доступности.
- Приложение должно обеспечивать бесшовную работу, отслеживая изменение цветов темы с помощью API, и используя их соответствующим образом.

Давайте же опробуем это на практике!

Создание кнопки

Первое, что нам нужно сделать - создать кнопку запуска веб-приложения. Это можно сделать двумя способами:

1. При помощи @botfather - кнопка слева снизу

1.1. Идем в @botfather и пишем команду: /setmenubutton

1.2. Далее выбираем бота, которому нужна кнопка веб приложения

1.3. Отправляем ссылку по которой доступно наше веб-приложение

1.4. Пишем имя кнопки - будет отображаться внизу слева

создание кнопки через @botfather
создание кнопки через @botfather
как выглядит main button
как выглядит main button

Вот и все. В целом, если у вас есть адаптивный сайт и вы хотели просто добавить его в бота, тут можете остановиться.

Только при добавлении кнопки этим способом мы можем получить информацию о пользователе.

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()) 

Готово. Кнопки у нас есть.

Тут можно вообще закончить, если вы просто хотели, чтобы пользователь мог открыть ваш сайт из бота (зачем-то). Работать это будет вот так:

как работают web apps
как работают web apps

Работа с веб-приложением

Теперь идем в наше веб-приложение. На момент написания статьи открывается любая ссылка, даже на 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) // задает параметры в виде объекта 
Основная кнопка в тестовом @DurgerKingBot
Основная кнопка в тестовом @DurgerKingBot

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_id
usercard.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
Бот-пример

Комментарии (15)


  1. raamid
    18.05.2022 10:42
    +1

    Интересно, а можно ли в боте для Телеграм запускать веб приложения с использованием WebGL?


    1. mihailgok Автор
      18.05.2022 12:13

      По сути - это практически стандартное окно браузера, открытое поверх телеграм. Так что: почему нет? - Как-то работает)


  1. DesignDiversion
    18.05.2022 12:08

    Ребята, вопрос: в web apps есть кэш на картинки и css файлы. Вопрос - как это убрать для css?


    1. mihailgok Автор
      18.05.2022 12:20

      При обновлении кода сайта можно ставить версии подключенных файлов:

      <link rel="stylesheet" href="style.css?v1.1">

      Или же вовсе запретить кэш.


      1. DesignDiversion
        18.05.2022 13:57
        +1

        Благодарю за ответ, попробую!


  1. kubk
    18.05.2022 14:42
    +1

    Это безусловно интересный функционал в Телеграм, открывающий доселе невиданные возможности при создании ботов. Но остался вопрос с точки зрения безопасности. Так как итоговый бот это HTML-страница, то можно воспользоваться официальной веб-версией Телеграм, чтобы извлечь iframe и запустить страницу локально. В такую страницу можно внести любые модификации, например подменить глобальную переменную tg, верно? И например использовать идентификатор другого пользователя.


    1. ikely
      18.05.2022 16:14
      +1

      На данный момент Web приложения в web.telegram.org не поддерживаются, но я думаю к релизу разработчики выдадут безопасное обновление в web-версии)


      1. kubk
        18.05.2022 16:32

        Сейчас официальные это webz/webk, победители конкурсов. Они поддерживают web приложения, вот даже код с iframe'ом. Интересно как будет решена проблема безопасного общения клиента и сервера для web ботов.


  1. Dr_Malevich
    18.05.2022 23:51
    +1

    Бесконечно благодарен!


  1. Mitiplay2
    19.05.2022 11:38

    Кнопка слева снизу для вызова Webapp получается в группе не работает?


    1. s0ftik3
      19.05.2022 12:11

      вебботы добавляются к вам в менюшку, при нажатии на скрепку. Однако доступно это не всем) Пока что только для ботов, авторы которых занесли телеграму 2 миллиона евро в их рекламном кабинете


      1. Mitiplay2
        20.05.2022 00:07

        К сожалению это доступно только в приватных чатах.


  1. s0ftik3
    19.05.2022 11:41

    забавно, что автор закрасил свой айдишник, но оставил юзерку. Любой может открыть его профиль и при необходимости, имея кастомный клиент например, достать айди) Но толку в этом нет, ибо айди тебе абсолютно ничего не даст. Люди, не бойтесь палить свой айдишник) Не заморачивайтесь, он итак публичный, и кому надо — его достанут


  1. DmitryBobryakov
    19.05.2022 12:35

    Пишу бота с WebApp уже месяц с самого релиза, есть парочка моментов.

    1) В офф документации очень мало инфы

    2) Объект initData передаётся согласно офф докам только через inline кнопку, но первые 2 недели было наоборот- только через неё объект не передавался.

    3) Почему initData не передаётся через остальные кнопки- непонятно.

    Самое главное:

    4) Не сбрасываются куки. Я прошёл аутентификацию через сторонний сервис (он через 302 статус и хэдер set-cookies проставил у меня в WebApp куку) месяц назад- кука с токеном сессии до сих пор жива и передаётся этому сервису. Сброс кэшей и бд Телеграмма, Хрома, Android WebView не помогает. Единственный выход- переустановка клиента Телеграмма. Возможно, поможет ещё костыль в виде set-cookie из моего WebApp, но я пока не пробовал.


  1. merlinkory
    20.05.2022 17:35

    Не кто не сталкивался, с тем что в Desktop версии (window) телеграмма в WebApps не работает часть браузерного API, например тот же alert() ?