React-Native Step Counter Library
This library provides an interface for tracking the number of steps taken by the user in a React Native app. This package uses the StepCounter
(or Custom accelerometer-based step-counter) Sensor API on Android and the Core Motion
framework on iOS to count the steps. It's built using Turbo Module, a new module development architecture for React Native. I made this library compatible with both new and legacy architectures. (Because the turbo module is still in the experimental stage. so it is not widely used.)
Installation
npm install @uguratakan/react-native-step-counter-improved
yarn add @uguratakan/react-native-step-counter-improved
pnpm add @uguratakan/react-native-step-counter-improved
Native modules will automatically connect after React Native 0.60 version. So you don't need to link the native modules manually.
👣 if you are using the legacy architecture, you need to follow the guide below. otherwise, you can skip next step.
WALKING_TRACKER EXAMPLE REPO
IF YOU WANT SEE A DEMO IN STANDALONE REACT-NATIVE APPLICATION, SEEThank you for your interest in my first NPM open source package! I've received a lot of issue reports on various issues, especially the react-native's NEW ARCHITECTURE
backwards compatibility, and I've more or less finalized those issues by fixing the code structure across the board. We had generated an example folder from create-react-native-library's template and used it for this project, but due to the structure of that template, we found that the example folder contained a lot of code that was not suitable for reference in a working app, as it was part of the overall development process rather than a standalone application. For this reason, I'm going to independently manage the example application, which we had been developing informally as a sub-repository, as a repository named walking_tracker. I'd really appreciate it if you could take this into consideration.
Setup the New Architecture
-
Applying a new architecture to React Native applications (Common)
- React Native released the support for the New Architecture with the release
0.68.0
. - This is written with the expectation that you’re using the latest React Native release.
- You can find instructions on how to upgrade in the page upgrading to new versions.
- write all JS bridges with TypeScript (or Flow.js) because Codegen requires explicitly defined types. As you know, JavaScript is a dynamically typed language, so it is not possible to generate code.
- use hermes and flipper debugging tools.
- React Native released the support for the New Architecture with the release
-
Applying a new architecture to React Native iOS applications
1. set platform version to 12.4 or higher. (min_ios_version_supported)
- platform :ios, '11.0' + platform :ios, '12.4' # ↓ or you can use the variable of (react_native_pods.rb) + platform :ios, min_ios_version_supported
2. set NODE_BINARY to .xcode.env file.
echo 'export NODE_BINARY=$(command -v node)' > .xcode.env
3. Fix an API Change in the
AppDelegate.m
file.- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif }
4. Rename all Objective-C(.m) files to Objective-C++ (.mm) 5. Make your AppDelegate conform to RCTAppDelegate
-
ios/StepCounterExample/AppDelegate.h
- #import <React/RCTBridgeDelegate.h> + #import <RCTAppDelegate.h> #import <UIKit/UIKit.h> - @interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate> + @interface AppDelegate : RCTAppDelegate - @property (nonatomic, strong) UIWindow *window; @end
-
ios/StepCounterExample/AppDelegate.mm
#import "AppDelegate.h" #import <React/RCTBundleURLProvider.h> @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.moduleName = @"StepCounterExample"; self.initialProps = @{}; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } - (BOOL)concurrentRootEnabled { return true; } @end
-
Run
pod install
export RCT_NEW_ARCH_ENABLED=1 cd ios && pod install
-
-
Applying a new architecture to React Native Android applications
- If your project has React Native later than
v0.71.0
, you already meet all the prerequisites to use the New Architecture on Android. - You will only need to set
newArchEnabled
totrue
in yourandroid/gradle.properties
file.
- If your project has React Native later than
If you prefer to read the official documentation, you can find it here.
ANDROID
3 uses-permission, 3 uses-feature
<!-- android/src/main/AndroidManifest.xml-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.stepcounter">
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND" />
<uses-feature
android:name="android.hardware.sensor.stepcounter"
android:required="false" />
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="true" />
</manifest>
iOS
set NSMotionUsageDescription
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<plist version="1.0">
...
<key>NSMotionUsageDescription</key>
<string>We want to access your motion data to count your steps.</string>
...
</plist>
Interface
-
isStepCountingSupported()
: Promise<Record<string, boolean>>: method to check if the device has a feature related step counter or accelerometer.- One key for the response object is
granted
, whether the app user has granted this feature permission, andsupported
is whether the device supports this feature. - This NativeModule can apply algorithms to a raw accelerometer to extract walking event data without activity sensor privileges, regardless of this response, but it is not recommended. You must write a code that stops tracking sensor events if user denies read-permission - even if you can do that.
- One key for the response object is
-
startStepCounterUpdate(start: Date, callBack: StepCountUpdateCallback)
: EmitterSubscription:- If the pedometer sensor is available and supported on the device, register it with the listener in the sensor manager, and return the step count event listener.
- If the pedometer sensor is not supported by the device or is not available, register the accelerometer sensor with the listener, generate a accel event through an vector algorithm filter and receive it to the app.
-
stopStepCounterUpdate(): void
:- unregister registered listener from
sensorManager
and release it.
- unregister registered listener from
-
StepCountData
:-
Common Interface
-
steps
: This is a number property that indicates the number of steps taken by the user during the specified time period. -
startDate
: This is a number property that indicates the start date of the data in Unix timestamp format, measured in milliseconds. -
endDate
: This is a number property that indicates the end date of the data in Unix timestamp format, measured in milliseconds. -
distance
: This is a number property that indicates the distance in meters that the user has walked or run during the specified time period. -
counterType
: The name of the sensor used to count the number of steps. In iOS, only theCMPedometer
is returned, and in Android, theStepCounter
orAccelerometer
is returned depending on the device state.
-
-
iOS Only
-
floorsAscended
: This is a number property that indicates the number of floors the user has ascended during the specified time period. it can be nil if the device does not support this feature. -
floorsDescended
: This is a number property that indicates the number of floors the user has descended during the specified time period. it can be nil if the device does not support this feature. -
currentPace
: (iOS 9.0+) This is a number property that indicates the current pace of the user in meters per second. -
currentCadence
: (iOS 9.0+) This is a number property that indicates the current cadence of the user in steps per second. -
averageActivePace
: (iOS 10.0+) This is a number property that indicates the average pace of the user in meters per second.
-
-
Usage
To use the Step Counter Library in your React Native app, follow these steps:
Import the library into your React Native app.
import React, { useEffect, useState } from 'react';
import {
isStepCountingSupported,
parseStepData,
startStepCounterUpdate,
stopStepCounterUpdate,
} from '@uguratakan/react-native-step-counter-improved';
Use the isStepCountingSupported
method to check if the device has a step counter or accelerometer sensor.
const [supported, setSupported] = useState(false);
const [granted, setGranted] = useState(false);
async function askPermission() {
isStepCountingSupported().then((result) => {
console.debug('🚀 - isStepCountingSupported', result);
setGranted(result.granted === true);
setSupported(result.supported === true);
});
}
Call the startStepCounterUpdate
method to start the step counter service.
const [steps, setSteps] = useState(0);
async function startStepCounter() {
startStepCounterUpdate(new Date(), (data) => {
console.debug(parseStepData(data));
setSteps(data.steps);
});
}
Here's an example of a complete React component that uses the NativeStepCounter
.
Link to Example Application: here
Change Log
See the Release Notes
for a list of changes.
Contributing
See the Contributing Guide
to learn how to contribute to the repository and the development workflow.
License
MIT
Made with create-react-native-library