Přeskočit na obsah
_CORE
AI & Agentic Systems Core Informační Systémy Cloud & Platform Engineering Data Platforma & Integrace Security & Compliance QA, Testing & Observability IoT, Automatizace & Robotika Mobile & Digital Banky & Finance Pojišťovnictví Veřejná správa Obrana & Bezpečnost Zdravotnictví Energetika & Utility Telco & Média Průmysl & Výroba Logistika & E-commerce Retail & Loyalty
Reference Technologie Blog Knowledge Base O nás Spolupráce Kariéra
Pojďme to probrat

Proč vaše mobilní aplikace nefunguje offline — a jak to napravit

05. 02. 2026 8 min čtení CORE SYSTEMSai

Uživatel otevře vaši aplikaci v metru, v letadle, na chatě bez signálu — a vidí spinner. Nebo prázdnou obrazovku. Nebo chybovou hlášku. V roce 2026 je tohle neakceptovatelné. Offline-first není luxus — je to základ dobré mobilní zkušenosti. A překvapivě, většina týmů to pořád dělá špatně.

Proč offline matters

Statistiky jsou jednoznačné: průměrný uživatel stráví 11 % času bez stabilního připojení k internetu. Ne proto, že by žil na vesnici — ale proto, že jezdí metrem, cestuje letadlem, prochází betonovými budovami s mizerným signálem. A v těch momentech vaše aplikace buď funguje, nebo ji uživatel nahradí jinou, která funguje.

Offline-first neznamená „aplikace nějak přežije bez internetu.” Znamená to, že lokální data jsou primární zdroj pravdy a síť je mechanismus synchronizace. Tohle je fundamentální architektonický posun — ne feature, kterou přilepíte na konec.

Pro business aplikace (field service, logistika, inspekce, retail) je offline podpora kritická. Technik v terénu musí zadat data, i když nemá signál. Řidič musí potvrdit doručení v podzemní garáži. Inspektor musí vyfotit závadu v suterénu. Pokud tohle vaše aplikace neumí, máte problém.

Service Workers: základ offline webu

Pro PWA a webové aplikace jsou Service Workers klíčová technologie. Service Worker je JavaScript soubor, který běží na pozadí v prohlížeči, nezávisle na hlavní stránce. Funguje jako proxy mezi aplikací a sítí — zachytává HTTP requesty a rozhoduje, jestli je obslouží z cache, ze sítě, nebo kombinací obojího.

`// sw.js — registrace Service Workeru

self.addEventListener(‘install’, (event) => {

event.waitUntil(

caches.open(‘app-shell-v2’).then((cache) => {

return cache.addAll([

’/’,

‘/css/app.css’,

‘/js/app.js’,

‘/offline.html’

]);

})

);

});

self.addEventListener(‘fetch’, (event) => {

event.respondWith(

caches.match(event.request)

.then((cached) => cached || fetch(event.request))

.catch(() => caches.match(‘/offline.html’))

);

});`

Klíčový koncept: Service Worker přežívá zavření tabu. Jednou nainstalovaný zůstává aktivní a může obsluhovat requesty, i když je uživatel offline. To je zásadní rozdíl oproti obyčejnému HTTP cachování — máte nad ním plnou programatickou kontrolu.

IndexedDB vs SQLite: kam ukládat offline data

Cache API řeší statické assety. Ale co dynamická data — objednávky, formuláře, produktové katalogy? Tady máte dvě hlavní volby.

IndexedDB

Nativní browser API. Asynchronní, transakční NoSQL databáze přímo v prohlížeči. Ideální pro PWA. Kapacita v řádu stovek MB. Přístup přes strukturované klíče a indexy.

SQLite (WASM / native)

Plnohodnotná SQL databáze. Pro nativní aplikace (React Native, Flutter, Swift, Kotlin) — přímý přístup. Pro web přes sql.js nebo OPFS. Silné v relačních datech a komplexních dotazech.

Kdy co použít? Pro PWA je IndexedDB přirozená volba — je v prohlížeči, nepotřebuje WASM runtime a má slušnou výkonnost pro většinu use cases. Pro nativní mobilní aplikace je SQLite jasná volba — je rychlejší, má lepší podpora pro transakce a komplexní dotazy, a je to de facto standard v mobilním světě.

`// IndexedDB — uložení offline záznamu

async function saveOfflineRecord(record) {

const db = await openDB(‘fieldwork’, 1, {

upgrade(db) {

const store = db.createObjectStore(‘inspections’, {

keyPath: ‘id’

});

store.createIndex(‘synced’, ‘synced’);

store.createIndex(‘timestamp’, ‘timestamp’);

}

});

await db.put(‘inspections’, {

…record,

id: crypto.randomUUID(),

synced: false,

timestamp: Date.now()

});

}`

Důležitý detail: nikdy nespoléhejte na localStorage pro offline data. Limit 5 MB, synchronní API (blokuje main thread) a žádná podpora pro indexy nebo transakce. localStorage je pro user preferences, ne pro business data.

Sync strategie: optimistic vs pessimistic

Nejsložitější část offline-first architektury není ukládání dat — je to jejich synchronizace zpět na server, když se připojení obnoví. Existují dva fundamentální přístupy.

Optimistic sync (offline-first)

Uživatel provede akci, aplikace ji okamžitě potvrdí a zápis do lokální databáze. Synchronizace proběhne na pozadí, jakmile je dostupná síť. Pokud vznikne konflikt, řeší se zpětně — buď automaticky (last-write-wins, merge), nebo s uživatelským potvrzením.

Výhody: okamžitá odezva, funguje bez sítě, lepší UX. Nevýhody: konflikty, eventual consistency, složitější error handling. Použití: field service aplikace, poznámky, formuláře, ToDo listy, chat.

Pessimistic sync (online-first)

Uživatel provede akci, aplikace čeká na potvrzení serveru a teprve pak aktualizuje UI. Offline queue ukládá operace pro pozdější odeslání, ale neprezentuje je jako potvrzené.

Výhody: konzistence, žádné konflikty, jednodušší implementace. Nevýhody: pomalejší UX, závislost na síti pro potvrzení. Použití: finanční transakce, objednávky, medicínské záznamy — cokoliv, kde eventual consistency není akceptovatelná.

`// Optimistic sync — offline queue s retry

class SyncManager {

async enqueue(operation) {

const queue = await this.getQueue();

queue.push({

id: crypto.randomUUID(),

operation,

timestamp: Date.now(),

retries: 0,

status: ‘pending’

});

await this.saveQueue(queue);

this.attemptSync();

}

async attemptSync() {

if (!navigator.onLine) return;

const queue = await this.getQueue();

for (const item of queue.filter(i => i.status === ‘pending’)) {

try {

await this.sendToServer(item.operation);

item.status = ‘synced’;

} catch (e) {

item.retries++;

if (item.retries >= 3) item.status = ‘failed’;

}

}

await this.saveQueue(queue);

}

}`

Background Sync API

Manuální polling a online/offline eventy jsou fragile. Background Sync API je browser API, které řeší synchronizaci elegantně: zaregistrujete sync event v Service Workeru a prohlížeč ho spustí, jakmile má stabilní připojení — i když uživatel aplikaci zavřel.

`// Registrace Background Sync z hlavní aplikace

async function scheduleSync() {

const registration = await navigator.serviceWorker.ready;

await registration.sync.register(‘sync-inspections’);

}

// Service Worker — obsluha sync eventu

self.addEventListener(‘sync’, (event) => {

if (event.tag === ‘sync-inspections’) {

event.waitUntil(syncPendingInspections());

}

});

async function syncPendingInspections() {

const db = await openDB(‘fieldwork’, 1);

const pending = await db.getAllFromIndex(

‘inspections’, ‘synced’, false

);

for (const record of pending) {

const res = await fetch(‘/api/inspections’, {

method: ‘POST’,

body: JSON.stringify(record)

});

if (res.ok) {

record.synced = true;

await db.put(‘inspections’, record);

}

}

}`

Důležité omezení: Background Sync API má zatím plnou podporu pouze v Chromium prohlížečích. Safari podpora je omezená. Pro nativní aplikace používejte platformní ekvivalenty — WorkManager (Android) nebo BGTaskScheduler (iOS).

Cache strategie

Výběr správné cache strategie zásadně ovlivňuje výkon i offline chování aplikace. Neexistuje jedna správná strategie — různý typ obsahu vyžaduje různý přístup.

  • Cache First: Vždy servíruj z cache, síť použij jen pro aktualizaci. Ideální pro statické assety (CSS, JS, fonty, ikony), které se mění jen při deployi.
  • Network First: Zkus síť, při selhání fallback na cache. Pro API data, kde chcete čerstvost, ale tolerujete stale data offline.
  • Stale-While-Revalidate: Okamžitě servíruj z cache a zároveň aktualizuj cache ze sítě na pozadí. Nejlepší kompromis mezi rychlostí a čerstvostí. Skvělé pro produktové katalogy, seznamy, profily.
  • Network Only: Žádné cachování. Pro data, která musí být vždy aktuální — autentizační tokeny, real-time ceny, transakce.
  • Cache Only: Pouze cache, žádná síť. Pro pre-cached assety aplikačního shellu, offline fallback stránky.

`// Stale-While-Revalidate v Service Workeru

self.addEventListener(‘fetch’, (event) => {

if (event.request.url.includes(‘/api/products’)) {

event.respondWith(

caches.open(‘api-cache’).then(async (cache) => {

const cached = await cache.match(event.request);

const fetchPromise = fetch(event.request).then((res) => {

cache.put(event.request, res.clone());

return res;

});

return cached || fetchPromise;

})

);

}

});`

V praxi kombinujete strategie podle typu obsahu. App shell je Cache First, API endpointy jsou Stale-While-Revalidate nebo Network First, a autentizace je Network Only. Klíčové je mít toto explicitně definované v architektonickém dokumentu, ne ad hoc v kódu.

Real-world architektura offline-first aplikace

Jak to celé skládáme dohromady? Typická architektura offline-first mobilní aplikace v produkci má tyto vrstvy:

  • UI Layer: React Native / Flutter / PWA. Čte data výhradně z lokální databáze. Nikdy přímo ze sítě.
  • Local Storage Layer: SQLite (native) nebo IndexedDB (web). Strukturovaná lokální databáze s indexy, transakcemi a migration support.
  • Sync Engine: Vlastní nebo knihovní (WatermelonDB, PouchDB, PowerSync). Řeší bidirectional sync, conflict resolution, retry logic a delta sync.
  • Network Layer: HTTP/REST nebo GraphQL s offline queue. Interceptor detekuje online/offline stav a routuje requesty.
  • Backend API: Serverová strana s podporou pro idempotentní operace, conflict detection (vector clocks, timestamps) a bulk sync endpointy.

Kritický detail, který většina týmů podcení: conflict resolution. Co se stane, když dva uživatelé editují stejný záznam offline? Last-write-wins je nejjednodušší, ale ne vždy správný. Pro komplexní scénáře potřebujete CRDT (Conflict-free Replicated Data Types) nebo field-level merge s uživatelským potvrzením.

Jak to stavíme v CORE SYSTEMS

V CORE SYSTEMS dodáváme offline-first mobilní aplikace pro field service, logistiku a inspekční procesy — tedy přesně ty scénáře, kde spolehlivý offline režim není nice-to-have, ale hard requirement.

Náš přístup začíná data flow analýzou: které entity musí být dostupné offline, jaký je expected objem dat, jaké operace se provádějí bez sítě a jaká je tolerance ke konfliktům. Na základě toho navrhujeme sync strategii — většinou kombinujeme optimistic sync pro vytváření nových záznamů s pessimistic přístupem pro editace kritických dat.

Technologicky sáhneme po React Native + WatermelonDB pro nativní aplikace nebo PWA + IndexedDB + Workbox pro webové řešení. Workbox od Googlu je production-grade knihovna pro Service Worker strategie — řeší precaching, runtime caching i Background Sync s minimem boilerplate kódu.

Každá offline-first aplikace, kterou dodáváme, má: sync status indikátor v UI (uživatel vždy ví, jestli je online/offline a kolik operací čeká na sync), conflict resolution UI pro edge cases, automated sync testing v CI/CD pipeline a monitoring dashboard pro sledování sync health v produkci.

Závěr: Offline-first je architektonické rozhodnutí

Offline podporu nemůžete přidat na konec vývojového cyklu. Je to architektonické rozhodnutí, které ovlivňuje datový model, sync logiku, UX flow i backend API design. Čím dříve ho uděláte, tím levněji vás vyjde.

Dobrá zpráva: v roce 2026 máme vyspělé nástroje — Service Workers, IndexedDB, Background Sync API, WatermelonDB, Workbox, PowerSync. Technologie není blokátor. Blokátor je architektonické myšlení, které stále předpokládá, že internet je vždy k dispozici. Není.