IlmHamroh
JavaScript Full-stack/21-qism. React: media, integratsiyalar, PWA22/32-dars23 daqiqa
Mundarija (36)

Telegram Mini Apps React'da: WebApp SDK, initData, tema, MainButton va BackButton

Qisqacha: Telegram Mini App — Telegram ichida ochiladigan oddiy veb sahifa (sizning React ilovangiz). Telegram unga telegram-web-app.js orqali window.Telegram.WebApp obyektini beradi: foydalanuvchi (initDataUnsafe.user), tema ranglari (themeParams va --tg-theme-* CSS o'zgaruvchilari), pastdagi asosiy tugma (MainButton), orqaga tugmasi (BackButton), tebranish (HapticFeedback). initDataUnsafe — faqat ko'rsatish uchun: unga ishonib bo'lmaydi, tekshiruv — serverda (keyingi dars). Biz bot yaratmadik: darsda Telegram muhiti soxta obyekt (mock) bilan taqlid qilinadi.

Bu darsda

  • Mini App qanday ochilishini va Telegram unga qanday ma'lumot berishini (manzildagi #tgWebAppData) tushuntirasiz.
  • initData va initDataUnsafe farqini bilasiz va foydalanuvchi ismini ko'rsatasiz.
  • Interfeysni Telegram temasiga moslaysiz: themeParams, --tg-theme-*, themeChanged.
  • MainButton, BackButton va HapticFeedback ni React hook'lari bilan ulaysiz (cleanup bilan).
  • Viewport, BotFather sozlamalari va SDK kutubxonalarini (@tma.js/sdk-react, @twa-dev/sdk) taqqoslaysiz.

Oldin bilishingiz kerak: Custom hooklar II, useEffect III: cleanup, Dev server proxy, HTTPS va CORS, CSS o'zgaruvchilar, To'lov UI.

1. Nega bu kerak?

O'tgan darsda «Bahor» saytiga to'lov qo'shdik. Jasur aka statistikaga qaradi: mehmonlarning ko'pi saytga emas, Telegram kanaliga keladi. "Menyuni Telegram'ning o'zida ochsak bo'lmaydimi? Saytga o'tib, qaytadan kirish — ko'pchilik shu yerda tashlab ketadi".

Bo'ladi. Telegram Mini App (avvalgi nomi — Web App) — bot orqali Telegram ichida ochiladigan veb sahifa. Mehmon tugmani bosadi — menyu Telegram oynasining o'zida ochiladi. Ismi allaqachon ma'lum, rangi Telegram temasiga mos, pastda Telegram'ning katta ko'k tugmasi: «Savatcha (2)».

Ichida esa — sizning oddiy React ilovangiz. Yangi til yoki framework o'rganish shart emas.

Hayotiy o'xshatish: savdo markazidagi do'kon. Bino (Telegram) — eshik, yorug'lik, lift, qo'riqchi umumiy. Do'kon ichi (sizning sahifangiz) — o'zingizniki. Do'kon binoning "tugmalari" dan foydalanadi: "Kassaga" yo'nalish belgisi bino tomonidan osiladi, lekin u sizning kassangizga olib boradi.

2. Mini App qanday ochiladi

2.1 Kirish eshiklari

Mini App'ni bot ochadi. Telegram bir necha "eshik" beradi:

Eshik Qanday ko'rinadi
Menyu tugmasi bot chatidagi kiritish maydoni yonida «Menyu»
Inline tugma bot xabari ostidagi tugma (web_app turi)
To'g'ridan havola t.me/<bot>/<ilova> — har qayerdan, kanaldan ham
Asosiy Mini App bot profilidagi «Ilovani ochish» (Bot API 7.8+)

Hammasi bot orqali sozlanadi — BotFather (Telegram'ning "botlar boti") bilan: /newbot — yangi bot va uning tokeni, /newapp — to'g'ridan havolali Mini App, bot sozlamalarida — menyu tugmasi manzili. Manzil HTTPS bo'lishi shart.

Diqqat: Kurs topshirig'iga ko'ra biz bot yaratmadik va BotFather'da hech narsa sozlamadik. BotFather qadamlari — Telegram hujjati (core.telegram.org/bots/webapps) bo'yicha. Kod esa natija oynasida soxta Telegram muhiti bilan ishlaydi. Haqiqiy botda sinash — sizning 4-mashqingiz.

2.2 Telegram sahifaga nima beradi

Mehmon tugmani bosganda Telegram ichki brauzerda (WebView — ilova ichidagi brauzer oynasi) sizning manzilingizni ochadi va manzil oxiriga # dan keyin ma'lumot qo'shadi:

text
https://example.com/menyu#tgWebAppData=user%3D…&tgWebAppVersion=8.0&tgWebAppPlatform=android&tgWebAppThemeParams=…
sequenceDiagram
  participant M as Mehmon
  participant T as Telegram ilovasi
  participant W as WebView (React)
  participant S as Bizning server
  M->>T: «Menyu» tugmasi
  T->>W: ochadi: manzil + #tgWebAppData=…
  W->>W: SDK hash'ni o'qiydi → WebApp
  W->>T: ready() — yuklanish tugadi
  W->>S: initData (xom satr, imzoli)
  S->>S: imzoni tekshiradi (keyingi dars)
  S-->>W: "Bu — Aziz, id 1"

Nimaga qarang: Telegram ma'lumotni sahifaga beradi, serverga emas. Serverga uni sahifaning o'zi yuboradi — shuning uchun server unga ko'r-ko'rona ishonmaydi.

Bular — ishga tushirish parametrlari (launch params): foydalanuvchi ma'lumoti, Telegram versiyasi, platforma va tema ranglari. # dan keyingi qism serverga yuborilmaydi — faqat brauzer ko'radi (location va hash).

Ularni qo'lda o'qish shart emas — buni SDK qiladi. Lekin bir marta ichiga qarash foydali:

js
// Telegram yasaydigan hash'ning namunasi (soxta ma'lumot)
const data = new URLSearchParams({
  user: JSON.stringify({ id: 1, first_name: "Aziz" }),
  auth_date: "1760000000",
  hash: "soxta",
}).toString();
const hash =
  "#" +
  new URLSearchParams({
    tgWebAppData: data,
    tgWebAppVersion: "8.0",
    tgWebAppPlatform: "android",
  });

// Sahifa tomoni: o'qish
const launch = new URLSearchParams(hash.slice(1));
const initData = launch.get("tgWebAppData");
console.log(initData);
const user = JSON.parse(new URLSearchParams(initData).get("user"));
console.log(user.first_name, launch.get("tgWebAppPlatform"));

Konsolda:

text
user=%7B%22id%22%3A1%2C%22first_name%22%3A%22Aziz%22%7D&auth_date=1760000000&hash=soxta
Aziz android

Birinchi qator — initData: so'rov qatori ko'rinishidagi xom satr. Ichida user (JSON), auth_date (ochilgan vaqt) va hash — Telegram'ning imzosi. Bu satrni serverga o'zgartirmasdan yuborasiz — server imzoni tekshiradi (keyingi dars).

3. SDK va soxta muhit

3.1 telegram-web-app.js

Telegram'ning rasmiy SDK'si — bitta skript. U <head> da, ilova kodidan oldin ulanadi:

html
<script src="https://telegram.org/js/telegram-web-app.js"></script>

U hash'ni o'qiydi, window.Telegram.WebApp obyektini yaratadi va tema ranglarini CSS o'zgaruvchilari qilib yozadi. Ilova tayyor bo'lgach Telegram.WebApp.ready() chaqiriladi — Telegram yuklanish ko'rsatkichini olib tashlaydi.

CSP'da bu — tashqi skript: script-src 'self' https://telegram.org. vazifalar kabi Trusted Types yoqilgan ilovada skript <script> tegi bilan HTML'da ulanadi (JS'dan emas) — shuning uchun TT unga to'sqinlik qilmaydi. Muqobili — skriptni npm paket ichida olib keladigan kutubxonalar («SDK kutubxonalari» bo'limida).

3.2 Natija oynasida Telegram yo'q

Natija oynasi — oddiy brauzer, Telegram emas: window.Telegram yo'q. Telegram'dan tashqarida rivojlantirish uchun soxta muhit (mock) yasaladi — SDK obyektining o'zimiz yozgan o'rinbosari. Rasmiy hujjat ham, SDK kutubxonalari ham shunday maslahat beradi (@tma.js/sdk da tayyor mockTelegramEnv bor).

Bizning mock — kerakli qismlari bilan (o'quv modeli). Keyingi bloklar davomi — shu kodni davom ettiradi:

jsx
// Soxta Telegram muhiti (o'quv modeli). Haqiqiysi —
// telegram-web-app.js. Bu kod faqat natija oynasi uchun.
import { useSyncExternalStore } from "react";

const bus = {}; // hodisa nomi → ishlovchilar
const frame = new Set(); // Telegram "ramkasi" tinglovchilari
let version = 0;
function notify() {
  version += 1;
  for (const l of frame) l();
}
function emit(name) {
  for (const cb of bus[name] ?? []) cb();
}
function onEvent(name, cb) {
  (bus[name] ??= new Set()).add(cb);
}
function offEvent(name, cb) {
  bus[name]?.delete(cb);
}
function makeButton(event) {
  return {
    text: "",
    isVisible: false,
    setText(t) { this.text = t; notify(); return this; },
    show() { this.isVisible = true; notify(); return this; },
    hide() { this.isVisible = false; notify(); return this; },
    onClick(cb) { onEvent(event, cb); return this; },
    offClick(cb) { offEvent(event, cb); return this; },
  };
}

const THEMES = {
  dark: { bg_color: "#17212b", text_color: "#f5f5f5",
    button_color: "#5288c1", button_text_color: "#ffffff" },
  light: { bg_color: "#ffffff", text_color: "#000000",
    button_color: "#2481cc", button_text_color: "#ffffff" },
};
function applyTheme(scheme) {
  tg.colorScheme = scheme;
  tg.themeParams = THEMES[scheme];
  for (const [key, value] of Object.entries(tg.themeParams)) {
    const name = `--tg-theme-${key.replaceAll("_", "-")}`;
    document.documentElement.style.setProperty(name, value);
  }
  emit("themeChanged");
}

const user = { id: 1, first_name: "Aziz", language_code: "uz" };
const tg = {
  initData: new URLSearchParams({
    user: JSON.stringify(user),
    auth_date: "1760000000",
    hash: "soxta",
  }).toString(),
  initDataUnsafe: { user, auth_date: 1760000000, hash: "soxta" },
  platform: "android",
  version: "8.0",
  ready() { console.log("tg: ready"); },
  onEvent,
  offEvent,
  MainButton: makeButton("mainButtonClicked"),
  BackButton: makeButton("backButtonClicked"),
  HapticFeedback: {
    impactOccurred: (s) => console.log("tebranish:", s),
    notificationOccurred: (t) => console.log("tebranish:", t),
  },
};
window.Telegram = { WebApp: tg };
applyTheme("dark");

// Telegram'ning o'z tugmalari — natija oynasida chiziladi
function TelegramFrame({ children }) {
  useSyncExternalStore(
    (l) => { frame.add(l); return () => frame.delete(l); },
    () => version,
  );
  const { MainButton: main, BackButton: back } = tg;
  return (
    <>
      {back.isVisible && (
        <button onClick={() => emit("backButtonClicked")}>
          ‹ Orqaga
        </button>
      )}
      <div>{children}</div>
      {main.isVisible && (
        <div>
          <button onClick={() => emit("mainButtonClicked")}>
            {main.text}
          </button>
        </div>
      )}
    </>
  );
}

// --- Ilova kodi shu yerdan boshlanadi ---
const WebApp = window.Telegram.WebApp;
WebApp.ready();

function App() {
  const name = WebApp.initDataUnsafe.user?.first_name ?? "mehmon";
  return (
    <TelegramFrame>
      <h3>Salom, {name}!</h3>
      <p>Platforma: {WebApp.platform}</p>
    </TelegramFrame>
  );
}

Konsolda:

text
tg: ready

Ekranda:

text
Salom, Aziz!
Platforma: android

Mock'ning ikki qismi bor. Yuqorisi — window.Telegram.WebApp ning o'rinbosari: haqiqiy SDK'dagi nomlar bilan (initDataUnsafe, MainButton.setText, onEvent). TelegramFrame esa Telegram ilovasining o'zi chizadigan narsalarni (pastki ko'k tugma, tepadagi "orqaga" strelkasi) natija oynasida oddiy tugma qilib ko'rsatadi. Haqiqiy Mini App'da TelegramFrame bo'lmaydi.

«Ilova kodi shu yerdan boshlanadi» chizig'idan pasti — haqiqiy Mini App'dagi bilan bir xil. Mock o'rniga telegram-web-app.js qo'yilsa, o'zgarmasdan ishlaydi.

Tekshirib ko'ring: Mini App'ni oddiy brauzerda (Telegram'siz) ochsangiz, WebApp.initDataUnsafe.user nima bo'ladi? Kod nega ?. va ?? "mehmon" bilan yozilgan?

Javob

telegram-web-app.js Telegram'dan tashqarida ham WebApp obyektini yaratadi, lekin hash bo'sh — initDataUnsafe bo'sh obyekt, user yo'q (undefined). ?. — xato o'rniga undefined, ?? — zaxira matn. Mini App'ni har kim oddiy brauzerda ochishi mumkin: kod bunga tayyor bo'lsin.

4. initData va initDataUnsafe

4.1 Nega "unsafe"

Ikkalasi ham bir xil ma'lumot:

initData initDataUnsafe
Ko'rinishi xom satr: user=%7B…&auth_date=…&hash=… obyekt: { user: { first_name: "Aziz" }, … }
Kim uchun server — imzoni tekshiradi brauzer — ko'rsatish uchun
Ishonch tekshirilgandan keyin — ha yo'q

"Unsafe" (xavfsiz emas) — ma'lumot yomon degani emas, tekshirilmagan degani. Sahifa uni hash'dan oladi, hash'ni esa har kim yozishi mumkin: Mini App manzilini oddiy brauzerda #tgWebAppData=user%3D…"first_name":"Admin"… bilan ochish — bir daqiqalik ish. «Hujumchi nigohi» da batafsil.

Qoida: initDataUnsafe dan ism ko'rsatish — mumkin. Uning user.id si bilan buyurtma yozish, ball berish, ruxsat tekshirish — yo'q. Buning uchun initData serverga ketadi va server Telegram imzosini tekshiradi (Mini Apps II).

4.2 Foydalanuvchi maydonlari

initDataUnsafe.user da (hujjat bo'yicha): id, first_name, ixtiyoriy last_name, username, language_code (Telegram interfeysi tili), is_premium, photo_url, allows_write_to_pm. Telefon raqami yo'q — uni so'rash uchun alohida ruxsat oynasi bor (requestContact).

language_code — interfeys tilini tanlash uchun yaxshi boshlang'ich taxmin: i18n darsidagi kabi, foydalanuvchi o'zi tanlagan til ustun bo'lsin.

5. Tema: Telegram ranglari

5.1 themeParams va CSS o'zgaruvchilari

Telegram'da yorug' va qorong'i tema, foydalanuvchining o'z ranglari bor. Mini App oq fonda "yarqirab" turmasligi uchun Telegram ranglarni beradi:

  • WebApp.themeParams — obyekt: bg_color, text_color, hint_color, link_color, button_color, button_text_color, secondary_bg_color, section_bg_color, accent_text_color, destructive_text_color va boshqalar (#RRGGBB).
  • Bir xil qiymatlar — CSS o'zgaruvchilari sifatida <html> da: --tg-theme-bg-color, --tg-theme-button-color… SDK ularni o'zi yozadi (CSS o'zgaruvchilar).
  • WebApp.colorScheme — "light" yoki "dark".

CSS'da ishlatish — zaxira qiymat bilan (Telegram'dan tashqarida o'zgaruvchi bo'lmaydi):

css
body {
  background: var(--tg-theme-bg-color, #ffffff);
  color: var(--tg-theme-text-color, #1f2937);
}
.tugma {
  background: var(--tg-theme-button-color, #2481cc);
  color: var(--tg-theme-button-text-color, #ffffff);
}

5.2 Jonli: tema o'zgarganda

Foydalanuvchi Mini App ochiq turganda Telegram temasini almashtirishi mumkin. SDK themeChanged hodisasini chiqaradi:

jsx
import { useEffect, useState } from "react";

function useTelegramTheme() {
  const [scheme, setScheme] = useState(WebApp.colorScheme);
  useEffect(() => {
    const update = () => setScheme(WebApp.colorScheme);
    WebApp.onEvent("themeChanged", update);
    return () => WebApp.offEvent("themeChanged", update);
  }, []);
  return scheme;
}

function App() {
  const scheme = useTelegramTheme();
  const bg = document.documentElement.style.getPropertyValue(
    "--tg-theme-bg-color",
  );
  useEffect(() => {
    console.log(`tema: ${scheme}, fon: ${bg}`);
  }, [scheme, bg]);
  return (
    <section
      style={{
        background: "var(--tg-theme-bg-color, #fff)",
        color: "var(--tg-theme-text-color, #000)",
      }}
    >
      <p>Tema: {scheme === "dark" ? "qorong'i" : "yorug'"}</p>
      {/* natija oynasi uchun: Telegram sozlamasini taqlid qiladi */}
      <button onClick={() => applyTheme("light")}>
        Yorug' temani yoqish
      </button>
    </section>
  );
}

Konsolda:

text
tg: ready
tema: dark, fon: #17212b
tema: light, fon: #ffffff

(Birinchi qator — mock blokidagi WebApp.ready(): davomi bloki o'sha kod bilan bitta modul bo'lib ishlaydi. Keyingi bloklarda ham shunday.)

Ekranda:

text
Tema: yorug'
Yorug' temani yoqish
  • CSS o'zgaruvchilari o'zi yangilanadi — var(--tg-theme-bg-color) bilan bezalgan hamma narsa React'siz rangini almashtiradi.
  • React state esa faqat hodisa orqali biladi — JS'da tema nomi kerak bo'lsa (masalan, grafik ranglari yoki rasm tanlash uchun), themeChanged ga obuna bo'ling.
  • Cleanup — offEvent: komponent yo'qolsa, ishlovchi qolib ketmasin (cleanup).

Telegram sarlavha va fon rangini sahifangizga moslashtirishni ham taklif qiladi: WebApp.setHeaderColor("#17212b"), setBackgroundColor(…) — Mini App tepasidagi Telegram paneli bilan sahifa birlashib ketadi.

6. MainButton, BackButton va tebranish

6.1 Telegram'ning tugmalari

Mini App pastida Telegram'ning asosiy tugmasi (MainButton) chiqishi mumkin — katta, to'liq kenglikdagi, tema rangidagi tugma. Telegram foydalanuvchilari unga o'rgangan: "Buyurtma berish", "Davom etish", "To'lash". Uni Telegram chizadi — siz faqat matn va bosilganda nima bo'lishini berasiz. Tepada esa orqaga tugmasi (BackButton) — Telegram sarlavhasidagi ‹ strelka.

Nega o'z tugmangiz emas? Sahifa pastiga yopishgan o'z tugmangiz telefon klaviaturasi, "xavfsiz zona" va Telegram paneli bilan to'qnashadi. MainButton esa doim to'g'ri joyda va Telegram uslubida.

6.2 Hook: useMainButton

Tugma — tashqi tizim: React uni chizmaydi, faqat buyruq beradi. Demak bu — effekt va cleanup bilan:

jsx
function useMainButton(text, onClick) {
  useEffect(() => {
    const button = WebApp.MainButton;
    button.setText(text).show().onClick(onClick);
    return () => {
      button.offClick(onClick); // eski ishlovchi qolmasin!
      button.hide();
    };
  }, [text, onClick]);
}

Eng ko'p uchraydigan xato — offClick siz: har render'da yangi ishlovchi qo'shiladi va bitta bosishda funksiya 2, 3, 10 marta ishlaydi. Telegram ishlovchilarni o'zi almashtirmaydi — qo'shib boradi.

6.3 Jonli: menyu → savatcha → orqaga

Hamma qism birga: MainButton savatchada nechta taom borligini ko'rsatadi, bosilsa — savatcha sahifasi. U yerda BackButton chiqadi:

jsx
import { useCallback, useEffect, useState } from "react";

function useMainButton(text, onClick, visible) {
  useEffect(() => {
    if (!visible) return;
    const button = WebApp.MainButton;
    button.setText(text).show().onClick(onClick);
    return () => {
      button.offClick(onClick);
      button.hide();
    };
  }, [text, onClick, visible]);
}

function useBackButton(onClick, visible) {
  useEffect(() => {
    if (!visible) return;
    const button = WebApp.BackButton;
    button.show().onClick(onClick);
    return () => {
      button.offClick(onClick);
      button.hide();
    };
  }, [onClick, visible]);
}

function App() {
  const [cart, setCart] = useState([]);
  const [page, setPage] = useState("menu");
  const openCart = useCallback(() => {
    WebApp.HapticFeedback.impactOccurred("light");
    setPage("cart");
  }, []);
  const goBack = useCallback(() => setPage("menu"), []);

  useMainButton(
    `Savatcha (${cart.length})`,
    openCart,
    page === "menu" && cart.length > 0,
  );
  useBackButton(goBack, page === "cart");

  function add(name) {
    WebApp.HapticFeedback.notificationOccurred("success");
    setCart((c) => [...c, name]);
  }

  return (
    <TelegramFrame>
      {page === "menu" ? (
        <>
          <button onClick={() => add("Osh")}>+ Osh</button>{" "}
          <button onClick={() => add("Manti")}>+ Manti</button>
        </>
      ) : (
        <p>Savatchada: {cart.join(", ")}</p>
      )}
    </TelegramFrame>
  );
}

Konsolda:

text
tg: ready
tebranish: success
tebranish: success
tebranish: light

Ekranda:

text
+ Osh + Manti
Savatcha (2)

Qadamma-qadam:

Qadam Sahifa MainButton BackButton
boshida menyu yashirin (savatcha bo'sh) yashirin
«+ Osh», «+ Manti» menyu «Savatcha (2)» yashirin
«Savatcha (2)» savatcha yashirin «‹ Orqaga»
«‹ Orqaga» menyu «Savatcha (2)» yashirin
  • useCallback — openCart va goBack har render'da yangi funksiya bo'lmasin: aks holda effekt har safar offClick/onClick qiladi (ishlaydi, lekin ortiqcha). Matn o'zgarganda (Savatcha (1) → (2)) effekt baribir qayta ishlaydi — eski ishlovchi olinadi, yangisi qo'yiladi.
  • Tebranish — HapticFeedback: impactOccurred ("light", "medium", "heavy", "rigid", "soft") — jismoniy bosish hissi; notificationOccurred ("success", "warning", "error") — natija; selectionChanged() — tanlov o'zgardi. Kam ishlating: har bosishda tebranish — bezovta qiladi.
  • Haqiqiy routing bo'lsa (React Router), BackButton navigate(-1) ni chaqiradi va faqat ichki sahifalarda ko'rinadi (dasturiy navigatsiya).

MainButton ning yana foydali metodlari (hujjat bo'yicha): showProgress() / hideProgress() — tugmada aylanuvchi belgi (so'rov ketayotganda), enable() / disable(), setParams({ color, text_color, has_shine_effect }). Bot API 7.10 dan boshlab pastki panelda ikkinchi tugma ham bor — SecondaryButton (o'sha versiyada ikkala tugmaning umumiy turi BottomButton deb nomlandi).

Tekshirib ko'ring: useMainButton effektidan cleanup olib tashlandi. «+ Osh», «+ Manti», keyin «Savatcha (2)» bosildi. openCart necha marta chaqiriladi?

Javob

Uch marta: matn o'zgargan har safar (Savatcha (1), (2)) — va birinchi ko'rsatilishda — onClick(openCart) yana qo'shildi. Haqiqiy SDK'da ishlovchilar to'plamda bo'lsa, bir xil funksiya bir marta saqlanishi mumkin, lekin turli funksiyalar (useCallback'siz) — har biri alohida. Ikkala holatda ham tuzatish bitta: cleanup'da offClick.

7. Viewport va ekran

7.1 Balandlik

Mini App ko'pincha ekranning yarmida ochiladi, foydalanuvchi uni yuqoriga tortib kengaytiradi. 100vh bu yerda ishonchsiz: u Telegram oynasining hozirgi holatini bilmaydi. SDK beradi (hujjat bo'yicha):

  • WebApp.viewportHeight va CSS'da --tg-viewport-height — joriy ko'rinadigan balandlik (tortilayotganda o'zgaradi).
  • WebApp.viewportStableHeight va --tg-viewport-stable-height — tortish tugagandagi barqaror balandlik. Pastga yopishgan elementlar uchun shu.
  • WebApp.expand() — darhol to'liq balandlikka ochish; isExpanded — ochilganmi.
  • viewportChanged hodisasi — balandlik o'zgarganda.
css
.savatcha-panel {
  position: sticky;
  bottom: 0;
  /* Telegram'siz — oddiy 100dvh */
  max-height: var(--tg-viewport-stable-height, 100dvh);
}

Bot API 8.0 dan to'liq ekran rejimi va xavfsiz zona qo'shildi (requestFullscreen(), --tg-safe-area-inset-top …) — kamera teshigi va tizim paneli ostiga kontent tushmasligi uchun. Ular Mini Apps II da.

7.2 Versiya

Har Telegram ilovasi o'z versiyasida: eski Android'dagi Telegram yangi metodlarni bilmasligi mumkin. WebApp.version ("8.0") va WebApp.isVersionAtLeast("7.10") bilan tekshiriladi. Mavjud bo'lmagan metod chaqirilsa, SDK konsolga ogohlantirish yozadi va hech narsa qilmaydi — ilova yiqilmaydi, lekin funksiya ham ishlamaydi.

8. SDK kutubxonalari

8.1 Ikki yo'l

window.Telegram.WebApp — global obyekt, TypeScript turlarisiz, React hook'larsiz. Ikki mashhur kutubxona bor:

  • @twa-dev/sdk — rasmiy SDK'ning npm o'rami: import WebApp from "@twa-dev/sdk". Skript <head> da emas, bundle ichida keladi. Turlar bor.
  • @tma.js/sdk-react — jamoa (community) SDK'si: komponentlar (mainButton, backButton, themeParams) signallar bilan, retrieveLaunchParams(), mockTelegramEnv() (Telegram'dan tashqarida rivojlantirish uchun). Xaritada uning avvalgi nomi — @telegram-apps/sdk-react: paket bir necha bor qayta nomlangan. Kanon @tma.js/sdk-react 3.0.23 ni o'lchadi.

8.2 Biz sinab ko'rdik

Kanon tajribasida (tajriba/kutubxonalar/src/k/tma-sdk.tsx) — bot yo'q, mockTelegramEnv bilan (qatorlarga bo'lindi):

tsx
// #22 @tma.js/sdk-react 3.0.23 — Telegram tashqarisida:
// mockTelegramEnv (bot yo'q)
import {
  init,
  mockTelegramEnv,
  retrieveLaunchParams,
} from "@tma.js/sdk-react";

mockTelegramEnv({
  launchParams: {
    tgWebAppThemeParams: {
      bg_color: "#ffffff",
      text_color: "#000000",
    },
    tgWebAppData: new URLSearchParams([
      ["user", JSON.stringify({ id: 1, first_name: "Aziz" })],
      ["hash", "soxta"],
      ["auth_date", "1760000000"],
      ["signature", "soxta"],
    ]),
    tgWebAppVersion: "8.0",
    tgWebAppPlatform: "tdesktop",
  },
});
init();
// <p>{JSON.stringify(retrieveLaunchParams().tgWebAppPlatform)}</p>

Bu bizning mock'imiz bilan bir xil g'oya: launch params soxta beriladi, SDK ularni haqiqiy deb o'qiydi. Natija (kutubxonalar-21.txt):

text
tma-sdk                JS   77952 (+  10.0 KB) CSS      0 | CSP style-src-elem×1 | xato: Applying inline style violates the following Content Security Policy directive 'style-src 'self''. E | ochiq: tashqi yo'q
tma-twa                JS   80508 (+  12.5 KB) CSS      0 | CSP 0 | xato: yo'q | ochiq: tashqi yo'q
  • @tma.js/sdk-react +10.0 KB va CSP buzilishi: init() sahifaga o'z <style> tegini qo'shadi, vazifalar siyosati (style-src 'self') uni to'sadi. Ekranda matn chiqdi (TMA SDK "tdesktop") — ilova ishladi, lekin SDK qo'shmoqchi bo'lgan uslublar qo'llanmadi. Qat'iy CSP'li loyihada buni hujjatdan tekshirish yoki style-src ga nonce berish kerak.
  • @twa-dev/sdk +12.5 KB, CSP 0. Telegram'dan tashqarida WebApp.platform ekranda bo'sh chiqdi — hash yo'q, ma'lumot ham yo'q (shuning uchun mock kerak).

Ikkalasi ham tashqi serverga bormadi. Rasmiy skriptni <script src> bilan ulash esa bundle'ga 0 KB qo'shadi, lekin telegram.org dan yuklanadi — CSP'ga host qo'shiladi va har ochilishda tashqi so'rov.

8.3 Sinash va debug

  • Brauzerda, mock bilan — kundalik ishning 90% i. Tez, DevTools bor.
  • Haqiqiy Telegram'da — Telegram Desktop (sozlamalarda "webview inspecting" yoqilsa — DevTools), Android'da chrome://inspect (WebView debug), iOS'da Safari Web Inspector. Hujjatdagi "Debug Mode for Mini Apps" bo'limi.
  • HTTPS kerak — lokal Vite server'ni Telegram ochishi uchun tunnel (HTTPS manzil) yoki Telegram test serveri. Bular — Mini Apps II da.

8.4 Nega vazifalar da Mini App yo'q

Bot yaratilmadi — bu hisob va token degani, topshiriq bunga ruxsat bermaydi. Mini App foydalanuvchini tanishi uchun backend ham kerak (initData tekshiruvi). Kanon faqat SDK'larni o'lchadi. vazifalar ni Mini App qilish — 29-qismda bot backend'i bilan, capstone loyihalardan biri esa butunlay Mini App (Telegram Mini App capstone).

9. Hujumchi nigohi

1. Soxta foydalanuvchi. Hujumchi Mini App manzilingizni oddiy brauzerda ochadi va hash'ga o'z tgWebAppData sini yozadi: "id": 12345, "first_name": "Jasur aka". initDataUnsafe endi shuni ko'rsatadi. Agar ilova user.id ni serverga "men shu odamman" deb yuborsa va server ishonsa — hujumchi boshqa odamning buyurtmalarini ko'radi yoki uning nomidan buyurtma beradi.

Himoya: serverga initDataUnsafe.user.id emas, xom initData yuboriladi. Server hash ni bot tokeni bilan tekshiradi — hujumchi bot tokenini bilmaydi, demak to'g'ri imzo yasay olmaydi. Batafsil va kod bilan — keyingi darsda.

2. Tema qiymatlari. themeParams ham hash'dan keladi — hujumchi u yerga "bg_color": "red;background:url(…)" yozishi mumkin. CSS o'zgaruvchisi sifatida bu ko'pincha zararsiz (noto'g'ri rang e'tiborsiz qoladi). Lekin bu qiymatlarni innerHTML ga, style satriga birlashtirib yoki URL'ga qo'ymang — tashqi ma'lumot (XSS).

3. Havolalar. Mini App ichidan tashqi saytni ochish — WebApp.openLink(url) (tashqi brauzerda), Telegram havolasi — openTelegramLink. Manzil foydalanuvchi ma'lumotidan yasalsa — faqat https: va o'z ro'yxatingizdagi domenlar (ochiq yo'naltirish).

10. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Cannot read properties of undefined (reading 'WebApp') telegram-web-app.js ulanmagan yoki keyin ulangan <head> da, ilova skriptidan oldin; yoki @twa-dev/sdk
Telegram'da cheksiz yuklanish ready() chaqirilmagan ilova chizilgach WebApp.ready()
Bir bosishda ikki-uch buyurtma MainButton.onClick cleanup'siz effekt cleanup'ida offClick
Oq fon qorong'i Telegram'da ranglar qotirilgan var(--tg-theme-bg-color, …)
Pastki panel klaviatura ostida qoldi 100vh --tg-viewport-stable-height
Oddiy brauzerda yiqiladi initDataUnsafe.user.first_name ?. va zaxira qiymat
Applying inline style violates … 'style-src 'self'' SDK o'z <style> ini qo'shmoqda CSP nonce yoki SDK sozlamasi
Telegram manzilni ochmaydi http:// yoki localhost HTTPS manzil (tunnel) yoki test server

11. Mashqlar

Mashqlar kurs/mashqlar/21/22-telegram-mini-app/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.

1-mashq (oson): bo'sh joylarni to'ldiring

  • Telegram rasmiy SDK skripti yaratadigan obyekt: window.Telegram.
  • Server imzoni tekshirishi uchun yuboriladigan xom satr:
  • Asosiy tugma tema rangi uchun CSS o'zgaruvchisi: --tg-theme-
  • Ilova tayyor ekanini Telegram'ga aytadigan metod:
  • Tema almashganda chiqadigan hodisa:
Yechim

WebApp — telegram-web-app.js yaratadi. initData — xom satr, imzosi bilan; initDataUnsafe — o'sha ma'lumotning tekshirilmagan obyekt ko'rinishi. --tg-theme-button-color — themeParams.button_color ning CSS nomi (pastki chiziq — chiziqcha). ready() — yuklanish ko'rsatkichini olib tashlaydi. themeChanged — onEvent bilan tinglanadi.

2-mashq (o'rta): launch params'dan salomlashish

Hash satridan (Telegram yasaydigan ko'rinishda) foydalanuvchi va tilni o'qiydigan readLaunch(hash) funksiyasini yozing. U { name, lang, platform } qaytarsin:

  • name — first_name va bo'lsa last_name;
  • lang — language_code, faqat uz, ru, en dan biri, boshqasi yoki yo'q bo'lsa — uz;
  • hash bo'sh yoki buzuq bo'lsa (JSON.parse yiqilsa) — { name: "mehmon", lang: "uz", platform: "unknown" }.

Uchta hash bilan sinang: to'liq (Aziz Karimov, ru, ios), tilsiz (de), bo'sh satr.

Ishora: «Telegram sahifaga nima beradi» dagi URLSearchParams zanjiri; try/catch (xatolarni ushlash).

Yechim
js
const LANGS = ["uz", "ru", "en"];
const GUEST = { name: "mehmon", lang: "uz", platform: "unknown" };

function readLaunch(hash) {
  try {
    const launch = new URLSearchParams(hash.replace(/^#/, ""));
    const raw = launch.get("tgWebAppData") ?? "";
    const data = new URLSearchParams(raw);
    const user = JSON.parse(data.get("user"));
    const name = [user.first_name, user.last_name]
      .filter(Boolean)
      .join(" ");
    const lang = LANGS.includes(user.language_code)
      ? user.language_code
      : "uz";
    const platform = launch.get("tgWebAppPlatform") ?? "unknown";
    return { name, lang, platform };
  } catch {
    return GUEST;
  }
}

function makeHash(user, platform) {
  const data = new URLSearchParams({ user: JSON.stringify(user) });
  return "#" + new URLSearchParams({
    tgWebAppData: data.toString(),
    tgWebAppPlatform: platform,
  });
}

const full = { first_name: "Aziz", last_name: "Karimov",
  language_code: "ru" };
console.log(readLaunch(makeHash(full, "ios")));
console.log(readLaunch(makeHash(
  { first_name: "Malika", language_code: "de" }, "android")));
console.log(readLaunch(""));

Konsolda:

text
{ name: 'Aziz Karimov', lang: 'ru', platform: 'ios' }
{ name: 'Malika', lang: 'uz', platform: 'android' }
{ name: 'mehmon', lang: 'uz', platform: 'unknown' }

Bo'sh hash'da data.get("user") — null, JSON.parse(null) esa null qaytaradi va user.first_name TypeError beradi — catch uni ushlaydi. Til ro'yxat bilan cheklangan: tashqi qiymat (type guard g'oyasi).

3-mashq (qiyin): MainButton progress bilan

«Jonli: menyu → savatcha → orqaga» mock'ini davom ettiring (jsx davomi). Savatcha sahifasida MainButton matni — «Buyurtma berish». Bosilganda:

  • MainButton.showProgress() chaqirilsin (mock'ga qo'shing: konsolga tugma: progress), soxta server 200 ms dan keyin javob bersin;
  • javobdan keyin hideProgress() (tugma: tayyor), notificationOccurred("success") va sahifada «Buyurtma qabul qilindi!».

Ishora: mock'dagi makeButton qaytargan obyektga ikki metod qo'shish — WebApp.MainButton.showProgress = () => { …; return WebApp.MainButton; }.

Yechim
jsx
import { useCallback, useState } from "react";

WebApp.MainButton.showProgress = function () {
  console.log("tugma: progress");
  return this;
};
WebApp.MainButton.hideProgress = function () {
  console.log("tugma: tayyor");
  return this;
};

function sendOrder() {
  return new Promise((resolve) => setTimeout(resolve, 200));
}

function App() {
  const [cart, setCart] = useState([]);
  const [page, setPage] = useState("menu");
  const openCart = useCallback(() => setPage("cart"), []);
  const order = useCallback(async () => {
    WebApp.MainButton.showProgress();
    await sendOrder();
    WebApp.MainButton.hideProgress();
    WebApp.HapticFeedback.notificationOccurred("success");
    setPage("done");
  }, []);

  useMainButton(
    `Savatcha (${cart.length})`,
    openCart,
    page === "menu" && cart.length > 0,
  );
  useMainButton("Buyurtma berish", order, page === "cart");

  return (
    <TelegramFrame>
      {page === "menu" && (
        <button onClick={() => setCart((c) => [...c, "Osh"])}>
          + Osh
        </button>
      )}
      {page === "cart" && <p>Savatchada: {cart.join(", ")}</p>}
      {page === "done" && <p>Buyurtma qabul qilindi!</p>}
    </TelegramFrame>
  );
}

Konsolda:

text
tg: ready
tugma: progress
tugma: tayyor
tebranish: success

Ekranda:

text
Buyurtma qabul qilindi!

useMainButton — oldingi blokdan (davomi). Ikkita chaqiruv bitta tugmani boshqaradi: har sahifada faqat bittasi visible. Sahifa almashganda birinchisining cleanup'i tugmani yashiradi va ishlovchisini oladi, ikkinchisi o'z matnini qo'yadi. Haqiqiy SDK'da showProgress() tugmani o'chirib ham qo'yadi — ikkinchi bosish buyurtmani takrorlamaydi (idempotentlik ham baribir kerak).

4-mashq: tajriba qadami (ixtiyoriy)

vazifalar ga tegmang. Agar o'zingizning Telegram akkauntingizda bot yaratishga tayyor bo'lsangiz (bu ixtiyoriy va sizning qaroringiz): BotFather'da /newbot, keyin alohida papkada (kurs/tajriba/mini-app/) Vite + React loyiha, index.html ga telegram-web-app.js, darsdagi App (mock'siz). Lokal server'ni HTTPS tunnel bilan oching (Mini Apps II da batafsil) va bot menyu tugmasiga shu manzilni qo'ying. Tekshiring: ism, tema almashganda ranglar, MainButton, BackButton.

Yechim

Tekshiruv ro'yxati:

  • Telegram'da ochilganda ism va platforma (android, ios, tdesktop, weba) to'g'ri.
  • Telegram sozlamasida tema almashtirilsa — fon va matn rangi darhol o'zgaradi (CSS o'zgaruvchilari), «Tema: …» matni ham (themeChanged).
  • Savatchaga taom qo'shilganda pastda Telegram'ning ko'k tugmasi, savatchada — tepada ‹.
  • Telefon tebranishi (HapticFeedback) — Telegram Desktop'da sezilmaydi, telefonda bor.
  • Bot tokeni hech qayerga — kodga, .env ga, GitHub'ga — yozilmagan: Mini App frontend'iga token umuman kerak emas.

12. Real ishda

  • O'zbekistonda Telegram — asosiy kanal: restoranlar, do'konlar, kurslar, taksi va xizmatlar Mini App bilan "ilovasiz ilova" quradi. Mehmon hech narsa o'rnatmaydi.
  • Bir kod — ikki joy: ko'p jamoalar bitta React ilovani ham sayt, ham Mini App qiladi: WebApp.initData bo'lsa — Telegram rejimi (MainButton, tema), bo'lmasa — oddiy sayt.
  • Hajm muhim: Mini App ko'pincha mobil internetda, WebView'da ochiladi. Birinchi yuklash JS'i kichik bo'lsin (yuklanishni optimallashtirish).
  • Intervyu savollari: "initData va initDataUnsafe farqi?", "Mini App'da foydalanuvchini qanday tanib olasiz?", "Tema ranglarini qanday qo'llaysiz?", "MainButton ishlovchisini qanday tozalaysiz?", "Mini App'ni lokal qanday sinaysiz?".

Xulosa

  • Mini App — Telegram ichidagi WebView'da ochiladigan oddiy veb sahifa; bot va BotFather orqali (menyu tugmasi, inline tugma, t.me/<bot>/<ilova>), faqat HTTPS.
  • Telegram ma'lumotni manzil hash'ida beradi (tgWebAppData, versiya, platforma, tema); telegram-web-app.js uni window.Telegram.WebApp ga aylantiradi, ilova tayyor bo'lgach — ready().
  • initData — xom satr, serverga (imzo tekshiruvi); initDataUnsafe — faqat ko'rsatish uchun, unga ishonilmaydi.
  • Tema: themeParams, --tg-theme-* (zaxira qiymat bilan), themeChanged; viewport: --tg-viewport-stable-height, expand().
  • MainButton / BackButton — tashqi tizim: effekt + cleanup'da offClick; HapticFeedback — kam va o'rinli.
  • Kutubxonalar: @tma.js/sdk-react (+10.0 KB, o'z <style> i — CSP), @twa-dev/sdk (+12.5, CSP 0); Telegram'dan tashqarida — mock.

Keyingi dars: Telegram Mini Apps II: auth, to'lov va production — initData imzosini server qanday tekshiradi (HMAC, Node'da jonli), startapp havolalari, Telegram Stars bilan to'lov, CloudStorage, to'liq ekran va HTTPS tunnel.

Manbalar

  • Telegram: "Telegram Mini Apps" (WebApp, initData, ThemeParams, BottomButton, BackButton, HapticFeedback, viewport, "Debug Mode") — core.telegram.org/bots/webapps
  • Telegram Mini Apps platformasi (jamoa hujjati): "Launch Parameters", "Theming", @tma.js/sdk-react, mockTelegramEnv — docs.telegram-mini-apps.com
  • @twa-dev/sdk — github.com/twa-dev/sdk
  • Kanon: tajriba/kutubxonalar/src/k/tma-sdk.tsx, tma-twa.tsx, natijalar/tajriba/kutubxonalar-21.txt (2026-10-17)
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Telegram Mini Apps React'da: WebApp SDK, initData, tema, MainButton va BackButton — IlmHamroh