Was ist Headless JS in React Native?

Headless JS ist eine integrierte React Native-Funktion, mit der Sie JavaScript-Code im Hintergrund ausführen können, auch wenn die Benutzeroberfläche der Anwendung nicht aktiv ist. Im Gegensatz zur Vordergrundausführung, bei der die App sichtbar und interaktiv ist, führt Headless JS Aufgaben als separate Prozesse aus, die nicht vom Haupt-Benutzeroberflächen-Thread abhängen. Dies ist wichtig für Operationen, die nach dem Schließen der App oder vor dem Öffnen der App fortgesetzt werden müssen - wie z. B. Synchronisieren von Daten, Verarbeiten eingehender Push-Benachrichtigungen oder Umgang mit zeitkritischen Warnungen. Headless JS schließt die Lücke zwischen React Native JavaScript-Laufzeit und den nativen Schichten von Android und iOS, so dass Sie plattformübergreifende Hintergrundlogik mit minimalem nativem Code schreiben können.

Häufige Anwendungsfälle für Headless JS

Wenn Sie verstehen, wann Sie Headless JS verwenden, können Sie entscheiden, ob es zu Ihrem Projekt passt.

  • Datensynchronisation – Hochladen von Protokollen oder Herunterladen neuer Inhalte, wenn sich die App im Hintergrund befindet.
  • Push-Benachrichtigungshandling – Durchführen benutzerdefinierter Logik, wenn eine Benachrichtigung eintrifft (z. B. Aktualisierung eines Abzeichens, lokale Speicherung von Daten), bevor die Warnung angezeigt wird.
  • Standort-Updates – Abfrage von GPS-Koordinaten im Hintergrund für Geofencing oder Echtzeit-Tracking.
  • Zeitbasierte Aufgaben – Ausführung eines Auftrags in einem geplanten Intervall (wie tägliche Bereinigung), auch wenn der Benutzer die App nicht geöffnet hat.
  • Schnelle Aktionen vom Startbildschirm – Führen Sie eine kurze Operation durch, wenn der Benutzer eine 3D-Touch- oder Widget-Aktion drückt.

Headless JS ist nicht für lang laufende oder schwere Berechnungen konzipiert – das System kann Ihren Hintergrundprozess beenden, wenn es zu lange dauert. Kombinieren Sie ihn für erweiterte Hintergrundarbeit mit nativen Diensten wie WorkManager (Android) oder BackgroundTasks (iOS).

Headless JS in React Native einrichten: Schritt für Schritt

Die Implementierung von Headless JS umfasst zwei Hauptteile: die Erstellung eines JavaScript-Handlers und die Registrierung im nativen Code für jede Plattform.

1. Erstellen Sie den JavaScript Background Handler

Beginnen Sie mit dem Erstellen einer neuen Datei, z. B. . Diese Datei enthält die Funktion, die ausgeführt wird, wenn die Hintergrundaufgabe ausgelöst wird. Die Funktion erhält ein -Objekt, das Parameter enthalten kann, die von der nativen Seite übergeben werden.

// 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);

Beachten Sie, dass der Handler eine Funktion sein muss, die ein Versprechen zurückgibt (oder eine async-Funktion), das System wartet, bis das Versprechen gelöst ist, bevor es die Aufgabe als abgeschlossen betrachtet.

2. Registrieren Sie die Aufgabe in Android Native Code

Android verlangt, dass Sie die Headless-Task in Ihrem (oder registrieren, abhängig von der React Native-Version.

Schritt A – Update 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
 }
}

Für die Aufgabe selbst ist keine explizite Registrierung in Java erforderlich, wenn Sie verwenden – React Native ordnet den JavaScript-Handler automatisch einer nativen Aufgabe zu.

Schritt B – Erstellen Sie einen HeadlessJsTaskService

Erstellen Sie eine neue Java-Klasse im selben Paket:

// 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;
 }
}

Dieser Dienst extrahiert alle Extras aus der Absicht (wie Daten aus einer Benachrichtigung) und leitet sie an den JavaScript-Handler weiter.

Schritt C – Fügen Sie den Dienst zu AndroidManifest.xml hinzu

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

Jetzt kann jedes native Modul diesen Dienst mit einer Absicht starten, oder Sie können einen Broadcast-Empfänger verwenden, um ihn über eine Push-Benachrichtigung auszulösen.

3. iOS-Hintergrundfunktionen einrichten

Um Headless JS unter iOS zu verwenden, müssen Sie geeignete Hintergrundmodi aktivieren und native Planung verwenden (wie Push-Benachrichtigungen oder Hintergrundabruf).

Schritt A – Aktivieren Sie Hintergrundmodi

Öffnen Sie Ihr Xcode-Projekt, gehen Sie zu Signing & Capabilities und fügen Sie die Background Modes-Fähigkeit hinzu. Überprüfen Sie die Modi, die Ihre App benötigt, z. B. “Background fetch” oder “Remote notifications”.

Schritt B – Implementieren von App Delegate Methods

Implementieren Sie in die erforderlichen Delegiertenmethoden, um Hintergrundereignisse zu empfangen und die kopflose Aufgabe zu starten.

// 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

Auf der JavaScript-Seite müssen Sie auf das Ereignis hören und dann die Headless-Task manuell starten. Headless JS wird jedoch häufiger zusammen mit Push-Benachrichtigungen verwendet - wenn eine Benachrichtigung eintrifft, können Sie Headless-Code ausführen, bevor Sie die Warnung anzeigen.

Für Push-Benachrichtigungen implementieren Sie in AppDelegate und senden Sie ein Ereignis an React Native.

Auslösen von Hintergrundaufgaben

Nach der Einrichtung können Sie eine Headless JS-Aufgabe aus verschiedenen Quellen auslösen:

  • Push-Benachrichtigungen (Android & amp; iOS) – Verwenden Sie einen benutzerdefinierten Broadcast-Empfänger auf Android oder den App-Delegierten auf iOS, um den Dienst zu starten, wenn eine stille Benachrichtigung eintrifft.
  • Native Module – Erstellen Sie ein natives Modul, das auf Android aufruft oder eine Benachrichtigung auf iOS veröffentlicht.
  • Hintergrund fetch (iOS) – iOS ruft Ihren App-Delegierten regelmäßig auf; Sie können diese Gelegenheit nutzen, um die kopflose Aufgabe auszulösen.
  • Alarms – Benutze oder , um die periodische Ausführung zu planen.

Beispiel: Starten des Android-Dienstes von einem Broadcast-Empfänger, der auf eine benutzerdefinierte Aktion hört:

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);
 }
}

Registrieren Sie dann den Empfänger in AndroidManifest.xml und planen Sie einen Alarm mit .

Best Practices für zuverlässigen Hintergrundbetrieb

Hintergrundaufgaben sind von Natur aus fragil – das Betriebssystem kann Ihren Prozess jederzeit beenden. Befolgen Sie diese Richtlinien, um Ihre Headless JS-Aufgaben robust zu machen:

  • Behalte Aufgaben kurz. Ziele auf weniger als 30 Sekunden Ausführung.
  • Verwalte Fehler anmutig. Wickele deine Logik in try/catch.
  • Nutze Offline-Erstmuster. Da Hintergrundaufgaben oft ohne Netzwerkgarantien laufen, implementiere Retries und speichere fehlgeschlagene Operationen für später.
  • Vermeiden Sie schwere Zustandsverwaltung. Verlassen Sie sich nicht auf Redux- oder React-Zustand – Hintergrundaufgaben, die in einem separaten JavaScript-Kontext ausgeführt werden.
  • Testen Sie auf realen Geräten. Der Android-Emulator und der iOS-Simulator verhalten sich anders als physische Hardware. Testen Sie mit ausgeschaltetem Gerätebildschirm und im Doze-Modus (Android) oder im Low Power-Modus (iOS).
  • Respektiere die Akkuoptimierung. Verwenden Sie mit einer Wake-Sperre auf Android, um zu verhindern, dass die CPU schläft, aber lösen Sie die Sperre sofort. Auf iOS werden Hintergrundabrufintervalle vom System verwaltet – respektieren Sie die gewährte Zeit.

Debugging Headless JS Aufgaben

Das Debuggen von Hintergrundcode ist schwierig, da Sie den Chrome DevTools-Inspektor nicht verwenden können, wenn die Benutzeroberfläche nicht aktiv ist.

  • Logcat (Android) – Fügen Sie -Anweisungen hinzu; sie erscheinen in logcat mit dem Tag “ReactNativeJS”.
  • Lokale Dateiprotokolle – Schreibe Logeinträge in eine Datei auf dem Gerät und rufe sie später ab.
  • Flipper – React Native Flipper kann Konsolenprotokolle von Headless-Aufgaben erfassen (stellen Sie sicher, dass Sie in Ihrem Flipper-Plugin auf true einstellen).
  • Native Logging – Verwenden Sie in Ihrem Java-Dienst, um zu verfolgen, wann die Aufgabe beginnt und endet.

Einschränkungen und Überlegungen

Headless JS ist keine Silberkugel. Verstehen Sie ihre Grenzen, um Überraschungen zu vermeiden:

  • Keine UI-Interaktion. Sie können keine Ansichten darstellen oder Benachrichtigungen innerhalb einer Headless-Task anzeigen. Verwenden Sie Push-Benachrichtigungen, um den Benutzer über die Ergebnisse zu informieren.
  • Einzelne Aufgabe pro Prozess. Der Headless-Dienst von React Native führt nur eine JavaScript-Task gleichzeitig aus.
  • iOS-Einschränkungen. iOS drosselt die Hintergrundausführung stark. Headless JS auf iOS ist nur für kurze Aufgaben zuverlässig, die durch Push-Benachrichtigungen oder Hintergrundabruf ausgelöst werden – das System kann die Ausführung verzögern oder verhindern, wenn der Benutzer die App zwingt, die App zu verlassen.
  • Kein Redux-Store. Wie bereits erwähnt, teilt sich der Headless JavaScript-Kontext nicht denselben Redux-Store wie die Vordergrund-App.
  • App-Beendigung. Wenn der Benutzer Ihre App unter Android 12+ oder iOS zwangsweise schließt, werden Hintergrundaufgaben möglicherweise erst ausgeführt, wenn der Benutzer die App erneut öffnet.

Vergleich mit anderen Hintergrundbibliotheken

React Natives Headless JS ist der am niedrigsten integrierte Mechanismus. Für viele Anwendungsfälle bieten Community-Pakete eine komfortablere API:

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.

Wenn Ihre Aufgabe auch nach einem Neustart ausgeführt werden muss oder Sie eine komplexe Planung benötigen, sollten Sie eine native WorkManager-Implementierung umschließen und über ein React Native Native-Modul freilegen. Headless JS ist nach wie vor hervorragend für leichte „Fire-and-Forget-Jobs geeignet.

Komplettes Beispiel: Synchronisierung von Daten auf Push-Benachrichtigung

Lassen Sie uns alles mit einem realistischen Szenario zusammenfassen: Wenn eine stille Push-Benachrichtigung auf Android eintrifft, lädt die App die neuesten Daten aus einer API herunter und speichert sie lokal. Der Benutzer sieht nie eine UI-Änderung - die Daten sind beim nächsten Öffnen der App bereit.

Android – Push Receiver

Erstellen Sie einen Broadcast-Empfänger, der die Push-Aktion abhört (z. B. von 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);
 }
}

Registrieren Sie es in AndroidManifest.xml mit einem Intentfilter für Ihre Push-Aktion (oder verwenden Sie FirebaseMessagingServices , um den Dienst direkt zu starten).

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);

Wenn der Benutzer die App wieder öffnet, kann der Vordergrund lesen und die Benutzeroberfläche sofort aktualisieren, wodurch ein nahtloses Offline-Ersterlebnis entsteht.

Performance und Batterieauswirkungen

Headless-Aufgaben laufen in derselben JavaScript-Engine wie die Haupt-App, aber in einem separaten Kontext. Jede Aufgabe dreht eine neue Headless-JS-Instanz, die Speicher und CPU verbraucht.

  • Verwenden Sie die kürzeste Timeout, die noch erlaubt, die Arbeit zu vollenden.
  • Führen Sie keine häufigen Umfragen durch - bevorzugen Sie Push-basierte Trigger.
  • Rufen Sie unter Android vom Dienst auf, nachdem die Aufgabe abgeschlossen ist (HeadlessJsTaskService macht dies automatisch, wenn das Versprechen aufgelöst wird).
  • Kombinieren Sie mit batteriebasierten APIs wie WorkManager für Android und BGTaskScheduler für iOS, wenn Sie regelmäßige Arbeiten benötigen.

Schlussfolgerung

Headless JS ist ein leistungsstarkes Tool im React Native Entwicklergürtel für die Handhabung kurzer Hintergrundaufgaben, die unabhängig von der Sichtbarkeit der App ausgeführt werden müssen. Durch die Einrichtung eines JavaScript-Handlers und die Verbindung mit nativen Hintergrundauslösern - wie Push-Benachrichtigungen, Alarme oder Hintergrundabrufe - können Sie reaktionsschnelle, datengesteuerte Anwendungen erstellen, die sich immer eingeschaltet fühlen. Denken Sie daran, Best Practices in Bezug auf Kürze, Fehlerbehandlung und plattformspezifische Einschränkungen zu befolgen, um sicherzustellen, dass Ihre Hintergrundoperationen zuverlässig und batteriefreundlich sind. Für erweiterte Planung oder längere Aufgaben ergänzen Sie Headless JS mit dedizierten Bibliotheken wie oder nativem WorkManager.

Für weitere Informationen siehe die offizielle Dokumentation von React Native zu Headless JS (Android) und Headless JS (iOS) Auch die react-native-background-fetch Library für periodisches Task-Management.