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

@geofencekit/sdk

v0.2.1

Published

React Native geofencing SDK: server-managed fence sync, native iOS/Android region monitoring, offline event queue, local notifications

Readme

Geofence Mobile SDK — native core

A server-managed geofencing SDK whose entire logic lives in native Swift and Kotlin — no JavaScript, no cross-platform runtime baked in. Fence sync, OS region monitoring, the offline event queue, notifications, and config all run natively, so the same dependable engine can be consumed by a native app, a Flutter plugin, or a React Native module.

Any SDK-provided UI (permission priming, debug map) ships as SwiftUI / Jetpack Compose — never web views or JS components.

Why server-managed?

iOS caps monitored regions at 20 per app; Android at 100. The SDK registers only the nearest 18 fences (leaving iOS headroom) and re-syncs when the device moves — so the platform supports unlimited branches while staying inside OS limits.

Layout

Package.swift                         Swift Package manifest (pure-native iOS)
ios/Sources/GeofenceSDK/              Native iOS core — no React
├── GeofenceSDK.swift                 Public facade: configure / requestPermissions / start / stop
├── GeofenceConfig.swift · Models.swift
├── APIClient.swift                   URLSession client (fence sync, event upload)
├── EventStore.swift                  Offline queue (Application Support, batched)
├── BackgroundUploader.swift          Background URLSession upload + BGTaskScheduler
├── FenceStore.swift                  UserDefaults: fences, config, cooldowns, anchor
├── LocationManager.swift             CLLocationManager: permissions, regions, SLC
└── NotificationManager.swift         UNUserNotificationCenter

android/src/main/java/com/geofencesdk/   Native Android core — no React
├── GeofenceSdk.kt                    Public facade (mirror of the Swift one)
├── GeofenceConfig / Models.kt
├── ApiClient.kt                      HttpURLConnection + org.json (no deps)
├── EventQueue.kt                     Offline queue (SharedPreferences, batched)
├── UploadWorker.kt                   WorkManager background upload (survives Doze / reboot)
├── FenceStore.kt                     Persisted fences, config, cooldowns, anchor
├── GeofenceManager.kt                GeofencingClient + FusedLocation wrapper
├── GeofenceBroadcastReceiver.kt      Headless triggers (app dead) → notify + record + upload
├── BootReceiver.kt                   Re-register fences on reboot / app update
└── NotificationHelper.kt            NotificationManagerCompat

bindings/                             Thin host wrappers (see bindings/README.md)
├── react-native/                     RN module — thin delegate to the native core
└── flutter/                          Flutter plugin (MethodChannel) — vendors the cores

Install

iOS — Swift Package Manager (recommended)

// Package.swift
dependencies: [
  .package(url: "https://github.com/mohamedma872/geofence-mobile-sdk.git", from: "0.2.0")
]

Add the location + background-mode keys to Info.plist (NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription, UIBackgroundModeslocation).

Android — Gradle (AAR via Maven / local module)

dependencies {
  implementation "com.geofencekit:geofence-sdk:0.2.0"
  implementation "com.google.android.gms:play-services-location:21.2.0"
}

Declare ACCESS_FINE_LOCATION, ACCESS_BACKGROUND_LOCATION, POST_NOTIFICATIONS, RECEIVE_BOOT_COMPLETED in the manifest and request the runtime permissions from your Activity.

Use it — native

Swift

import GeofenceSDK

let sdk = GeofenceSDK.shared
sdk.configure(GeofenceConfig(baseURL: "https://api.example.com", apiKey: "sdk-key", userId: "u_1"))

let status = await sdk.requestPermissions()          // two-step WhenInUse → Always
if status == .grantedAlways {
    let fences = try await sdk.start()               // sync + register + monitor
}

Kotlin

val sdk = GeofenceSdk.getInstance(context)
sdk.configure(GeofenceConfig(baseUrl = "https://api.example.com", apiKey = "sdk-key", userId = "u_1"))

// Request ACCESS_FINE / BACKGROUND / POST_NOTIFICATIONS from your Activity, then:
if (sdk.permissionStatus() == PermissionStatus.GRANTED_ALWAYS) {
    lifecycleScope.launch { val fences = sdk.start() }
}

Runtime behaviour (identical on both platforms)

  1. start() gets the current location, calls GET /v1/fences/nearest, registers the nearest fences with the OS, and begins movement monitoring.
  2. On movement past the server's refresh_after_m, the fence set is re-fetched and swapped.
  3. On enter, a local notification fires immediately from cached campaign content — no network round-trip, works offline — with a per-fence cooldown (hours managed server-side, applied on device).
  4. Events queue offline-safe with idempotency keys and upload in batches; the server enforces the authoritative cooldown / quiet hours / windows.
  5. Server-managed rules (fence limit, re-sync distance, cooldown) arrive in the sync response and are applied on the next sync — no app release.

Android process-death resilience

GeofenceBroadcastReceiver fires even when the app process is dead: it notifies from FenceStore-persisted content, records the event, and schedules a WorkManager upload (network-constrained, exponential backoff) that runs when connectivity returns — surviving app-death, Doze, and reboot. BootReceiver re-registers all fences on BOOT_COMPLETED and app update — the two moments Android silently drops geofences.

iOS background delivery

Uploads use a background URLSession, so iOS finishes the transfer out-of-process even if the app is suspended or terminated, and relaunches the app to deliver the result. Events are removed from the queue only once the server confirms them (idempotent client_event_id makes a re-send harmless). A BGTaskScheduler processing task provides a periodic drain when no location event is relaunching the app.

Two of these require host wiring you add once. Call configure() early (in didFinishLaunching) so the background session + BGTask handler are registered before iOS delivers events:

// Info.plist
// <key>UIBackgroundModes</key><array><string>location</string><string>processing</string></array>
// <key>BGTaskSchedulerPermittedIdentifiers</key><array><string>com.geofencekit.upload.refresh</string></array>

// AppDelegate
func application(_ app: UIApplication,
                handleEventsForBackgroundURLSession identifier: String,
                completionHandler: @escaping () -> Void) {
    GeofenceSDK.shared.handleBackgroundURLSession(identifier, completion: completionHandler)
}

// in application(_:didFinishLaunchingWithOptions:)
BGTaskScheduler.shared.register(
    forTaskWithIdentifier: "com.geofencekit.upload.refresh", using: nil
) { task in
    GeofenceSDK.shared.handleBGTask(task as! BGProcessingTask)
}

Without the wiring it still works — uploads just fall back to the region / movement wake windows (nothing is lost; delivery may be less timely). The React Native host wires the same two hooks from a Swift AppDelegate.

Platform limits & quotas

The SDK is thin; these limits live on the platform and apply to every host.

| Limit | Default | Notes | | --- | --- | --- | | Branches per workspace | 100 | Platform admin can raise it per customer | | API keys — trial / production | 2 / 25 | Active keys a workspace can self-issue | | Trial | 30 days · 1,000 devices · 10,000 events/mo | All features during the trial | | Fences monitored per device | ~18 | Nearest fences, re-synced on movement (iOS caps at 20 regions) | | Zone types | Circle + polygon | Radius fence or arbitrary polygon (point-in-polygon) | | Analytics retention | 90 days | Auto-deleted after; export to CSV from the dashboard anytime |

Capabilities: native iOS (Swift) + Android (Kotlin) cores; React Native + Flutter bindings; enter / exit / dwell; circular + polygon zones; background operation surviving reboot & app update (Android); offline event queue with idempotency keys; server-managed nearest-N fence sync; instant offline notifications from cached campaign content; central config (cooldown, quiet hours, fence limit) managed from the dashboard and synced to devices.

Bindings

The native cores are the SDK. Hosts plug in through thin wrappers — see bindings/README.md. Flutter uses a MethodChannel; React Native uses a small native module. Neither contains business logic — they only forward calls to the native facade.