Создание мини-приложения для Telegram: пошаговое руководство
Создание мини-приложения для Telegram: пошаговое руководство
Вы когда-нибудь хотели охватить миллионы пользователей без необходимости скачивать ваше приложение? Это именно то, что предлагают мини-приложения Telegram. Имея более 800 миллионов активных пользователей в месяц, Telegram предоставляет невероятную платформу для развертывания ваших приложений непосредственно в своей экосистеме.
Зачем создавать мини-приложение для Telegram?
- Мгновенный доступ: охватите миллионы пользователей без барьеров
в магазине приложений- Нативная интеграция: бесшовный опыт в интерфейсе
Telegram- Возможности в реальном времени: идеально подходит для приложений
для совместной работы- Отсутствие установки: пользователи могут сразу начать использовать ваше приложение
Во время недавнего проекта я разрабатывал приложение Telegram Mini и столкнулся с несколькими проблемами из-за ограниченного объема документации. Я решил поделиться тем, что узнал из этого.
В этом подробном руководстве мы создадим доску задач для совместной работы в группах Telegram с нуля. Вы узнаете, как:
- Настроить проект Next.js с помощью TypeScript
- Интегрировать Firebase для управления
данными в режиме реального времени- Развернуть свое мини-приложение в рабочей среде
- Справиться с распространенными ошибками и их решениями
Интересует создание миниапсов или ботов в телеграмме?
Хотите заказать или научиться делать сами?
Обращайтесь в наш канал Вокруг Крипты
Понимание объема проекта
Мы создаем систему управления задачами, которая позволяет участникам группы Telegram позволять:
- Создавать и управлять задачами вместе
- Отслеживать статус
выполнения задач- Удалять выполненные задачи
- Все это в режиме реального времени, прямо в Telegram
Архитектура проекта
- Приложение Telegram Mini служит точкой входа для пользователей, обеспечивая бесшовную интеграцию с нативным интерфейсом Telegram. Он предлагает прямой доступ к функциям веб-приложения, позволяя пользователям взаимодействовать с приложением, не покидая среду Telegram.
- Next.js Web App — это ядро нашего приложения, обрабатывающее основную логику приложения с возможностями рендеринга на стороне сервера. Созданный с использованием TypeScript для повышения удобства обслуживания, он предоставляет полный набор функций и управляет всеми взаимодействиями с пользователем.
- Firebase действует как наша центральная система управления данными, обеспечивая возможности базы данных в режиме реального времени и выполняя аутентификацию. Он обеспечивает синхронизацию данных между всеми компонентами и предлагает надежные облачные функции для серверных операций.
- Telegram Bot управляет автоматическими уведомлениями и осуществляет прямую связь с Firebase. Он обрабатывает команды и предоставляет дополнительный функционал через интерфейс бота Telegram, дополняя опыт Mini App.
💡 Совет от > Pro: Этот урок предполагает базовые знания React и TypeScript. Если вы новичок в этих технологиях, сначала ознакомьтесь с их основами.
Давайте погрузимся и создадим что-то удивительное вместе!
Мини-приложение
Мы собираемся создать совместную доску заданий для групп Telegram. Это мини-приложение позволит членам группы создавать, назначать и управлять задачами вместе в интерфейсе Telegram.
Настройка проекта
Сначала мы создаем проект NextJs и устанавливаем необходимые пакеты:
npx create-next-app@latest task-board-telegramcd task-board-telegramnpm install @telegram-apps/sdk-react firebase @headlessui/react @heroicons/reactnpm install telegraf dotenv
Создание веб-приложения
После настройки нашего проекта давайте создадим простую доску задач, которая будет интегрироваться с группами Telegram. Сейчас мы просматриваем каждый файл. Если вы не хотите проходить, вы можете клонировать репозиторий GitHub по этой ссылке https://github.com/Tanguyvans/task-board-telegram
1. Конфигурация Firebase
Прежде чем мы сможем использовать Firebase в нашем приложении, нам нужно правильно его настроить:
a) Создайте проект Firebase:
- Перейдите в [Консоль Firebase](https://console.firebase.google.com/)
- Нажмите "Добавить проект"
- Назовите свой проект (например, "task-board-telegram")
б) Включите Firestore:
- В консоли Firebase перейдите в раздел "Firestore Database"
- Нажмите "Создать базу данных"
- Выберите "Запустить в тестовом режиме" для разработки
- Выберите место, ближайшее к вашим пользователям
c) Получите конфигурацию Firebase:
- Перейдите в настройки проекта (⚙️ иконка)
- На вкладке "Общие" прокрутите до "Ваши приложения"
- Нажмите на веб-иконку (</>)
- Зарегистрируйте свое приложение с псевдонимом
- Скопируйте объект firebaseConfig
г) Настройте переменные среды:
Создайте файл '.env.local' в корне вашего проекта:
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_keyNEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.comNEXT_PUBLIC_FIREBASE_DATABASE_URL=https://your_project.firebaseio.comNEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_idNEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.comNEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_idNEXT_PUBLIC_FIREBASE_APP_ID=your_app_idNEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_id
Во-первых, нам нужно настроить Firebase. Создадим новый файл 'app/lib/firebase.ts':
'use client';import { initializeApp } from "firebase/app";import { getFirestore, Firestore } from "firebase/firestore";const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID};// Initialize Firebase only on client sidelet app;let db: Firestore;if (typeof window !== 'undefined') { app = initializeApp(firebaseConfig); db = getFirestore(app);}export { db };
2. Создание интерфейса задания
export interface Task { id: string; title: string; completed: boolean; createdAt: Date; groupId: string; }
3. Сборка компонентов
Создайте 'app/components/TaskForm.tsx':
"use client";import { useState } from 'react';import { addDoc, collection } from 'firebase/firestore';import { db } from '@/app/lib/firebase';interface TaskFormProps { groupId: string;}export default function TaskForm({ groupId }: TaskFormProps) { const [title, setTitle] = useState(''); const [error, setError] = useState<string | null>(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!title.trim() || !db) return; try { await addDoc(collection(db, 'tasks'), { title: title.trim(), completed: false, createdAt: new Date(), groupId, }); setTitle(''); setError(null); } catch (err) { console.error('Error adding task:', err); setError('Failed to add task'); } }; return ( <form onSubmit={handleSubmit} className="space-y-4"> <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Add a new task" className="w-full px-4 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" /> <button type="submit" className="w-full bg-blue-500 text-white py-2 rounded-md hover:bg-blue-600 transition-colors" > Add Task </button> </form> );}
Создайте 'app/components/TaskItem.tsx':
"use client";import { useState } from 'react';import { updateDoc, doc, deleteDoc } from 'firebase/firestore';import { db } from '@/app/lib/firebase';import { Task } from '@/app/types/task';interface TaskItemProps { task: Task;}export default function TaskItem({ task }: TaskItemProps) { const [isCompleted, setIsCompleted] = useState(task.completed); const toggleComplete = async () => { setIsCompleted(!isCompleted); await updateDoc(doc(db, 'tasks', task.id), { completed: !isCompleted, }); }; const deleteTask = async () => { await deleteDoc(doc(db, 'tasks', task.id)); }; return ( <li className="flex items-center justify-between p-4 bg-white rounded-lg shadow"> <div className="flex items-center space-x-4"> <input type="checkbox" checked={isCompleted} onChange={toggleComplete} className="form-checkbox h-5 w-5 text-blue-600" /> <span className={isCompleted ? 'line-through text-gray-500' : ''}> {task.title} </span> </div> <button onClick={deleteTask} className="text-red-500 hover:text-red-700" > Delete </button> </li> );}
Создайте 'app/components/TaskList.tsx':
"use client";import { useState, useEffect } from 'react';import { collection, query, where, onSnapshot } from 'firebase/firestore';import { db } from '@/app/lib/firebase';import TaskItem from '@/app/components/TaskItem';import { Task } from '@/app/types/task';interface TaskListProps { groupId: string;}export default function TaskList({ groupId }: TaskListProps) { const [tasks, setTasks] = useState<Task[]>([]); useEffect(() => { const q = query( collection(db, 'tasks'), where('groupId', '==', groupId) ); const unsubscribe = onSnapshot(q, (querySnapshot) => { const taskList: Task[] = []; querySnapshot.forEach((doc) => { taskList.push({ id: doc.id, ...doc.data() } as Task); }); setTasks(taskList); }); return () => unsubscribe(); }, [groupId]); return ( <ul className="space-y-4"> {tasks.map((task) => ( <TaskItem key={task.id} task={task} /> ))} </ul> );}
4. Развертывание на Vercel
Развернуть приложение Telegram Mini на Vercel очень просто:
a) Подготовьтесь к развертыванию:
- Убедитесь, что ваш код отправлен на GitHub
- Создайте [учетную запись Vercel](https://vercel.com)
b) Разверните приложение:
- Перейдите в [Vercel Dashboard](https://vercel.com/dashboard)
- Нажмите "Новый проект"
- Импортируйте свой репозиторий
GitHub- Настройте проект:
— Предустановка фреймворка: Next.js
— Корневой каталог: ./
— Команда сборки: следующая сборка
— Выходной каталог: .next
в) Переменные среды:
- В настройках проекта Vercel перейдите в раздел "Переменные среды"
- Добавьте все переменные среды Firebase:
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_keyNEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.comNEXT_PUBLIC_FIREBASE_DATABASE_URL=https://your_project.firebaseio.comNEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_idNEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.comNEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_idNEXT_PUBLIC_FIREBASE_APP_ID=your_app_idNEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_id
d) Развертывание:
- Нажмите "Развернуть"
- Дождитесь завершения
сборки - Ваше приложение будет доступно по адресу: "https://your-project.vercel.app"
Создание Telegram-бота
1. Создание бота с помощью BotFather
Во-первых, нам нужно создать нового бота с помощью BotFather от Telegram:
1. Откройте Telegram и выполните поиск по запросу [@BotFather](https://t.me/botfather)
2. Отправьте команду
'/newbot' 3. Выберите имя для вашего бота
4. Выберите имя пользователя (должно заканчиваться на 'bot')5
. Важно: Сохраните предоставленный токен API, он вам понадобится позже
2. Настройка команд бота
Настройте команды бота с помощью команды '/setcommands' от BotFather:
3. Строительный бот
Создайте новую директорию 'bot' в корне вашего проекта:
mkdir botcd botmkdir commands types
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_keyNEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.comNEXT_PUBLIC_FIREBASE_DATABASE_URL=https://your_project.firebaseio.comNEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_idNEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.comNEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_sender_idNEXT_PUBLIC_FIREBASE_APP_ID=your_app_idNEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=your_measurement_idBOT_TOKEN= bot_tokenWEBAPP_URL= your_vercel_url
const dotenv = require('dotenv');const path = require('path');dotenv.config({ path: path.resolve(__dirname, '../.env.local') });module.exports = { BOT_TOKEN: process.env.BOT_TOKEN, WEBAPP_URL: process.env.WEBAPP_URL};
const { Telegraf } = require('telegraf');const { BOT_TOKEN, WEBAPP_URL } = require('./config');if (!BOT_TOKEN) { throw new Error('BOT_TOKEN must be provided!');}const bot = new Telegraf(BOT_TOKEN);// Basic commandsbot.command('start', (ctx: any) => { ctx.reply('Welcome to TaskVaultBot! 🚀\nUse /help to see available commands.');});bot.command('help', (ctx: any) => { ctx.reply( 'Available commands:\n' + '/start - Start the bot\n' + '/help - Show this help message\n' + '/webapp - Open the Mini App' );});bot.command('webapp', (ctx: any) => { ctx.reply('Open Web App', { reply_markup: { inline_keyboard: [[ { text: "Open App", web_app: { url: WEBAPP_URL || '' }} ]] } });});bot.launch().then(() => { console.log('Bot is running...');});// Enable graceful stopprocess.once('SIGINT', () => bot.stop('SIGINT'));process.once('SIGTERM', () => bot.stop('SIGTERM'));
Запуск бота
Добавьте в свой 'package.json':
{ "scripts": { "bot:dev": "ts-node bot/index.ts" }}
npm run bot:dev
Текущие ограничения
На этом шаге у вас должно быть полностью работающее приложение. Тем не менее, есть две основные проблемы:
Разрешения группового чата: бот не будет отвечать на команду «/webapp» в группах Telegram
Отсутствует идентификатор группы: при открытии мини-приложения вы получите сообщение о том, что мы не предоставили идентификатор группы.
Интеграция с группами обработки
Чтобы сделать наше веб-приложение доступным в группах Telegram, нам необходимо зарегистрировать его как мини-приложение:
Создание мини-приложения с помощью BotFather
Чтобы сделать наше веб-приложение доступным в группах Telegram, нам нужно зарегистрировать его как Mini App:
— Открыть @BotFather в Telegram
— Отправить команду
'/newapp' — Выбрать своего бота из списка
— Введите имя для вашего мини-приложения
— Укажите URL-адрес вашего веб-приложения (из развертывания Vercel)
— Выберите короткое имя (необязательно)
— Загрузите фотографию профиля (необязательно)
После завершения настройки BotFather предоставит вам URL-адрес мини-приложения.
Обновление кода
Обновите файл .env.local, указав новый URL-адрес мини-приложения:
WEBAPP_URL=https://t.me/YourBotName/Home # Replace with your Mini App URL
Измените команду webapp в 'bot/index.ts', чтобы использовать URL-адрес мини-приложения:
bot.command('webapp', (ctx: any) => { ctx.reply('Open Web App', { reply_markup: { inline_keyboard: [[ { text: "Open App", url: WEBAPP_URL || '' } ]] } });});
💡 > **Профессиональный совет**: Обязательно перезапустите бота после обновления переменных среды, чтобы изменения вступили в силу.
Интеграция идентификатора группы
Чтобы наше мини-приложение работало в группах Telegram, нам нужно правильно передать и обработать идентификатор группы. Это позволяет нам управлять задачами, специфичными для каждой группы.
Обновление бота
Для начала модифицируем нашего бота так, чтобы он передавал идентификатор чата группы в мини-приложение:
bot.command('webapp', (ctx: any) => { const chatId = ctx.chat.id; // Encode le chatId en base64 const encodedGroupId = Buffer.from(chatId.toString()).toString('base64'); console.log('Chat ID:', chatId); console.log('Encoded Group ID:', encodedGroupId); ctx.reply('Open Web App', { reply_markup: { inline_keyboard: [[ { text: "Open App", url: `${WEBAPP_URL}?startapp=${encodedGroupId}` } ]] } });});
💡 > **Примечание**: Мы используем кодировку base64 для безопасной передачи идентификатора чата через URL.
Обработка идентификатора группы в веб-приложении
Далее нам нужно обновить наше веб-приложение, чтобы получать и обрабатывать этот параметр. В Telegram Mini Apps мы можем получать параметры только через параметр 'startapp'.
Вот наша обновленная страница «page.tsx»:
"use client";import { Suspense, useEffect, useState } from 'react';import Image from "next/image";import TaskList from "./components/TaskList";import TaskForm from "./components/TaskForm";import { useLaunchParams } from "@telegram-apps/sdk-react";import dynamic from 'next/dynamic';// Créer un composant client-only pour le TaskBoardconst TaskBoardClient = dynamic(() => Promise.resolve(TaskBoard), { ssr: false});function TaskBoard() { const [groupId, setGroupId] = useState<string | null>(null); const [error, setError] = useState<string | null>(null); const [isLoading, setIsLoading] = useState<boolean>(true); const launchParams = useLaunchParams(); useEffect(() => { const initializeComponent = async () => { try { if (launchParams?.startParam) { const encodedGroupId = launchParams.startParam; try { const decodedGroupId = atob(encodedGroupId); console.log("Decoded Group ID:", decodedGroupId); setGroupId(decodedGroupId); } catch (error) { console.error("Error decoding group ID:", error); setError("Invalid group ID format"); } } else { console.log("No start_param available"); setError("No group ID provided"); } } catch (error) { console.error("Error in initializeComponent:", error); setError("An error occurred while initializing the component"); } finally { setIsLoading(false); } }; initializeComponent(); }, [launchParams]); if (isLoading) { return <div className="p-8">Loading...</div>; } if (error) { return <div className="p-8 text-red-500">{error}</div>; } if (!groupId) { return <div className="p-8">Please provide a valid group ID</div>; } return ( <div className="grid grid-rows-[auto_1fr_auto] min-h-screen p-8 gap-8"> <header className="flex items-center justify-between"> <Image className="dark:invert" src="/next.svg" alt="Next.js logo" width={100} height={20} priority /> <h1 className="text-2xl font-bold">Task Board - Group {groupId}</h1> </header> <main className="flex flex-col gap-8"> <TaskForm groupId={groupId} /> <TaskList groupId={groupId} /> </main> <footer className="flex justify-center text-sm text-gray-500"> Powered by Next.js </footer> </div> );}export default function Home() { return ( <Suspense fallback={<div className="p-8">Loading...</div>}> <TaskBoardClient /> </Suspense> );}
Основные детали реализации
1. Bot Side:
— Кодирует идентификатор чата группы в base64
— Передает его через параметр
URL startapp — Регистрирует идентификаторы для отладки
2. Сторона веб-приложения:
— Использует 'useLaunchParams' для получения параметра
'startapp' — Декодирует идентификатор группы из base64
— Обрабатывает различные состояния (загрузка, ошибка, успех)
— Рендеринг только на стороне клиента для предотвращения проблем с SSR
Результат
При правильной интеграции наше мини-приложение теперь легко справляется с задачами, специфичными для группы. Давайте рассмотрим, как это работает на практике:
Выполнение команд
При запуске команды «/webapp» в любой группе Telegram генерируется уникальная ссылка, содержащая закодированный идентификатор этой группы. Это позволяет пользователям получать доступ к мини-приложению непосредственно из группового чата, сохраняя групповой контекст на протяжении всего сеанса.
Особенности, специфичные для групп
Приложение Mini App теперь работает в режиме полного учета групп. Все задачи автоматически связываются с текущей группой, что гарантирует, что пользователи видят и управляют только задачами, относящимися к их группе. Обновления в режиме реального времени ограничиваются определенной группой, поддерживая изоляцию данных между различными группами Telegram.
Визуальная верификация
Для обеспечения прозрачности и отладки идентификатор группы отображается в заголовке мини-приложения. Этот визуальный индикатор помогает проверить, работают ли пользователи в правильном контексте группы. Когда пользователи переключаются между разными группами, они будут видеть отдельные списки задач, соответствующие действиям каждой группы.
💡 > **Совет от профессионала**: Протестируйте свое мини-приложение в нескольких группах, чтобы обеспечить надлежащую изоляцию задач между группами.
Заключение
Мы успешно создали мини-приложение для Telegram, которое демонстрирует ключевые концепции интеграции: создание мини-приложения, его интеграцию с группами Telegram и обработку параметров между ботом и веб-приложением. Этот пример дает прочную основу для понимания того, как работают мини-приложения Telegram и как разработать свои собственные.
Интересует создание миниапсов или ботов в телеграмме?
Хотите заказать или научиться делать сами?
Обращайтесь в наш канал Вокруг Крипты