Skip to content

joncodeofficial/react-native-beacon

react-native-beacon-kit

iBeacon / AltBeacon library for React Native built on New Architecture (TurboModules + JSI). Real background scanning on Android via foreground service — what other libraries promised but never delivered.

Platform support: Android fully supported. iOS in development.

Features

  • New Architecture (TurboModules + JSI) — no legacy bridge
  • Real background scanning on Android via foreground service
  • iBeacon + AltBeacon support (~85% of the beacon market)
  • Kalman filter for stable distance readings (optional)
  • Configurable scan intervals
  • Does not request permissions — respects your app's UX flow

Installation

npm install react-native-beacon-kit

Android permissions

All required permissions are automatically merged into your app's AndroidManifest.xml via autolinking — no manual changes needed for React Native CLI or Expo bare workflow.

Expo managed workflow — declare permissions explicitly in app.json:

{
  "expo": {
    "android": {
      "permissions": [
        "android.permission.ACCESS_FINE_LOCATION",
        "android.permission.ACCESS_BACKGROUND_LOCATION",
        "android.permission.BLUETOOTH_SCAN",
        "android.permission.BLUETOOTH_CONNECT"
      ]
    }
  }
}

Permissions are declared but not requested by the library — use react-native-permissions to request them at runtime before calling any scanning method.

Usage

import Beacon from 'react-native-beacon-kit';

// Configure once on app start
Beacon.configure({
  betweenScanPeriod: 0,
  foregroundService: true,   // required for real background scanning
  kalmanFilter: { enabled: true },
});

// Check permissions (does not request them)
const granted = await Beacon.checkPermissions();

// Start ranging
await Beacon.startRanging({
  identifier: 'my-region',
  uuid: 'FDA50693-A4E2-4FB1-AFCF-C6EB07647825',
});

// Listen for beacons
const sub = Beacon.onBeaconsRanged((event) => {
  event.beacons.forEach((beacon) => {
    console.log(beacon.uuid, beacon.major, beacon.minor);
    console.log(beacon.distance);   // meters
    console.log(beacon.rssi);       // dBm
    /** @warning May be randomized on Android 10+ */
    console.log(beacon.macAddress);
  });
});

// Cleanup
sub.remove();
await Beacon.stopRanging({ identifier: 'my-region', uuid: '...' });

API

configure(config)

Call once before starting any scan. All fields are optional.

Beacon.configure({
  scanPeriod?: number,          // how long the BLE radio actively scans, in ms (default: 5000)
  betweenScanPeriod?: number,   // how long the BLE radio rests between scans, in ms (default: 0)
  foregroundService?: boolean,  // enable real background scanning (default: false)
  kalmanFilter?: {
    enabled: boolean,
    q?: number,   // process noise — how much you trust movement (default: 0.008)
    r?: number,   // measurement noise — how much you trust RSSI (default: 0.1)
  },
});

scanPeriod vs betweenScanPeriod

scanPeriod is how long the BLE radio is on and detecting. betweenScanPeriod is how long it rests before the next scan. Beacons are reported once at the end of each active period.

|←── scanPeriod ──→|←── betweenScanPeriod ──→|←── scanPeriod ──→|
      radio ON              radio OFF                radio ON

betweenScanPeriod: 0 means continuous scanning. Adding a rest period saves battery — scanPeriod: 5000, betweenScanPeriod: 3000 and scanPeriod: 8000, betweenScanPeriod: 0 both update every ~8s, but the first uses less power because the radio is off for 3s each cycle.

Use case scanPeriod betweenScanPeriod
Real-time positioning 1100 0
Standard indoor navigation 5000 0
Background zone detection 5000 10000
Battery-sensitive background 2000 30000

checkPermissions(): Promise<boolean>

Returns true if all required permissions are granted. Does not request them.

startRanging(region) / stopRanging(region)

Detects nearby beacons with RSSI and distance (~every 1s).

startMonitoring(region) / stopMonitoring(region)

Detects region entry/exit. Battery efficient — use to wake up ranging when the user enters a zone.

onBeaconsRanged(callback)

const sub = Beacon.onBeaconsRanged((event) => {
  // event.region  — the active region
  // event.beacons — array of detected beacons
});

sub.remove(); // unsubscribe

onRegionStateChanged(callback)

const sub = Beacon.onRegionStateChanged((event) => {
  // event.region — the region
  // event.state  — 'inside' | 'outside'
});

Beacon object

interface Beacon {
  uuid: string;
  major: number;
  minor: number;
  rssi: number;       // signal strength in dBm
  distance: number;   // estimated distance in meters
  txPower: number;    // calibrated tx power of the beacon
  /** @warning May be randomized on Android 10+ — use uuid + major + minor as unique identifier instead. */
  macAddress: string;
  timestamp: number;
}

Background scanning

Background scanning on Android requires a foreground service — a persistent notification the user can see. Enable it via configure({ foregroundService: true }).

Without this, Android will kill the scanning process when the app goes to background. This is what most other beacon libraries for React Native never implemented.

Platform notes

Android

  • Requires ACCESS_BACKGROUND_LOCATION for background scanning (Android 10+)
  • Requires BLUETOOTH_SCAN + BLUETOOTH_CONNECT (Android 12+)
  • Foreground service keeps scanning alive even when the app is killed

iOS

iOS support is in development. Android is fully supported.

When iOS is released, it will require:

  • NSLocationAlwaysAndWhenInUseUsageDescription in Info.plist
  • NSLocationWhenInUseUsageDescription in Info.plist
  • "Location updates" background mode enabled in Xcode capabilities

Background ranging on iOS works differently from Android. iOS does not support continuous background ranging — instead, use startMonitoring() to wake the app when the user enters a region, then start ranging from that callback. iOS gives ~10 seconds of execution time per region event.

License

MIT

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Contributors