npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-nitro-bg-timer-plus

v0.5.0

Published

react-native-nitro-bg-timer-plus is a React Native package built with Nitro, forked from react-native-nitro-bg-timer

Readme

react-native-nitro-bg-timer-plus

A maintained, independent fork of react-native-nitro-bg-timer by Thành Công, maintained by Marco Crupi.

npm version license

Native timeout and interval scheduling for Android and iOS, built with Nitro Modules. Application callbacks run in JavaScript; background execution depends on the time and resources the operating system grants your app.

This README describes version 0.5.0. See the release notes for the compatibility changes since 0.4.0. Use the documentation from the matching release tag when consuming another version.

Requirements

The current manifest declares:

| Dependency/tool | Requirement | | --- | --- | | React Native peer | >=0.78.0 (New Architecture) | | Nitro Modules peer | ^0.37.1 (>=0.37.1 <0.38.0) | | React peer | * (development/example use 19.2.5) | | Node | ^22.13.0 \|\| ^24.3.0 \|\| >=26.0.0 | | Repository package manager | Yarn 4.6.0 |

Upgrading from 0.4.0: that release pins React Native 0.87.1 and Nitro Modules 0.37.1. Version 0.5.0 broadens the RN peer range and includes the opt-in compatibility patch described below.

Use a native React Native application with the New Architecture; Old Architecture is not supported. The React Native floor comes from Nitro Modules 0.37, which does not compile against RN 0.76/0.77 on Android. Nitro stays within 0.37.x because the bundled bindings are generated by Nitrogen 0.37.1. The upper bound is open in the manifest; verification covers only the exact versions in the compatibility matrix. Verified configurations cover Android and iOS RN 0.78.3–0.88.0, one RN patch release per minor. iOS RN 0.78–0.83 additionally requires exactly Nitro 0.37.1 with the opt-in compatibility patch. Stock Nitro 0.37.1 fails to build those iOS configurations. The development example uses RN 0.87.1. The Android library has a default minimum SDK of 24; the host RN/toolchain can impose stricter requirements. The iOS podspec uses React Native's min_ios_version_supported. A podspec visionOS declaration is not visionOS runtime qualification.

Compatibility matrix

Each row is a fresh app from the RN template with the packed library installed under strict peer resolution and built in Release. The runtime check verifies an interval, a cleared timeout and a final timeout in the foreground. Qualification on 2026-10-16 used Nitro Modules 0.37.1, Node 24.14.1 and RN CLI 20.2.0 on these targets:

  • Android: API 36 ARM64 emulator, all eleven RN versions below with stock Nitro.
  • iOS RN 0.84–0.88: Xcode 27.0, iOS 26.5 simulator, stock Nitro.
  • iOS RN 0.78–0.83: Xcode 16.4 on macos-15 ARM64 CI, iOS 18.5 simulator, with the supplied Nitro patch.

The same patch also passed build and runtime controls on iOS RN 0.78.3, 0.83.10, 0.84.1 and 0.88.0 with Xcode 27.0/iOS 26.5, and Android RN 0.78.3. An actual RN 0.78.3 app also passed npm ci with the documented postinstall hook, preserving the patched headers. Yarn 4 dependency-patch persistence was checked separately; the native matrix apps use npm.

Results combine the base matrix with the patched iOS qualification and the launcher follow-up. Timer sources and generated bindings are unchanged between the runs. PASS requires original command exits, a matching fresh run ID, exact peers and installed-artifact checks. The first RN 0.81/0.82 CI attempts built successfully but hit the runner's 30-second simulator-launch cap; the follow-up honors the configured timeout and retains all timer/result checks.

Reproduce the qualification with RN_CLI_VERSION=20.2.0 and scripts/compat-matrix.sh; add --nitro-ios-compat for the older iOS rows. See CONTRIBUTING.md. The permanent Compatibility CI workflow checks builds only, plus runner regressions.

| React Native | Android build | Android runtime | iOS Nitro setup | iOS build | iOS runtime | | --- | --- | --- | --- | --- | --- | | 0.78.3 | PASS | PASS | Patched 0.37.1 [^nitro-compat] | PASS | PASS | | 0.79.7 | PASS | PASS | Patched 0.37.1 [^nitro-compat] | PASS | PASS | | 0.80.3 | PASS | PASS | Patched 0.37.1 [^nitro-compat] | PASS | PASS | | 0.81.6 | PASS | PASS | Patched 0.37.1 [^nitro-compat] | PASS | PASS | | 0.82.1 | PASS | PASS | Patched 0.37.1 [^nitro-compat] | PASS | PASS | | 0.83.10 | PASS | PASS | Patched 0.37.1 [^nitro-compat] | PASS | PASS | | 0.84.1 | PASS | PASS | Stock 0.37.1 | PASS | PASS | | 0.85.3 | PASS | PASS | Stock 0.37.1 | PASS | PASS | | 0.86.3 | PASS | PASS | Stock 0.37.1 | PASS | PASS | | 0.87.1 | PASS | PASS | Stock 0.37.1 | PASS | PASS | | 0.88.0 | PASS | PASS | Stock 0.37.1 | PASS | PASS |

[^nitro-compat]: iOS RN 0.78–0.83 requires exactly Nitro 0.37.1 plus the app-side patch backported from Nitro PR #1575, which was open on 2026-10-16. The patch hides React renderer headers from Nitro's Swift-facing module. Stock Nitro fails in glog even with Xcode 16.4; the unpatched CI results are retained. Installing this library does not apply the fix: follow the npm/Yarn patch instructions before installing Pods.

The Xcode 27 builds also use the app-side fmt workaround where applicable. Apps without a UIScene life cycle need migration before launching on iOS 27 when built with its SDK. See the iOS build notes.

These foreground smoke checks do not qualify background execution. Declared peers are distinct from tested configurations. Physical QA covers specific Android/iPhone artifacts and scenarios, with gaps documented in PHYSICAL_QA.md. It does not establish compatibility with every device, OS version, power mode or store distribution.

Installation

Install version 0.5.0 and Nitro in a native React Native app within the declared range:

npm install [email protected] [email protected]
# Or:
yarn add [email protected] [email protected]

To build a local archive instead of installing from npm:

# In the library checkout; npm pack runs the Bob build through prepack.
yarn install --immutable
npm pack

Then install the resulting archive in your application, replacing the path:

npm install /absolute/path/to/react-native-nitro-bg-timer-plus-0.5.0.tgz [email protected]
# Or:
yarn add /absolute/path/to/react-native-nitro-bg-timer-plus-0.5.0.tgz [email protected]

For iOS RN 0.78–0.83, apply the compatibility patch before installing Pods. It requires exactly Nitro 0.37.1. See also the contributor package checks.

Autolinking includes the native library and generated Nitro bindings. Consumers do not run Nitrogen or manually register the package. Rebuild your native app after installation; restarting Metro alone cannot load a new native module. For iOS, install Pods using your application's Ruby/Bundler environment:

cd ios
bundle exec pod install

If your app does not use Bundler, use its established CocoaPods workflow. See Nitro installation. The base iOS timer mechanism needs no UIBackgroundModes entry.

On Android, the library manifest merges WAKE_LOCK, FOREGROUND_SERVICE, FOREGROUND_SERVICE_SPECIAL_USE, POST_NOTIFICATIONS, and a non-exported specialUse service into the app. Review the merged manifest for your build. Your app owns the Android 13+ notification permission request; the library does not display that permission dialog itself. See Android background mode.

iOS build notes

fmt and Xcode: React Native apps using fmt 11 can hit C++20 consteval errors with Xcode 26.4 and later; see the upstream issue. The affected rows in this matrix are RN 0.78–0.82 and 0.84. The Xcode 27 qualification builds set only the fmt pod to C++17. If you encounter this error, add the following inside your app's existing post_install block, after its react_native_post_install(...) call:

installer.pods_project.targets.each do |target|
  next unless target.name == 'fmt'

  target.build_configurations.each do |config|
    config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17'
  end
end

Run pod install again using the app's Bundler workflow, then rebuild. This workaround is separate from the Nitro header patch; affected apps may need both.

UIScene and iOS 27: apps built with the iOS 27 SDK must adopt the UIKit scene life cycle to launch on iOS 27. The unmodified templates tested here before RN 0.88 lack that setup. Update the app's lifecycle configuration before targeting iOS 27; the iOS 26.5 simulator results above do not qualify iOS 27 runtime behavior.

Quick start

import { BackgroundTimer } from 'react-native-nitro-bg-timer-plus'

const timeoutId = BackgroundTimer.setTimeout(() => {
  console.log('Timeout delivered')
}, 5000)

const intervalId = BackgroundTimer.setInterval(() => {
  console.log('Interval delivered')
}, 1000)

// Call when this feature finishes, before a pending callback is needed:
function cleanupTimers(): void {
  BackgroundTimer.clearTimeout(timeoutId)
  BackgroundTimer.clearInterval(intervalId)
}

In a React component, clear the timers created by that effect:

import { useEffect } from 'react'
import { BackgroundTimer } from 'react-native-nitro-bg-timer-plus'

export function useTimerLog(): void {
  useEffect(() => {
    const timeout = BackgroundTimer.setTimeout(() => console.log('Once'), 5000)
    const interval = BackgroundTimer.setInterval(() => console.log('Tick'), 1000)
    return () => {
      BackgroundTimer.clearTimeout(timeout)
      BackgroundTimer.clearInterval(interval)
    }
  }, [])
}

The exported BackgroundTimer is a shared wrapper, not a per-component instance. Use clear methods for ordinary feature cleanup. dispose() permanently ends the whole wrapper's lifetime and affects every feature using it.

API reference

Import the named BackgroundTimer export. All durations are milliseconds. All methods other than scheduling return void, not a Promise or a service success receipt. Native setup/interop errors can propagate; a scheduling ID acknowledges the wrapper call, not OS permission to execute in background.

setTimeout(callback: () => void, duration: number): number

Registers a callback and returns its numeric ID. callback must be a function (TypeError otherwise); duration must be a finite, nonnegative number (RangeError otherwise). A disposed wrapper throws Error before validation. If native registration throws synchronously, the callback registration is rolled back and that error is rethrown (F9).

Android posts to its worker using duration.toLong() milliseconds, truncating fractional values. iOS uses a main-run-loop Timer with duration / 1000 seconds. Zero is accepted; neither platform guarantees immediate delivery. A delivered timeout is removed even if its callback throws.

clearTimeout(id: number): void

Pass the ID returned by setTimeout. Removes its JS callback and requests native cancellation/queued-event removal on Android or iOS. Repeating a clear or clearing an unknown ID is harmless for normal numeric IDs. The wrapper does not validate IDs; do not pass arbitrary values. After wrapper disposal this is a silent no-op. Cancellation cannot interrupt a callback already executing.

setInterval(callback: () => void, interval: number): number

Registers a recurring callback and returns its numeric ID. Validation, disposed errors and synchronous registration rollback match setTimeout.

Both platforms apply a 1 ms native minimum to interval values below 1 ms, including zero (F10). For values at or above 1 ms, Android truncates to whole milliseconds; iOS retains the fractional millisecond value. For example, 1.5 uses 1 ms on Android and 1.5 ms on iOS. This is a scheduling floor, not a guarantee of 1 ms precision. Timeout scheduling does not use this interval floor. Intervals coalesce pending native events; missed ticks are not an elapsed-time counter. Clear an interval explicitly, including after a callback error.

clearInterval(id: number): void

Pass the ID returned by setInterval. Removes its JS callback and requests native cancellation/queued-event removal on both platforms. Repeated or unknown numeric IDs are harmless; IDs have no wrapper validation. Silent no-op after disposal. Cannot preempt a running callback.

dispose(): void

Idempotently marks the wrapper disposed, clears callback maps, removes its event subscription and invokes native disposal. Android cleanup releases this owner's FGS demand and wake lock, clears work and queues, and terminates its worker. iOS dispatches cleanup to the main queue, invalidates timers, removes its observer and ends its background task. Return from this method is not a synchronous cross-platform resource-settlement receipt.

After disposal, setTimeout, setInterval, configure and startBackgroundMode throw Error; clear methods, stopBackgroundMode and repeated dispose are no-ops. There is no public reset/reinitialize method. A fresh runtime/application can create a fresh wrapper. Android process-wide FGS opt-out is a separate lifetime described below.

configure(config: BackgroundTimerConfig): void

interface BackgroundTimerNotificationConfig {
  title?: string
  text?: string
  channelId?: string
  channelName?: string
  iconResourceName?: string
}
interface BackgroundTimerConfig {
  notification?: BackgroundTimerNotificationConfig
}

These types are exported. All notification fields are optional. Defaults are Background Timer Active, Tap to return to the app, nitro_bg_timer_channel, and Background Timer respectively. iconResourceName names an app drawable; missing/unresolved icons fall back to the launcher icon, then a system icon.

Android rejects configuration while that owner has an explicit request or uncleared accepted/pending/active timers. Clear all its timers and stop its explicit request first. IDs marked pending-clear no longer block configuration, so immediate clear → configure → schedule is supported. New sessions snapshot the current config (F5). Empty/missing notification fields use defaults. This is not a live-edit API for an active session.

On iOS the native operation is a no-op. The JS wrapper still serializes the argument with JSON.stringify(config ?? {}) on both platforms; non-serializable input can throw. Both platforms throw Error if the wrapper is disposed. Android native gating errors propagate to JS; malformed raw JSON is logged and ignored by native code, not exposed as a supported input contract.

startBackgroundMode(): void

Android requests an explicit service hold, including when there are no timers. Repeated calls while pending/active do not add holds. A later request can retry a recoverable failed start. When process opt-out has succeeded, native start is a no-op. iOS: native no-op; it does not extend the background-task budget. Both platforms throw Error if the wrapper is disposed.

stopBackgroundMode(): void

Android releases this owner's explicit hold. Active timers retain implicit demand; other owners can also retain the shared service. Repeated calls and calls after wrapper disposal are no-ops. iOS: no-op. It does not cancel timers.

disableForegroundService(): void

Android process-wide, irreversible opt-out (F6). The first successful call must precede any timer acceptance or explicit background request across every native owner in the process. A first call after such use throws, even when those timers have finished. After successful opt-out, repeated calls are no-ops, including with active wake-lock-only timers. It survives new HybridObjects and RN runtime reloads; only a fresh process without opt-out can enable FGS again.

iOS: no-op. Unlike configure/start, the wrapper has no disposed guard for this method: it always forwards to the native object. Android's native implementation ignores it on a disposed object. Do not rely on raw Nitro access after disposal; make opt-out decisions at process startup.

Low-level export

NitroBackgroundTimer is also exported: the raw HybridObject backing the wrapper. Its spec accepts numeric IDs plus durations, has the Android configuration method configure(configJson: string), the background-mode methods, and drainFiredTimers(): FiredTimerEvent[]. Events contain id, type (timeout 0, interval 1) and sequence; dispose() is inherited from Nitro's HybridObject. It has no application callback registry or wrapper validation. The event types are defined in the spec, not re-exported as named types from the package entry point. Prefer BackgroundTimer for apps. Do not drain its raw object yourself: that can consume events before the wrapper. Raw Nitro proxies must not be accessed after disposal, including for a second method lookup. The wrapper's idempotent disposal guard is a separate contract.

Native event delivery

Native Android runnables / iOS timers append fired events and send a NitroBackgroundTimerTimersAvailable signal through React Native's event emitter. The JS wrapper drains native events and invokes the callbacks held in its maps. Nitro calls do not mean application callbacks execute off the JS thread.

F1 replaces the former 1,024-entry eviction behavior with a dynamic queue: expired timeouts are not intentionally discarded at that old threshold. Memory is proportional to pending events; this is not a constant-memory queue or a persistent delivery mechanism. At most one event per interval ID remains pending until drained. Clear removes callbacks and queued native events; dispose empties the owner's queue. A blocked JS thread delays application callbacks; a suspended app or terminated process cannot be promised delivery. The queue records actual native fires, not every theoretical deadline missed while the OS suspended timers.

A drain continues processing its batch when a callback throws and rethrows the first thrown value after processing. Timeout callbacks are removed in finally; interval callbacks remain until cleared. Handle application errors inside your callbacks; the timer is not a universal error boundary. Async callback results are not awaited, so manage rejected promises and overlapping work yourself.

Lifecycle and cleanup

| Event | Expected boundary | | --- | --- | | Home / Resume | Does not itself dispose timers; execution is subject to OS policy. | | Android Activity recreation | Preserves timers when the same JS runtime/ReactContext remains alive (F2). | | Android ReactHost.reload() | Replaces the runtime; its TurboModule owner invalidates and disposes registered timer objects (F3). | | Android ReactHost.destroy() | Runtime invalidation uses the same cleanup path; this is distinct from Activity destruction. | | Fast Refresh | Can retain the runtime; does not prove native teardown. Clear feature timers in effect/unmount cleanup. | | Explicit dispose() | Terminal wrapper cleanup; use only when all users of the singleton are finished. | | Process termination | OS reclaims process resources; Java/JS/Swift cleanup callbacks are not guaranteed to run. Timers are not persisted. |

The Android owner is tied to the captured ReactContext, not an Activity or a later global context. Runtime invalidation disposes its objects and waits for old workers, including manual disposal already in flight, before returning. Cleanup releases per-owner wake locks and shared-service demand. Dropping a raw JS reference alone does not terminate a runtime-owned Android worker. GC/finalizers are fallback mechanisms, not deterministic feature cleanup.

On iOS, explicit disposal and deinit invalidate timers and end the background task. Do not equate Android's runtime-owner barrier with an independently observed iOS private-task teardown barrier.

Android background mode

Timers request the FGS when accepted, including in foreground; it is not started only after Home. Implicit demand ends when the owner's final timer finishes/is cleared. Explicit mode holds demand across gaps between timers:

import { BackgroundTimer } from 'react-native-nitro-bg-timer-plus'

BackgroundTimer.configure({
  notification: {
    title: 'Timer session',
    text: 'A timer session is active',
    channelId: 'timer_sessions',
    channelName: 'Timer sessions',
  },
})
BackgroundTimer.startBackgroundMode()
const timer = BackgroundTimer.setInterval(() => console.log('Tick'), 1000)

function endSession(): void {
  BackgroundTimer.clearInterval(timer)
  BackgroundTimer.stopBackgroundMode()
}

Configure before starting and request from a legitimate user-visible context. Multiple native owners share one service and notification (F8). The earliest owner still holding demand supplies the notification snapshot. When it leaves, the earliest remaining owner takes over; disposing one must not stop another's demand. Wake locks are per owner and tied to timers, not an explicit hold alone.

The coordinator handles pending stop/start races and subsequent configuration sessions. Notification title/text/icon/channel selection follow current demand; creating an existing channel does not retroactively change immutable channel settings or override user choices. See Android notification channels.

Recoverable startForegroundService refusals reset start state; a subsequent explicit or timer request can retry (F7). There is no automatic retry loop. While the process is alive, timers can use the wake-lock fallback. A failed initial startForeground promotion or missed handshake can still cause Android to terminate the process; catching an exception is not proof of survival. Background-start restrictions still apply. The service returns START_NOT_STICKY, not a persistence guarantee.

WAKE_LOCK is acquired non-reference-counted while timers remain and released after completion, clear or cleanup. Missing permission/acquisition failures are logged and timers continue without that protection. A wake lock does not grant unlimited process or JS execution. FGS does not guarantee exact timing or survival under every power, memory or OEM policy.

Notifications and opt-out

On Android 13+, request notification permission through your app's existing flow:

import { PermissionsAndroid, Platform } from 'react-native'

export async function requestTimerNotificationPermission(): Promise<void> {
  if (Platform.OS === 'android' && Platform.Version >= 33) {
    await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
    )
  }
}

Permission denial/notification visibility and successful service promotion are separate observations. Inspect service state rather than infer it from the shade.

To opt out, call BackgroundTimer.disableForegroundService() at startup before any use, as specified in the API reference. Explicit start then has no effect; timers continue using the wake-lock path where available. Runtime opt-out does not remove manifest declarations. If your app intentionally excludes this FGS, combine startup opt-out with manifest-merger removal of the service. Remove shared permissions only if no other feature needs them:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"
      tools:node="remove" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE"
      tools:node="remove" />
  <application>
    <service android:name="com.margelo.nitro.backgroundtimer.NitroBackgroundTimerService"
        tools:node="remove" />
  </application>
</manifest>

The bundled service declares specialUse with subtype continue_user_initiated_background_timer. Assess your app's actual use case and distribution requirements; this library and its QA do not establish store approval. Runtime opt-out alone does not remove that declaration.

iOS background execution

Native timers use the main run loop in common mode. Scheduling attempts to acquire UIApplication.beginBackgroundTask; the OS may deny or expire it. Expiration ends the matching identifier, preserves timer state and ignores stale identifiers. When the app later enters background with active timers and no task, the observer attempts reacquisition. It does not continuously renew an expired budget.

Suspension can stop both native timer firing and JS callback execution; resume can allow delivery again. There is no guaranteed expiration duration, infinite execution, or callback delivery while suspended. Clear/dispose release the task when appropriate. See Apple's background-task API.

Performance and limitations

Choose intervals that match the work, keep callbacks short, and clear them when finished. Frequent intervals, pending timeout backlogs and Android wake locks consume CPU, memory and battery. Use monotonic elapsed time for duration logic rather than equating interval callback counts with elapsed seconds.

No real-time precision, universal drift percentage, unlimited background window, process-kill delivery, or multi-OEM guarantee is made. Physical QA results identify specific artifacts and scenarios; a host/Jest PASS is not device qualification. The 1,500-event backlog test uses a raw adapter, not the wrapper's full automatic path. See qualification boundaries.

Troubleshooting

| Symptom | What to check | | --- | --- | | Native module / HybridObject unavailable | Match the installed RN/Nitro peers, install iOS Pods, verify autolinking and rebuild the native app. Use a native New Architecture build, not a JS-only runtime. | | iOS build fails in glog or fmt | iOS RN 0.78–0.83 with Nitro 0.37.1 needs the app-side compatibility patch, including with Xcode 16.4. For fmt errors, follow the separate iOS build notes. | | No callback | Check whether the ID was cleared or the shared wrapper disposed, whether JS is blocked, and whether the process/runtime changed. Use example smoke logs to separate URL delivery, event signals, drains and callbacks. | | Android background delays | Inspect current timer service and UID-owned wake lock, start-refusal logs, opt-out state and OS power policy. A worker or wake lock alone does not prove JS delivery. | | Android notification missing | Check app permission, channel/user settings and current service state separately. Confirm configure ran before active demand and the drawable exists. | | Android start refusal | Follow permitted foreground-service start conditions; retry through a later legitimate request. Do not disable OS protections to force a PASS. | | Configure throws | Clear all this owner's timers and release its explicit hold; other owners may still supply the shared notification. | | Disposed error | Use clear for feature cleanup. Restart the app/runtime for a new wrapper; there is no reset API. FGS opt-out additionally requires a fresh process to reverse. | | iOS timers pause | Check suspension, task denial/expiration, app lifecycle and process death. Test resume/re-entry; adding unrelated background modes does not grant unlimited execution. | | Physical QA refuses preflight | Read the historical baseline/hash gate in PHYSICAL_QA.md before attempting device runs. |

Android native logs use tag NitroBgTimer; iOS logs use [NitroBgTimer]. Debug builds include additional debug messages; there is no public debug-toggle API. Example-only smoke/QA bridges are diagnostics, not library methods.

Development and navigation

Credits and acknowledgements

The original library is by Thành Công: react-native-nitro-bg-timer. This fork is an independent continuation, not an official upstream release. Historical contributions and release records are retained.

Thanks to Nitro Modules, react-native-background-timer and react-native-background-job for the architecture, timer concepts and background-processing patterns.

License

MIT. Copyright 2025 Thành Công (original author) and 2026 Marco Crupi (fork maintainer), as recorded in the unchanged license file.