January 20

Телеграм WebApp

Начало работы

git clone https://dev.h3llo.cloud/H3LLO.CLOUD/twa_starter // Клонируем проект
npm install // Установка зависимостей
npm run dev:https // Запуск dev сервера с самозаверенным SSL-сертификатом

Создание бота через @botfather

  1. Начните диалог с @botfather
  2. Команда для создания нового бота /newbot
  3. Следуйте инструкции, бот попросит вас:
  • Указать имя вашего бота (прим. "My new WebApp")
  • Юзернейм (прим. "mynewbot") Имейте ввиду что юзернейм обязательно должен заканчиваться на bot

После указания нужных данных бот сообщит об успешном создании бота и пришлёт в ответ его токен. Для WebApp токен не требуется, однако он нужен для взаимодействия с ботом (отправка сообщений пользователю и т.п.). Подробнее вы можете почитать тут.

Сообщение об успешном создании нового бота.

Создание WebApp

  1. Команда для создания нового приложения /newapp
  2. BotFather попросит указать к какому боту прикрипить приложение
  3. Далее потребуется указать: название, краткое описание, загрузить фото 640х360 пикселей, GIF превью (можно пропустить), ссылку на ваше приложение (прим. https://example.com/my-web-app), а также краткое имя приложения.

После этого бот пришлёт вам ссылку, для запуска вашего приложения внутри Telegram.

Важно! Если вы хотите разрабатывать приложение локально, с поддержкой Hot Reload, укажите https://127.0.0.1:{PORT} в качестве ссылки на ваше приложение и запустите локальный сервер с активным SSL-сертификатом (в т.ч. можно использовать самозаверенный сертификат).
Если после открытия WebApp внутри Telegram вы видите ошибку, откройте ваше приложение в браузере и разрешите использование сертификата.

Разработка WebApp, примеры кода и лайфхаки

1. Поскольку приложение спроектировано так, чтобы контент не превышал высоту экрана, фиксируем экран для удобного взаимодействия при свайпах:

// layout.tsx
<body className="absolute inset-0 h-screen w-screen overflow-hidden">
  {children}
</body>

2. Инициализуем функции, которые предоставляет Telegram в файле init.tsx:

import {backButton, viewport, miniApp, initData, $debug, init as initSDK, swipeBehavior, themeParams} from '@telegram-apps/sdk-react';
/** * Инициализируем приложение и настраиваем зависимости. */

export async function init(debug: boolean): Promise<void> {
  // Устанавливает режим отладки для @telegram-apps/sdk-react.
  $debug.set(debug);
  
  // Инициализируем специальные обработчики событий для Telegram Desktop, Android, iOS и т.д.
  // Также настраиваем пакет.
  
  initSDK();
  
  // Кнопка назад.
  if (backButton.isSupported()) {
    backButton.mount();
  }
  
  // Определяем CSS-переменные, связанные с компонентами.
  if (!miniApp.isMounted()) {
    miniApp.mount();
  }
  
  // Создаём CSS переменные вроде:
  // --tg-bg-color: #aabbcc
  // --tg-header-color: #aabbcc
  if (miniApp.bindCssVars.isAvailable()) {
    miniApp.bindCssVars();
  }
  
  if (!themeParams.isMounted()) {
    themeParams.mount();
  }
  
  // Создаём CSS переменные вроде:
  // --tg-theme-button-color: #aabbcc
  // --tg-theme-accent-text-color: #aabbcc
  // --tg-theme-bg-color: #aabbcc
  if (themeParams.bindCssVars.isAvailable()) {
    themeParams.bindCssVars();
  }
  
  if (!viewport.isMounted() && !viewport.isMounting()) {
    void viewport.mount().catch((e) => {
      console.error("Something went wrong mounting the viewport", e);
    }).then(() => {
      // Переводим приложение в полноэкранный режим, если это возможно.
      if (viewport.requestFullscreen.isSupported() && viewport.requestFullscreen.isAvailable() && !viewport.isFullscreen()) viewport.requestFullscreen() });
  }
  

  // Создаём CSS переменные вроде:
  // --tg-viewport-height: 675px
  // --tg-viewport-width: 320px
  // --tg-viewport-stable-height: 675px
  if (viewport.bindCssVars.isAvailable()) {
    viewport.bindCssVars();
  }
  
  // Отключаем вертикальные свайпы (чтобы пользователь случайно не свернул приложение)
  if (!swipeBehavior.isMounted()) {
    swipeBehavior.mount();
  }
  
  if (swipeBehavior.disableVertical.isAvailable()) {
    swipeBehavior.disableVertical();
  }
  
  // Восстанавливаем initData
  initData.restore();
}

3. Хендлер для управления кнопкой "Назад":

'use client';

import { backButton } from '@telegram-apps/sdk-react';
import { PropsWithChildren, useEffect } from 'react';
import {useRouter} from "next/navigation";

export function BackButtonHandler({ children, back = true }: PropsWithChildren<{
 /**
  * True если нужно отображать кнопку, иначе false.
  */
  back?: boolean
}>) {
  const router = useRouter()
  useEffect(() => {
    if (back) {
      backButton.show();
        return backButton.onClick(() => {
          router.back();
        });
      }
    backButton.hide();
  }, [back, router]);
  
  return children;
}