mobile

OTA updates: cum livrezi mobile updates fără App Store review

OTA updates înlocuiesc bundle-ul JS al aplicației mobile fără review la magazin. Regulile App Store și Play Store, staged rollout și când să eviți OTA.

Cuprins

OTA updates (over-the-air updates) înseamnă livrarea unei versiuni noi a bundle-ului JavaScript sau Dart al unei aplicații mobile direct pe dispozitivul utilizatorului, fără re-submitere la App Store sau Play Store și fără că utilizatorul trebuie să apese „Actualizare" în magazin.

Tehnica este posibilă pentru că React Native, Expo și Flutter (prin Shorebird) separă codul interpretat (JS sau Dart) de codul nativ compilat. Codul nativ se schimbă rar și necesită un binar nou; codul care implementează logica de business se poate înlocui prin rețea. Înțelegerea acestei separări este esențială ca să știi ce poți livra prin OTA și ce nu.

Ce sunt OTA updates mai exact?

Un mecanism prin care aplicația ta mobile descarcă la pornire (sau în fundal) o versiune mai nouă a bundle-ului JavaScript sau Dart față de cea instalată cu ultima versiune din magazin. Dacă există o versiune nouă compatibilă cu release-ul curent, aplicația o descarcă, o stochează local și o aplică la următoarea pornire.

Cuvântul cheie este „compatibilă cu release-ul curent". Un OTA update nu poate schimba codul nativ compilat (modulele native, permisiunile declarate în AndroidManifest.xml sau Info.plist, dependențele native). Asta înseamnă că dacă adaugi o nouă librărie nativă sau ceri o permisiune nouă, trebuie oricum un binar nou trimis la magazin.

  • Expo Updates. Soluția oficială pentru proiecte Expo (React Native); integrată direct în managed workflow și disponibilă prin bare workflow. Bundles sunt găzduite pe serverele Expo sau self-hosted.
  • EAS Update. Serviciul Expo Application Services pentru OTA în producție, cu staged rollout, canale multiple și statistici de adoptare.
  • Shorebird. Soluție OTA pentru Flutter (și React Native); compilează Dart și livrează patch-uri native, nu bundle JS.

Cum funcționează tehnic: JS bundle, semnătură, rollback?

La pornire, aplicația face o cerere la serverul de update cu informații despre release-ul curent (versiunea de binar, canalul activ). Serverul răspunde cu metadatele ultimei versiuni de bundle disponibile pentru acel release. Dacă versiunea de pe server este mai nouă, aplicația descarcă bundle-ul, verifică semnătura criptografică și îl aplică la următoarea repornire.

Semnătura previne modificările neautorizate. Expo Updates folosește chei asimetrice: cheia privată semnează bundle-ul la build; cheia publică, inclusă în binar, verifică semnătura la descărcare. Un bundle semnat de altă cheie este respins. Fără acest mecanism, un server compromis ar putea livra cod arbitrar.

Rollback-ul funcționează în sens invers: marchezi versiunea curentă ca inactivă prin API sau dashboard. Expo, EAS Update și Shorebird permit rollback fără a publica un bundle nou; aplicațiile care au descărcat deja versiunea proastă revin la cea anterioară la next check.

Care sunt regulile App Store și Play Store?

App Store Rule 4.2 (Minimum Functionality) și 3.2.2 (Native Code Requirements) sunt limitele clare. Apple permite OTA updates pentru:

  • Reparații de bug-uri și patch-uri de securitate care nu schimbă comportamentul de bază.
  • Actualizări de conținut (texte, imagini, configurări) care nu adaugă funcționalitate nouă.

Apple interzice OTA updates care introduc funcționalitate nouă semnificativă, schimbă scopul aplicației, sau execută cod care nu a trecut prin review. Formularea din guidelines este deliberat vagă: Apple nu definește precis ce înseamnă „funcționalitate nouă", ceea ce înseamnă că decizia finală aparține reviewerilor la fiecare re-submitere. Aplicațiile din categorii sensibile (copii, aplicații financiare, aplicații medicale) au un prag mai strict.

Play Store este mai permisiv: nu există o interdicție explicită pentru OTA de JavaScript, iar Google nu a publicat restricții echivalente cu Rule 4.2. Totuși, Android 14 a introdus restricții noi pentru executarea de cod descărcat dinamic (dynamic code loading); verifică dacă implementarea ta respectă aceste reguli înainte de a extinde OTA pe versiunile noi de Android.

Cum poți face un rollout sigur: staged, monitoring, kill switch?

Un rollout brusc la 100% din utilizatori este cel mai rapid mod de a transforma un bug de logică într-un incident de producție cu mii de utilizatori afectați. Strategia standard are trei componente:

  • Staged percentages. Publici update-ul mai întâi la 5% din utilizatori, monitorizezi câteva ore, crești la 25%, monitorizezi din nou, apoi la 100%. EAS Update și Shorebird au staged rollout ca funcționalitate de bază. Dacă folosești un server de update self-hosted, implementezi aceeași logică la nivel de API (returnezi versiunea nouă doar pentru un procent din request-uri, pe baza unui hash stabil al device ID).
  • Monitoring de crash rate per versiune OTA. Fiecare versiune de bundle trebuie să aibă crash rate vizibil separat față de versiunile anterioare. Dacă crash rate-ul crește după un OTA update, îl detectezi în primele ore, nu din recenzii pe App Store. Integrează un tool precum Sentry sau Firebase Crashlytics și filtrează rapoartele după versiunea de bundle, nu doar după versiunea de binar.
  • Kill switch. Posibilitatea de a dezactiva un OTA update prin API sau dashboard fără a publica un bundle nou. Expo și EAS Update au această opțiune built-in. Pe un server self-hosted, un câmp simplu în baza de date care marchează versiunea ca inactivă este suficient; aplicația verifică flag-ul la fiecare check for updates și revine la versiunea anterioară dacă cea curentă este dezactivată.

Legătura cu canary deployment este directă: OTA cu staged rollout este canary deployment aplicat la nivel de bundle mobile, cu aceeași logică de risk reduction. Diferența față de canary pe server este că pe mobile nu poți forța toți utilizatorii să primească update-ul imediat; unii vor rula versiunea veche zile sau săptămâni.

Când să NU folosești OTA updates?

OTA nu este răspunsul corect în patru situații clare:

  • Când schimbarea implică cod nativ. Adaugi o cameră, biometrie, Bluetooth sau orice modul nativ? Nu poți face asta prin OTA. Trebuie un binar nou. Niciun mecanism de OTA JavaScript nu poate livra cod nativ compilat.
  • Când ai nevoie de adoptare garantată și imediată. Un patch critic de securitate care necesită că toți utilizatorii primesc update-ul în 24 de ore nu poate depinde de OTA. Utilizatorii care nu deschid aplicația nu vor primi niciodată bundle-ul. O versiune de binar cu force update este singura cale să garantezi adoptarea.
  • Când aplicația ta este în categorie sensibilă cu review strict. Aplicații pentru copii (Apple Kids Category), aplicații medicale de clasa IIa sau mai sus, sau aplicații de gaming cu mecanisme de tip loot box au un prag de interpretare mai restrictiv. Dacă reviewerul Apple a respins anterior o versiune din cauza OTA, tratează-l ca un semnal, nu ca o eroare ocazională.
  • Când blast radius-ul unui bug e mai mare decât beneficiul vitezei. Dacă aplicația ta procesează plăți, accesează date medicale sau controlează hardware fizic, un OTA greșit afectează direct integritatea datelor. Viteza de livrare nu justifică asumarea riscului. Procesul complet de review și testare pe un binar nou este prețul corect.

La crawlerra, decizia de a include OTA în arhitectura unui proiect mobil (serviciul S02) se ia la start, nu ca optimizare ulterioară. Întrebările cheie sunt aceleași ca în orice practică de site reliability engineering: cât de repede detectezi o regresie, ce procent din utilizatori poți expune unui bundle neconfirmat, și ce se întâmplă dacă update-ul e stricat. Fără observabilitate per versiune OTA (crash rate, ANR rate, session length), ai un mecanism de livrare fără capacitate de detectare a regresiei. Dacă OTA modifică payload-ul unui push, asigură-te că versiunile vechi de bundle gestionează corect payload-ul nou; mai multe în push notifications. Handlerul de deep linking din bundle-ul JS se poate actualiza prin OTA; o schemă de URL nouă necesită binar nou.

Întrebări frecvente

OTA updates merg și pe Flutter, nu doar pe React Native?

Da, prin Shorebird, care compilează Dart și livrează patch-uri native fără re-submitere la magazin. Expo Updates și CodePush lucrează la nivel de bundle JavaScript și nu merg pe Flutter (Dart compilat nativ). Shorebird este singura soluție matură de OTA pentru Flutter la momentul scrierii; API-ul ei de rollout este similar cu cel al Expo: staged percentages, rollback, monitoring de crash rate per versiune.

Pot livra o funcționalitate complet nouă prin OTA?

Nu fără să riști respingerea aplicației de pe App Store. Regula Apple 4.2 permite OTA doar pentru fix-uri de bug-uri și actualizări de conținut, nu pentru funcționalitate care schimbă comportamentul de bază al aplicației. Play Store este mai permisiv, dar comportamentul nou care solicită permisiuni suplimentare necesită oricum o versiune de binar nouă.

Ce se întâmplă dacă un OTA update strică aplicația?

Folosești kill switch-ul sau rollback-ul pentru a reveni la versiunea anterioară fără nicio acțiune din partea utilizatorului. Expo Updates, CodePush și Shorebird au toate rollback prin API sau CLI. Condiția este că ai monitorizare de crash rate per OTA version activă; fără ea, nu știi că update-ul e stricat decât din recenzii negative pe magazin.

OTA updates merg offline sau cu conexiune slabă?

Descărcarea bundle-ului necesită conexiune, dar aplicația rulează bundle-ul deja descărcat chiar și offline. Dacă utilizatorul nu a fost online de când ai publicat un OTA update, va rula versiunea veche. Acesta este motivul pentru care OTA nu înlocuiește o versiune de binar pentru schimbări critice de securitate: nu poți garanta că toți utilizatorii primesc update-ul imediat.

CodePush mai este întreținut în 2026?

Microsoft a anunțat retragerea CodePush din App Center la finalul lui 2024; alternativele active sunt Expo Updates (pentru proiecte Expo) și EAS Update sau expo-updates standalone pentru bare workflow. Dacă folosești CodePush în producție, planifică migrarea. Shorebird rămâne opțiunea pentru Flutter și pentru React Native când vrei patch-uri native, nu doar JS.