Cos'è Headless JS in React Native?

A differenza dell'esecuzione di primo piano, dove l'applicazione è visibile e interattiva, Headless JS gestisce le attività come processi separati che non dipendono dal principale thread UI. Questo è essenziale per le operazioni che devono continuare dopo che l'utente chiude l'applicazione o prima che lo si apre – come la sincronizzazione dei dati, l'elaborazione in tempo di cross-time

Casi di uso comune per JS senza testa

Capire quando usare Headless JS ti aiuta a decidere se si adatta al tuo progetto.

  • Sincronizzazione dei dati[[] – Caricare i log o scaricare nuovi contenuti quando l'applicazione è in background.
  • Gestione delle notifiche di alta qualità[[] – Esecuzione della logica personalizzata quando arriva una notifica (ad esempio, l'aggiornamento di un badge, la memorizzazione dei dati a livello locale) prima di mostrare l'avviso.
  • Aggiornamenti di localizzazione[] – Inquinamento delle coordinate GPS in background per la geofencing o il monitoraggio in tempo reale.
  • Attività basate sul tempo[[] – Eseguire un lavoro a intervalli programmati (come la pulizia quotidiana) anche se l'utente non ha aperto l'app.
  • Azioni rapide dalla schermata iniziale[] – Esecuzione di un breve funzionamento quando l'utente preme un'azione 3D Touch o widget.

JS non è progettato per i calcoli lunghi o pesanti – il sistema può uccidere il processo di sfondo se ci vuole troppo tempo. Per un lungo lavoro di sfondo, combinarlo con i servizi nativi come WorkManager (Android) o BackgroundTasks (iOS).

Impostazione di JS senza testa in React Native: Step-by-Step

Implementing Headless JS coinvolge due parti principali: creare un gestore JavaScript e registrarlo nel codice nativo per ogni piattaforma.

1. Creare il JavaScript Background Handler

Inizia creando un nuovo file, ad esempio ]. Questo file conterrà la funzione che viene eseguita quando viene attivata l'attività di sfondo. La funzione riceve un oggetto , che può contenere i parametri passati dal lato nativo.

// BackgroundTask.js
import { AppRegistry } from 'react-native';

const backgroundTask = async (taskData) => {
 console.log('Background task started with data:', taskData);
 // Your background logic goes here
 // For example, fetch new data from an API
 try {
 const response = await fetch('https://api.example.com/sync');
 const data = await response.json();
 // Store data in AsyncStorage or a local database
 console.log('Background sync complete');
 } catch (error) {
 console.error('Background task failed:', error);
 // Optionally throw an error to let the system know
 }
};

AppRegistry.registerHeadlessTask('BackgroundTask', () => backgroundTask);

Nota che il gestore deve essere una funzione che restituisce una promessa (o una funzione asincrona). Il sistema aspetterà che la Promessa si risolva prima di considerare l'attività completa. Se il Promise rifiuta, il lato nativo può trattarla come un fallimento.

2. Registrare il compito nel codice nativo Android

Android richiede di registrare il compito senza testa nel vostro (o a seconda della versione React Native). Inoltre, è necessario un HeadlessJsTaskService per gestire il ciclo di vita dell'attività.

Step A – Aggiornamento MainApplication.java[

// android/app/src/main/java/com/yourapp/MainApplication.java
import com.facebook.react.HeadlessJsTaskService;

public class MainApplication extends Application implements ReactApplication {
 // ... existing code

 @Override
 public void onCreate() {
 super.onCreate();
 // Initialize ReactNative instance as usual
 // The task will be registered via AppRegistry in JavaScript
 }
}

Non è necessaria alcuna registrazione esplicita in Java per l'attività stessa se si utilizza [ – React Native mappa automaticamente il gestore JavaScript in un'attività nativa.

Step B – Creare un servizio HeadlessJsTask[]

Creare una nuova classe Java nello stesso pacchetto:

// android/app/src/main/java/com/yourapp/BackgroundTaskService.java
package com.yourapp;

import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;

public class BackgroundTaskService extends HeadlessJsTaskService {
 @Override
 protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
 Bundle extras = intent.getExtras();
 if (extras != null) {
 return new HeadlessJsTaskConfig(
 "BackgroundTask",
 Arguments.fromBundle(extras),
 5000, // timeout in ms
 true // allows task to run in foreground as well
 );
 }
 return null;
 }
}

Questo servizio estrae qualsiasi extra dall'Intent (come i dati da una notifica) e li passa al gestore JavaScript.

Step C – Aggiungi il servizio ad AndroidManifest.xml

<service android:name=".BackgroundTaskService" />

Ora qualsiasi modulo nativo può avviare questo servizio utilizzando un Intent, o è possibile utilizzare un ricevitore di trasmissione per attivarlo da una notifica push.

3. Impostare le capacità di sfondo iOS

Per usare Headless JS su iOS, è necessario attivare le modalità di sfondo appropriate e utilizzare la pianificazione nativa (come le notifiche push o il fetch di sfondo).

Step A – Attivare modalità di sfondo[

Apri il tuo progetto Xcode, vai a []Signing & Capabilities[], e aggiungi la [Modalità di sfondo[] capacità.

Step B – Implement App Delegate Methods

In , implementare i metodi del delegato necessari per ricevere eventi di sfondo e avviare il compito senza testa.

// AppDelegate.m (Objective-C)
#import <React/RCTAppDelegate.h>
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>

@implementation AppDelegate

- (void)application:(UIApplication *)application
 performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
 // You can get the bridge from your ReactNative root view
 RCTBridge *bridge = [self.rootView bridge];
 [bridge.eventDispatcher sendAppEventWithName:@"BackgroundFetch"
 body:@{@"taskName": @"BackgroundTask"}];
 completionHandler(UIBackgroundFetchResultNewData);
}

@end

Sul lato JavaScript, è necessario ascoltare l'evento e quindi avviare l'attività senza testa manualmente. Tuttavia, Headless JS su iOS è più comunemente usato insieme con le notifiche push – quando arriva una notifica, è possibile eseguire il codice senza testa prima di mostrare l'avviso.

Per le notifiche push, implementa in AppDelegate e invia un evento a React Native.

Triggering compiti di sfondo

Una volta configurato, è possibile attivare un'attività JS senza testa da varie fonti:

  • Notifiche di Pissure[[] (Android & iOS) – Utilizzare un ricevitore di trasmissione personalizzato su Android o il delegato dell'app su iOS per avviare il servizio quando arriva una notifica silenziosa.
  • Moduli di carattere[[] – Creare un modulo nativo che chiama [ su Android o posta una notifica su iOS.
  • Background fetch[[] (iOS) – iOS chiama periodicamente la tua app delegata; puoi usare questa opportunità per sparare l'attività senza testa.
  • Arme [] – Usa o []] per programmare l'esecuzione periodica.

Esempio: Avviare il servizio Android da un ricevitore di trasmissione che ascolta per un'azione personalizzata:

public class AlarmReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
 Intent serviceIntent = new Intent(context, BackgroundTaskService.class);
 serviceIntent.putExtra("source", "alarm");
 context.startService(serviceIntent);
 }
}

Quindi registrare il ricevitore in AndroidManifest.xml e programmare un allarme utilizzando .

Migliori Pratiche per l'operazione di sfondo affidabile

I compiti di sfondo sono intrinsecamente fragili – il sistema operativo può uccidere il processo in qualsiasi momento. Seguire queste linee guida per rendere i vostri compiti JS Headless robusto:

  • Aggiungi i compiti brevi. Mirare per meno di 30 secondi di esecuzione. Utilizzare timeout (i 5000m nel nostro esempio) per evitare i compiti appesi.
  • Handle errori con grazia.[] Avvolgi la tua logica in prova / cattura. Se il compito fallisce, consideri l'accesso localmente utilizzando un reporter di crash (come Sentry) e non blocchi l'interfaccia utente.
  • Utilizzare modelli offline-first. Poiché le attività di sfondo spesso funzionano senza garanzie di rete, implementare retries e memorizzare operazioni fallite per più tardi.
  • Avoid heavy state management. Non affidatevi allo stato Redux o React – le attività di sfondo vengono eseguite in un contesto JavaScript separato.
  • Test su dispositivi reali.[] L'emulatore Android e il simulatore iOS si comportano in modo diverso dall'hardware fisico.
  • ottimizzazione della batteria di rispetto. Usa ] con un blocco di sveglia su Android per impedire alla CPU di dormire, ma rilascia immediatamente la serratura. Su iOS, gli intervalli di fetch di sfondo sono gestiti dal sistema – rispettano il tempo concesso.

Debug JS senza testa

Debugging codice di sfondo è difficile perché non è possibile utilizzare l'ispettore Chrome DevTools quando l'interfaccia utente non è attiva.

  • Logcat[] (Android) – Aggiungi [] dichiarazioni; appaiono in logcat con il tag “ReactNativeJS”.
  • log file locali[[] – Scrivere le voci di registro in un file sul dispositivo e recuperarle più tardi.
  • Flipper[ – React Native Flipper può catturare i log delle console da attività senza testa (assicurare di impostare [ per essere vero nel vostro plugin Flipper).
  • Native logging[ – Usa nel tuo servizio Java per tracciare quando l'attività inizia e termina.

Limitazioni e considerazioni

Headless JS non è un proiettile d'argento. Capire i suoi limiti per evitare sorprese:

  • Nessuna interazione UI. Non è possibile visualizzare le visualizzazioni o mostrare avvisi all'interno di un'attività senza testa.
  • L'attività principale del React Native è una sola attività JavaScript alla volta. Se avete bisogno di più operazioni di sfondo parallelo, considerate l'utilizzo di servizi nativi (WorkManager su Android, BGTaskScheduler su iOS).
  • iOS restrizioni.[] iOS fortemente accelera l'esecuzione di sfondo. Headless JS su iOS è solo affidabile per brevi compiti attivati da notifiche push o fetch di sfondo – il sistema può ritardare o impedire l'esecuzione se l'utente forza-quits l'applicazione.
  • Nessun negozio Redux. Come accennato in precedenza, il contesto JavaScript senza testa non condivide lo stesso negozio Redux come app di primo piano.
  • Risposta dell'app.] Se la forza utente chiude la tua app su Android 12+ o iOS, le attività di sfondo non possono essere eseguite finché l'utente non apre nuovamente l'app.

Confronto con altre biblioteche di sfondo

Il JS Headless di React Native è il meccanismo integrato di livello più basso, per molti casi di utilizzo, i pacchetti comunitari offrono un'API più conveniente:

LibraryPlatformFeatures
react-native-background-fetchAndroid & iOSPeriodic background fetching with system‑managed scheduling; supports Headless JS internally.
react-native-background-actionsAndroid & iOSRuns a long‑running foreground service (with persistent notification) – can execute heavy tasks.
WorkManager (Android only via native bridge)AndroidDeferrable, reliable background work with constraints (network, battery); does not use Headless JS by default.
Headless JS (vanilla)Android & iOSSimple, built‑in, no extra dependencies; best for short tasks triggered by push or alarms.

Se il vostro compito deve funzionare anche dopo un riavvio, o avete bisogno di pianificazione complessa, considerare l'imballaggio di un'implementazione nativa WorkManager e la espone tramite un modulo nativo React.

Esempio completo: sincronizzazione dei dati sulla notifica push

Mettiamo tutto insieme a uno scenario realistico: quando una notifica di spinta silenziosa arriva su Android, l'applicazione scarica i dati più recenti da un'API e lo memorizza localmente. L'utente non vede mai un cambiamento UI – i dati sono pronti quando apriranno l'app.

Android – Ricevitore di spinta

Creare un ricevitore di trasmissione che ascolta per l'azione push (ad esempio, da FCM):

public class PushReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
 Intent serviceIntent = new Intent(context, BackgroundTaskService.class);
 serviceIntent.putExtra("action", "syncData");
 context.startService(serviceIntent);
 }
}

Registralo in AndroidManifest.xml con un filtro-intento per la tua azione push (o utilizzare FirebaseMessagingService ] per avviare il servizio direttamente).

JavaScript Handler

// BackgroundTask.js (expanded)
import { AppRegistry } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

const backgroundTask = async (taskData) => {
 const { action } = taskData;
 if (action === 'syncData') {
 try {
 const response = await fetch('https://api.example.com/latest-data');
 const json = await response.json();
 await AsyncStorage.setItem('cachedData', JSON.stringify(json));
 console.log('Data synced successfully');
 } catch (error) {
 // Write error to a local log
 const errorLog = await AsyncStorage.getItem('errorLog');
 const newLog = (errorLog ? errorLog + '\n' : '') + new Date().toISOString() + ': ' + error.message;
 await AsyncStorage.setItem('errorLog', newLog);
 }
 }
};

AppRegistry.registerHeadlessTask('BackgroundTask', () => backgroundTask);

Quando l'utente riapre l'app, il primo piano può leggere [] e aggiornare immediatamente l'interfaccia utente, creando una prima esperienza offline senza soluzione di continuità.

Prestazioni e impatto batteria

Le attività senza testa vengono eseguite nello stesso motore JavaScript dell'app principale, ma in un contesto separato. Ogni compito genera una nuova istanza JS senza testa, che consuma memoria e CPU.

  • Utilizzare il timeout più breve che ancora permette il lavoro di completare.
  • Non eseguire frequenti inquinamenti – preferiscono i trigger basati su push.
  • Su Android, chiama dal servizio dopo che l'attività termina (HeadlessJsTaskService lo fa automaticamente quando la Promise si risolve).
  • Combinare con API di supporto batteria come WorkManager per Android e BGTaskScheduler per iOS se avete bisogno di lavoro periodico.

Conclusioni

Headless JS è uno strumento potente nella cintura di sviluppo React Native per la gestione di brevi compiti di sfondo che devono eseguire indipendentemente dalla visibilità dell'app. Con l'impostazione di un gestore JavaScript e la connessione con i trigger di sfondo nativi – come notifiche push, allarmi o fetch di sfondo – è possibile costruire applicazioni schonsive e basate su dati che si sentono sempre aggiornati.

Per ulteriori informazioni, fare riferimento alla documentazione ufficiale React Native su []Headless JS (Android) e ]Headless JS (iOS). Verificare anche il ]react-native-background-fetch library per la gestione periodica delle attività.