Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
14a8e8d
feat: integrate battery-efficient Activity Recognition (STILL/MOTION)…
manojvermamv Jun 22, 2026
cfbf79e
fix: include missing Android ActivityProvider interfaces and factory
manojvermamv Jun 22, 2026
d71ea25
build: update podspec and example app permissions for CoreMotion/Acti…
manojvermamv Jun 22, 2026
584c9a4
docs: update README, CHANGELOG, and package.json for v1.1.0 Activity …
manojvermamv Jun 22, 2026
c49cb99
fix: parseTrackingOptionsFromBundle now reads activityTrackingEnabled…
manojvermamv Jun 23, 2026
2bc022b
fix: prevent iOS crash if NSMotionUsageDescription is missing
manojvermamv Jun 23, 2026
871d261
fix(ios): initialize new tracking options in init nil branch
manojvermamv Jun 23, 2026
40f5a03
fix(android): extend isStill detection to include TILTING and UNKNOWN…
manojvermamv Jun 26, 2026
cfa5158
Add Android test CI, DB migration & activity fixes
manojvermamv Jun 30, 2026
ada2f87
fix: address maintainer PR #49 review — Room migration, automotive ex…
manojvermamv Jul 2, 2026
d6b2e0f
fix: remove invalid optional binding on non-optional effectiveTripId …
manojvermamv Jul 3, 2026
834eb9e
fix: apply Prettier formatting to trackingOptionsMapper.ts return block
manojvermamv Jul 3, 2026
3ee2234
fix: revert mapper to return {} for null/undefined and omit defaults …
manojvermamv Jul 3, 2026
9c05e9a
fix: add gradle wrapper files for CI test execution
manojvermamv Jul 6, 2026
907783b
chore: update XCODE_VERSION to 26.0.1 in CI
manojvermamv Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,31 @@ jobs:
flags: unittests
fail_ci_if_error: false

test-android:
runs-on: ubuntu-latest
needs: [lint, test]

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Setup
uses: ./.github/actions/setup

- name: Install JDK
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: 'zulu'
java-version: '17'

- name: Finalize Android SDK
run: |
/bin/bash -c "yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null"

- name: Run Android unit tests
run: ./gradlew testDebugUnitTest
working-directory: android

build-library:
runs-on: ubuntu-latest

Expand Down Expand Up @@ -129,7 +154,7 @@ jobs:
runs-on: macos-latest

env:
XCODE_VERSION: 16.4
XCODE_VERSION: 26.0.1
TURBO_CACHE_DIR: .turbo/ios
RCT_USE_RN_DEP: 1
RCT_USE_PREBUILT_RNCORE: 1
Expand Down
2 changes: 1 addition & 1 deletion BackgroundLocation.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |s|
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
s.private_header_files = "ios/**/*.h"

s.frameworks = "CoreLocation", "CoreData"
s.frameworks = "CoreLocation", "CoreData", "CoreMotion"

s.resource_bundles = {
'BackgroundLocationPrivacy' => ['ios/PrivacyInfo.xcprivacy'],
Expand Down
39 changes: 39 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
# Changelog

## [1.1.0] - 2026-06-22

### Added

- **Activity Recognition — Android** (`ActivityProvider.kt`, `ActivityProviderFactory.kt`, `ActivityRecognitionProvider.kt`): Implemented a battery-efficient activity recognition architecture using Google Play Services `ActivityRecognitionClient`. Uses polling-based `requestActivityUpdates` with confidence-based filtering.
- **Activity Recognition — iOS** (`ActivityProvider.swift`): Equivalent `CMMotionActivityManager` wrapper for iOS. Detects `stationary`, `walking`, `running`, `automotive`, and `cycling` states via `CoreMotion` framework. Runs on a dedicated serial queue with confidence-based filtering.
- **`ActivityReceiver.kt`**: Manifest-registered `BroadcastReceiver` that captures activity recognition `PendingIntent` events from Play Services and routes them safely to the `LocationService` singleton via a thread-safe `handleActivityStateChanged` method.
- **Dynamic GPS throttling**: `LocationService.kt` now pauses `requestLocationUpdates` when the device is detected as `STILL` with high confidence (if `pauseLocationWhenStill` is enabled) and resumes when polling indicates movement, cutting GPS battery drain to near-zero while stationary.
- **iOS dynamic GPS throttling**: `LocationManagerWrapper.swift` implements the same pause/resume logic driven by `ActivityProvider`'s `onActivityStateChanged` delegate callback.
- **Three new `TrackingOptions` fields** (Android, iOS, TypeScript — all platforms):
- `activityTrackingEnabled: boolean` — opt-in to activity recognition (default: `false`).
- `pauseLocationWhenStill: boolean` — pause GPS when device is stationary (requires `activityTrackingEnabled`, default: `false`).
- `activityUpdateInterval: number` — polling interval in milliseconds for Android `requestActivityUpdates` (default: `60000`).
- **TurboModule Codegen spec** (`src/NativeBackgroundLocation.ts`): Added the three new fields to `TrackingOptionsSpec` so Codegen generates the correct C++ struct accessors on both platforms.
- **TypeScript types** (`src/types/tracking.ts`): Full JSDoc-annotated `TrackingOptions` fields with platform tags.
- **TS options mapper** (`src/utils/trackingOptionsMapper.ts`): `toTrackingOptionsSpec()` now forwards the three new fields across the TurboModule bridge.
- **`BackgroundLocation.mm`** (iOS Objective-C++ bridge): `transportDictFromCodegenSpec:` maps `activityTrackingEnabled`, `pauseLocationWhenStill`, and `activityUpdateInterval` from the C++ struct into the `NSDictionary` delivered to Swift.
- **`CoreMotion` framework** added to `BackgroundLocation.podspec` (`s.frameworks`): CocoaPods now auto-links `CoreMotion` for consumers without any manual Xcode project changes.
- **Manifest permissions** (`android/src/main/AndroidManifest.xml`): Added `android.permission.ACTIVITY_RECOGNITION` (API 29+) and `com.google.android.gms.permission.ACTIVITY_RECOGNITION` (legacy Play Services).
- **Example app permissions** (`example/android/app/src/main/AndroidManifest.xml`): Mirrored same permissions for the bundled demo application.
- **Example app `Info.plist`** (`example/ios/BackgroundLocationExample/Info.plist`): Added `NSMotionUsageDescription` so the demo app can request CoreMotion access without crashing.
- **Android unit tests**:
- `ActivityRecognitionProviderTest.kt` — MockK-based tests validating client registration, `PendingIntent` delivery, and `cleanup()` resource release.
- `TrackingOptionsTest.kt` — Validates all new option fields parse correctly with expected defaults and custom values.

### Changed

- `LocationService.kt`: Integrated `ActivityProvider` lifecycle (start on `onStartCommand`, cleanup on `onDestroy`). Added `instanceLock`-guarded `handleActivityStateChanged` for safe cross-thread state transitions.
- `LocationManagerWrapper.swift`: Conforms to `ActivityProviderDelegate`; mounts/unmounts `ActivityProvider` alongside the `CLLocationManager` session.
- `BackgroundLocationModule.kt`: Parses `activityTrackingEnabled`, `pauseLocationWhenStill`, and `activityUpdateInterval` from the incoming `ReadableMap`.
- `TrackingOptions.kt` / `TrackingOptions.swift`: Extended with new fields, safe defaults, and computed boolean accessors (`isActivityTrackingEnabled`, `shouldPauseLocationWhenStill`).

### Notes

- **Non-breaking release.** All new `TrackingOptions` fields are optional and default to `false`/`0`, so existing call sites compile and behave identically without changes.
- **No new Android dependency required.** `ActivityRecognitionClient` is included in the existing `com.google.android.gms:play-services-location:21.3.0` dependency.
- **iOS requires `NSMotionUsageDescription`** in the host app's `Info.plist` when `activityTrackingEnabled: true` is used. Omitting it causes a runtime crash on iOS.
- Runtime permission for `ACTIVITY_RECOGNITION` must be requested on Android 10+ (API 29) before enabling activity tracking. The library manifest declares the permission; the host app is responsible for requesting it at runtime.

## [1.0.0-rc] - 2026-05-27

> **First release candidate for the 1.x line.** From `1.0.0` forward, the library follows strict semver: breaking changes ship only on a major version bump. Three surfaces are explicitly frozen for the 1.x line: (1) the public TypeScript surface (named exports from `src/index.tsx`), (2) the TurboModule Codegen spec (`src/NativeBackgroundLocation.ts`), and (3) the native event names emitted via `NativeEventEmitter` (`onLocationUpdate`, `onLocationError`, `onLocationWarning`, `onNotificationAction`, `onGeofenceTransition`). No native (Android/iOS) code changes and no public TypeScript API changes since `0.17.0` this release candidate exists to declare API stability, not to introduce behavior.
Expand Down
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ A TurboModule for the React Native New Architecture. Drives a foreground service
- Native geofencing (GeofencingClient on Android, CLCircularRegion on iOS)
- Persistent location storage (Room on Android, Core Data on iOS)
- Crash recovery via WorkManager and significant location monitoring
- **Battery-efficient Activity Recognition** — pauses GPS when device is `STILL` (high confidence), resumes on motion (Android: Play Services `ActivityRecognitionClient`; iOS: `CoreMotion CMMotionActivityManager`)
- React hooks: `useBackgroundLocation`, `useLocationPermissions`, `useLocationUpdates`, `useLocationTracking`
- Expo config plugin for managed workflows

Expand All @@ -49,6 +50,22 @@ cd ios && pod install

Autolinking handles Android manifest merging and iOS pod registration. Bare iOS apps must still add `NSLocationWhenInUseUsageDescription`, `NSLocationAlwaysAndWhenInUseUsageDescription`, `NSLocationAlwaysUsageDescription`, and a `UIBackgroundModes` entry containing `location` to their `Info.plist`. See the [iOS setup guide](https://gabriel-sisjr.github.io/react-native-background-location/docs/getting-started/ios-setup) for full details.

> **Activity Recognition on iOS:** If you enable `activityTrackingEnabled: true`, you must also add `NSMotionUsageDescription` to your `Info.plist`. Without it, activity tracking will gracefully fall back to standard GPS (no battery optimization) instead of crashing.
>
> ```xml
> <key>NSMotionUsageDescription</key>
> <string>This app requires motion data to optimize location tracking battery usage.</string>
> ```
>
> **App Store disclosure:** Apps using CoreMotion must disclose motion data collection in their App Store privacy nutrition labels. This library does not persist motion data — it is processed in-memory only — but the consuming app is responsible for accurate privacy disclosure.

> **Activity Recognition on Android:** On Android 10+ (API 29), you must add `android.permission.ACTIVITY_RECOGNITION` to your app's `AndroidManifest.xml` and request it at runtime before enabling activity tracking:
> ```xml
> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
> ```

> **Note:** On iOS, activity tracking state is not persisted across crash recovery. If the app is killed and restarted by the system, activity-based GPS pausing will be re-enabled only if `activityTrackingEnabled: true` is passed again. On Android, this state is persisted in Room and survives crash recovery automatically.

## Quick Start

```tsx
Expand All @@ -63,7 +80,11 @@ function App() {
return (
<Button
title="Start"
onPress={() => startTracking({ tripId: 'trip-1', distanceFilter: 10 })}
onPress={() =>
startTracking('my-trip', {
distanceFilter: 10,
})
}
/>
);
}
Expand Down
Binary file added android/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
169 changes: 169 additions & 0 deletions android/gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 81 additions & 0 deletions android/gradlew.bat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading