Guideline 2.5.4: mod de fundal respins de Apple
De Mehdi Azizi
Publicat pe , 9 min.
Apple respinge un mod de fundal declarat fără o funcție care să-l folosească. Scoate cheia sau arată-i reviewerului funcția.
Guideline 2.5.4 limitează modurile de fundal la utilizarea lor prevăzută: sunet, locație, apeluri VoIP, finalizarea sarcinilor, notificări locale. Respingerea vine când Info.plist-ul tău declară unul dintre aceste moduri și reviewerul nu găsește nicio funcție care să aibă nevoie de el. Scoate cheia dacă nimic nu o folosește, altfel arată-i reviewerului funcția în treizeci de secunde.
Îmi public propriile aplicații iOS cu Expo. Solys, alarma mea cu mini-jocuri, declară modul audio: l-am scos, apoi l-am pus la loc din alt motiv. Ghidul ăsta se bazează pe textul Apple, pe respingeri publicate de alți dezvoltatori și pe proiectele mele. Pentru imaginea de ansamblu a motivelor, citește de ce respinge Apple o aplicație.
Ce spune guideline 2.5.4?
Regula încape într-o frază, în secțiunea 2 „Performance”, partea 2.5 „Software Requirements”, din App Review Guidelines: „Multitasking apps may only use background services for their intended purposes: VoIP, audio playback, location, task completion, local notifications, etc.”
Pe scurt: un serviciu de fundal servește doar scopului pentru care există. De aici titlul „Guideline 2.5.4 - Performance - Software Requirements”.
Implicit, o aplicație trecută în fundal e suspendată. Ca să continue să ruleze, declară unul sau mai multe moduri în cheia UIBackgroundModes din Info.plist. Documentația Apple despre modurile de fundal cere să le folosești cu măsură, din cauza bateriei, și să preferi altă soluție când există. Fiecare mod declarat e o promisiune pe care reviewerul o poate verifica.
Modurile de fundal și utilizarea lor prevăzută
| Mod | Cheie | Utilizare prevăzută |
|---|---|---|
| Audio, AirPlay, PiP | audio | Sunet audibil în fundal |
| Locație | location | Locație continuă |
| Voce prin IP | voip | Apeluri cu CallKit |
| Preluare | fetch | Conținut de rețea regulat |
| Procesare | processing | Sarcini programate |
| Notificări la distanță | remote-notification | Push de conținut nou |
Tabelul rezumă pagina Apple. În respingerile publicate pe forumuri, audio, location și voip apar cel mai des.
Ce înseamnă mesajul de respingere 2.5.4?
Mesajul numește modul în cauză. Două exemple publicate de dezvoltatori pe forumurile Apple:
- Audio: „Your app still declares support for audio in the UIBackgroundModes key in your Info.plist but did not include features that require persistent audio.” Continuarea precizează că cheia
audioe făcută pentru aplicațiile care redau un conținut audibil în fundal, ca un player de muzică. Propune două ieșiri: adaugi acel conținut sau scoți cheia (firul de pe forum). - Locație: într-un fir din decembrie 2024, Apple n-a găsit nicio funcție în afară de urmărirea angajaților care să ceară locație permanentă și scrie că doar această utilizare nu e potrivită.
Cum o văd eu: reviewerul nu-ți citește codul, caută o funcție. Trebuie să o poată porni, să treacă aplicația în fundal și să constate că merge mai departe.
Există și cazul invers. Într-un fir din mai 2026, o aplicație de citire cu voce tare, care folosea cu adevărat modul audio, a fost respinsă de mai multe ori: reviewerul nu reușea să pornească sunetul. Alt dezvoltator scrie acolo că, după părerea lui, un video atașat i-a deblocat cazul. E o mărturie, nu o regulă Apple.
De unde vine cheia dacă n-ai adăugat-o tu?
Cu Expo, plugin-urile de configurare completează Info.plist la prebuild. Un mod de fundal poate deci intra în binarul tău fără să fi decis tu asta.
Plugin-ul expo-audio, cu setările implicite
Documentația expo-audio o spune: opțiunea enableBackgroundPlayback are implicit valoarea true și, pe iOS, adaugă modul audio. Să declari plugin-ul în forma scurtă, "expo-audio", e deci suficient ca să declari modul.
Asta am găsit recitind TradaZen înainte de prima trimitere: sunete scurte de interfață în prim-plan, dar un plugin declarat în forma scurtă. Corectura încape în app.json:
{
"expo": {
"plugins": [["expo-audio", { "enableBackgroundPlayback": false }]]
}
}
Alte pachete adaugă un mod în felul lor. Opțiunea isIosBackgroundLocationEnabled din expo-location adaugă location doar dacă o activezi. expo-background-task, în schimb, adaugă processing la prebuild imediat ce e instalat.
Folderul ios/ care păstrează cheia veche
A doua capcană, trăită pe Solys în iulie 2026. Scosesem audio din app.json, dar cheia rămânea în ios/Solys/Info.plist, generat mai devreme. Un prebuild fără --clean modifică proiectul ăsta în loc să-l recreeze, iar plugin-ul adaugă cheia fără s-o scoată vreodată. Un build local ar fi inclus-o. Un build EAS în cloud pornește de la un prebuild nou când ios/ e ignorat de git, cum era cazul meu.
Înainte de fiecare build, verific ce pleacă de fapt:
npx expo config --type introspect --json | grep -o '"UIBackgroundModes":\[[^]]*\]'
npx expo prebuild --clean --platform ios
Prima listează modurile pe care prebuild-ul le va scrie în Info.plist. A doua recreează proiectul nativ pentru un build local, ștergând folderul ios/. Pe Solys, prima afișează "UIBackgroundModes":["audio"], pe TradaZen nimic: ambele sunt intenționate.
Să adaugi sau să scoți un mod modifică Info.plist, deci binarul: ai nevoie de un build nou, un update la distanță nu ajunge. Documentația EAS Update pune aceste schimbări printre cele care cer un binar nou, ca la ITMS-90683.
Solys: un mod audio declarat, cu un motiv real
Solys e o alarmă, dar modul audio nu servește la sunatul alarmei: soneria trece prin AlarmKit, serviciul de alarmă Apple disponibil din iOS 26 (documentația AlarmKit). Sistemul sună, chiar și în modul silențios, nu aplicația.
Istoria cheii, pentru că raționamentul contează mai mult decât linia:
- La sfârșitul lui iulie 2026, o scot. Nimic nu reda sunet în fundal: efectele sonore ale mini-jocurilor rămân în prim-plan, iar alarma nu depinde de aplicație.
- Două zile mai târziu, o pun la loc, odată cu ascultarea nopții. Opțiunea asta înregistrează zgomotele din noaptea ta cu microfonul și le analizează pe iPhone. Înregistrarea trebuie să continue cu ecranul blocat, iar documentația expo-audio indică faptul că opțiunea de înregistrare în fundal adaugă și ea modul
audio.
Justificarea și-a schimbat natura: modul servește la înregistrat, nu la redat. Trei măsuri de siguranță, vizibile în aplicație:
- ascultarea e o opțiune dezactivată implicit, care se activează din setări sau din ritualul de seară;
- are propriul ecran de consimțământ, cum cere regula 2.5.14 pentru orice înregistrare, și nimic nu părăsește telefonul;
- microfonul se închide cu zece minute înainte de alarmă, ca ascultarea și soneria să nu se încurce niciodată.
Nu pot garanta că un reviewer va accepta mereu declarația asta. Știu să spun, pentru fiecare element, la ce servește și unde se vede.
Alarmele care țineau aplicația trează
Înainte de AlarmKit, o aplicație de alarmă terță nu putea suna ca alarma Apple. Unele biblioteci țineau deci aplicația trează: documentația pachetului Flutter alarm2 descrie un player audio silențios care rulează până la alarmă. Dar un sunet mut nu se aude. Din iOS 26, AlarmKit face ocolișul ăsta inutil.
Păstrezi sau scoți modul: grila de decizie
| Situația ta | Ce faci |
|---|---|
| Sunete scurte în prim-plan | Scoți audio |
| Muzică sau audiobook | Păstrezi, îl arăți |
| Înregistrare lungă | Păstrezi + consimțământ |
| Alarmă sau cronometru | AlarmKit (iOS 26) |
| Locație din când în când | Schimbări semnificative |
| Sincronizare fără urgență | fetch sau processing |
| Apeluri audio sau video | voip cu CallKit |
Pentru locație, pagina Apple citează serviciul de schimbări semnificative ca alternativă la modul location.
Celelalte alineate din 2.5: 2.5.1 și 2.5.2
2.5.1: API-uri publice și framework-uri la locul lor
„Apps may only use public APIs and must run on the currently shipping OS.” Aplicația folosește doar API-uri publice, rulează pe versiunea actuală a sistemului și renunță la ce e depreciat. Ca la 2.5.4, fiecare framework servește utilizării lui prevăzute, menționată în descriere: HealthKit pentru sănătate, HomeKit pentru casa inteligentă. Dacă o bibliotecă apelează un API privat, aplicația ta primește respingerea.
2.5.2: fără cod descărcat care schimbă aplicația
Aplicația rămâne autonomă în pachetul ei. Nu poate să „download, install, or execute code which introduces or changes features or functionality of the app”. Doar aplicațiile educaționale care învață programare au o excepție limitată, cu un cod complet vizibil și modificabil de utilizator.
Cu Expo, întrebarea atinge EAS Update, a cărui documentație amintește că update-urile trebuie să respecte regulile App Store. Păstrează update-urile la distanță pentru corecturi, niciodată pentru a livra o funcție pe care reviewerul n-a văzut-o. O corectură legată de review trece printr-un build nou, cum explic în ghidul despre guideline 2.1.
Cum răspunzi la o respingere 2.5.4?
Conversația are loc în secțiunea App Review a aplicației tale, unde răspunzi la mesajul App Review. Două cazuri:
- Modul nu servește la nimic: scoate-l, refă build-ul, verifică introspecția, apoi răspunde în două fraze.
- Modul servește o funcție reală: răspunde cu drumul exact și un video scurt, apoi pune textul ăsta în notele de review ale fiecărei versiuni.
Modelul pe care l-aș folosi, de adaptat (scoate fraza despre alarmă dacă aplicația ta nu are una):
Hello,
The "audio" background mode is used only by [feature], an
optional feature that [records / plays] audio while the
device is locked. It is off by default.
How to test:
1. Open [screen] and turn on [feature].
2. Accept the microphone permission if asked.
3. Tap [button], then lock the device.
[What the reviewer will hear or see.]
Our alarm does not use this mode: it is scheduled with
AlarmKit and rings through the system.
Attached: a short screen recording of these steps.
Best regards,
Checklist-ul 2.5.4 înainte de trimitere
- Introspecția Expo afișează doar modurile dorite și știi să numești funcția fiecăruia.
- Niciun plugin nu e declarat în forma scurtă dacă adaugă implicit un mod, ca expo-audio.
- Folderul tău
ios/local nu păstrează nicio cheie veche, sau compilezi dintr-un prebuild curat. - Funcția pornește repede, fără setare ascunsă, iar notele de review spun ce mod servește la ce și cum se testează.
- Orice înregistrare cere un consimțământ explicit și afișează un indicator vizibil. Regulile despre cererile de permisiune sunt în ghidul despre guideline 5.1.1.
- Pentru o alarmă, soneria trece prin AlarmKit, nu printr-un sunet redat din aplicație.
Verifică-ți dosarul înainte de trimitere
Review Kit adună checklist-ul meu dinainte de trimitere, modele de note pentru tester și skills Claude Code care îți recitesc proiectul. Pentru o privire umană, rezervă o oră cu mine: citim împreună mesajul Apple și Info.plist-ul tău, pe video. Demersul complet e pe pagina aplicație respinsă de Apple.
Îți pregătești prima lansare? Fă-ți diagnosticul gratuit: pune pașii în ordine și îți trimite checklist-ul meu anti-respingere Apple.
Nimeni nu poate garanta că Apple îți va accepta aplicația. Un mod de fundal bine justificat, în schimb, se apără în treizeci de secunde.
Întrebări frecvente
Ce înseamnă „Guideline 2.5.4 - Performance - Software Requirements”?
E titlul respingerii când Apple consideră că un mod de fundal din Info.plist-ul tău nu servește utilizării lui prevăzute. Mesajul numește modul și propune să arăți funcția care îl folosește sau să scoți cheia.
E nevoie de un build nou după o respingere 2.5.4?
Dacă scoți sau modifici un mod, da: cheia e în Info.plist, deci în binar. Dacă modul e justificat, un răspuns cu drumul exact și un video poate fi suficient.
Pot păstra modul audio pentru câteva sunete de interfață?
Nu. Sunetele scurte redate în prim-plan nu au nevoie de el. Cu Expo, setează enableBackgroundPlayback pe false în plugin-ul expo-audio.
O aplicație de alarmă are nevoie de modul audio?
Nu ca să sune, dacă se bazează pe AlarmKit, disponibil din iOS 26: sistemul redă alarma. Pe Solys, modul audio servește ascultării nopții, care înregistrează cu ecranul blocat.
De ce citează Apple 2.5.4 când eu n-am declarat nimic?
Poate un plugin a făcut-o în locul tău: expo-audio adaugă implicit modul audio, iar un folder ios/ vechi poate păstra o cheie scoasă din configurație. Verifică cu npx expo config --type introspect.

