Mundarija (36)
- Bu darsda
- 1. Nega bu kerak?
- 2. Mini App qanday ochiladi
- 2.1 Kirish eshiklari
- 2.2 Telegram sahifaga nima beradi
- 3. SDK va soxta muhit
- 3.1 telegram-web-app.js
- 3.2 Natija oynasida Telegram yo'q
- 4. initData va initDataUnsafe
- 4.1 Nega "unsafe"
- 4.2 Foydalanuvchi maydonlari
- 5. Tema: Telegram ranglari
- 5.1 themeParams va CSS o'zgaruvchilari
- 5.2 Jonli: tema o'zgarganda
- 6. MainButton, BackButton va tebranish
- 6.1 Telegram'ning tugmalari
- 6.2 Hook: useMainButton
- 6.3 Jonli: menyu → savatcha → orqaga
- 7. Viewport va ekran
- 7.1 Balandlik
- 7.2 Versiya
- 8. SDK kutubxonalari
- 8.1 Ikki yo'l
- 8.2 Biz sinab ko'rdik
- 8.3 Sinash va debug
- 8.4 Nega vazifalar da Mini App yo'q
- 9. Hujumchi nigohi
- 10. Ko'p uchraydigan xatolar
- 11. Mashqlar
- 1-mashq (oson): bo'sh joylarni to'ldiring
- 2-mashq (o'rta): launch params'dan salomlashish
- 3-mashq (qiyin): MainButton progress bilan
- 4-mashq: tajriba qadami (ixtiyoriy)
- 12. Real ishda
- Xulosa
- Manbalar
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.jsorqaliwindow.Telegram.WebAppobyektini beradi: foydalanuvchi (initDataUnsafe.user), tema ranglari (themeParamsva--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. initDatavainitDataUnsafefarqini bilasiz va foydalanuvchi ismini ko'rsatasiz.- Interfeysni Telegram temasiga moslaysiz:
themeParams,--tg-theme-*,themeChanged. MainButton,BackButtonvaHapticFeedbackni 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:
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:
// 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:
user=%7B%22id%22%3A1%2C%22first_name%22%3A%22Aziz%22%7D&auth_date=1760000000&hash=soxta
Aziz androidBirinchi 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:
<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:
// 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:
tg: readyEkranda:
Salom, Aziz!
Platforma: androidMock'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.usernima 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_colorva 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):
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:
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:
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:
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),
themeChangedga 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:
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:
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:
tg: ready
tebranish: success
tebranish: success
tebranish: lightEkranda:
+ 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—openCartvagoBackhar render'da yangi funksiya bo'lmasin: aks holda effekt har safaroffClick/onClickqiladi (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),
BackButtonnavigate(-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:
useMainButtoneffektidan cleanup olib tashlandi. «+ Osh», «+ Manti», keyin «Savatcha (2)» bosildi.openCartnecha 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.viewportHeightva CSS'da--tg-viewport-height— joriy ko'rinadigan balandlik (tortilayotganda o'zgaradi).WebApp.viewportStableHeightva--tg-viewport-stable-height— tortish tugagandagi barqaror balandlik. Pastga yopishgan elementlar uchun shu.WebApp.expand()— darhol to'liq balandlikka ochish;isExpanded— ochilganmi.viewportChangedhodisasi — balandlik o'zgarganda.
.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-react3.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):
// #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):
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,vazifalarsiyosati (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 yokistyle-srcga nonce berish kerak.@twa-dev/sdk+12.5 KB, CSP 0. Telegram'dan tashqaridaWebApp.platformekranda 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_nameva bo'lsalast_name;lang—language_code, faqatuz,ru,endan biri, boshqasi yoki yo'q bo'lsa —uz;- hash bo'sh yoki buzuq bo'lsa (
JSON.parseyiqilsa) —{ 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
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:
{ 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: konsolgatugma: 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
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:
tg: ready
tugma: progress
tugma: tayyor
tebranish: successEkranda:
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,
.envga, 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.initDatabo'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: "
initDatavainitDataUnsafefarqi?", "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.jsuniwindow.Telegram.WebAppga 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'daoffClick;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)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!