
Facilitates sensor data acquisition and management by supporting accelerometer, gyroscope, magnetometer, barometer, step counter, and location sensors, with built-in permission handling capabilities.
KSensor is a Kotlin Multiplatform library for observing device sensors and system states. Each sensor or state is grouped into its own plugin, allowing you to include only the features you need. This prevents pulling in unnecessary code and permissions.
All data emitted by plugins is wrapped in a KSensorResponse<T> which includes:
data: The actual sensor or state data.platform: The platform type (Android or iOS).timestamp: The system time when the data was collected.[!NOTE] Permissions: Plugins declare structured permission metadata. You can auto-generate
AndroidManifest.xmland iOSInfo.plistpermission snippets usingKSensor.permissionManifest()andKSensor.iosInfoPlistEntries(). For complete details and examples, see Permissions Handling.
The foundation of the library. It is required for all plugins.
Dependency:
implementation("io.github.shadadman:ksensor-core:version")object KSensor {
/**
* Flag to enable/disable "start on boot" for the entire library.
*/
var startOnBoot: Boolean
/**
* Registers a plugin.
* @param startOnBoot If true, this plugin will be marked to start automatically on device boot.
*/
fun register(plugin: KSensorPlugin, startOnBoot: Boolean = false)
/**
* Unregisters a plugin.
*/
fun unregister(id: PluginId)
/**
* Marks a plugin to start on boot or removes the mark.
*/
fun setStartOnBoot(id: PluginId, enable: Boolean)
/**
* Starts all plugins marked as "start on boot".
* Used only in Application class on Android and to achieve "start on boot" behavior on iOS.
*/
fun start()
/**
* Generates AndroidManifest.xml uses-permission tags snippet for registered or specified plugins.
*/
fun permissionManifest(
plugins: List<KSensorPlugin> = getRegisteredPlugins(),
includeOptional: Boolean = true,
includeComments: Boolean = true
): String
/**
* Generates iOS Info.plist usage description entries snippet for registered or specified plugins.
*/
fun iosInfoPlistEntries(
plugins: List<KSensorPlugin> = getRegisteredPlugins(),
includeOptional: Boolean = true,
includeComments: Boolean = true
): String
/**
* Debug utility that prints permission manifest entries for Android and iOS to stdout/console.
*/
fun printPermissionManifests(
plugins: List<KSensorPlugin> = getRegisteredPlugins()
)
}[!IMPORTANT] Android: To use "Start on Boot", you must register your plugins and call
KSensor.start()in yourApplicationclass. While the library handles the system boot broadcast automatically, callingstart()in your application class ensures that observations are resumed whenever the app process is created.iOS: iOS does not allow arbitrary code execution on boot. To achieve "Start on Boot" behavior, you must call
KSensor.start()in yourAppDelegate'sdidFinishLaunchingWithOptions. If you have background modes enabled (like Location or HealthKit), the system will relaunch your app into the background after a reboot, and callingKSensor.start()will resume observations.
These plugins provide access to hardware sensors for monitoring movement, environment, and health.
Provides access to hardware sensors for tracking movement.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-motion:version")Required Permissions:
ACTIVITY_RECOGNITION (Required for Step Counter)ACTIVITY_RECOGNITION (Motion & Fitness)Add the following to your AndroidManifest.xml:
android.permission.ACTIVITY_RECOGNITIONAdd the following key to your Info.plist:
NSMotionUsageDescription: Required for Step Counter and movement detection.Data Models (Wrapped in KSensorResponse):
Accelerometer(values: Vector3)
Gyroscope(values: Vector3)
StepCounter(steps: Int)
MotionDetector(type: MotionType) (Detects Walking, Running, Cycling, etc.)Provides data from sensors that monitor the ambient environment, such as pressure, light, proximity, and ambient noise.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-environment:version")Required Permissions:
RECORD_AUDIO (Only required if using the NoisePlugin)Add the following to your AndroidManifest.xml if you are using NoisePlugin:
android.permission.RECORD_AUDIOAdd the following key to your Info.plist if you are using NoisePlugin:
NSMicrophoneUsageDescription: Required for ambient noise measurement.Data Models (Wrapped in KSensorResponse):
Barometer(pressure: Float)
LightIlluminance(illuminance: Float)
Proximity(distanceInCM: Float, isNear: Boolean)
Noise(dB: Float, isLoud: Boolean, timestamp: Long?)
Provides location services and spatial orientation data.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-positioning:version")Required Permissions:
LOCATION
Add the following to your AndroidManifest.xml:
android.permission.ACCESS_FINE_LOCATIONandroid.permission.ACCESS_COARSE_LOCATIONData Models (Wrapped in KSensorResponse):
Location(latitude: Double?, longitude: Double?, altitude: Double?)
Magnetometer(values: Vector3)
Orientation(orientation: DeviceOrientation, orientationInt: Int)
Heading(magneticHeading: Double, trueHeading: Double, deviceHeading: Double, courseOverGround: Double)
LocationStatus(isLocationOn: Boolean)
Provides high-level data related to user input gestures.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-interaction:version")Required Permissions: None
Data Models (Wrapped in KSensorResponse):
TouchGestures(x: Float, y: Float, type: TouchGestureType)
ScrollStatus(horizontalPosition: Float, verticalPosition: Float, isScrolling: Boolean) (via scroll())[!NOTE]
scroll()reports the position of the most recently scrolled native container (Android:ScrollView,HorizontalScrollView,RecyclerView,ListView,WebView, ...; iOS: anyUIScrollView). Positions are in pixels on Android and points on iOS.isScrollingbecomesfalseonce scrolling has been idle for 300 ms.Important: This scroll observation is for native containers (
AndroidViewandUIKitView), not Jetpack Compose components. For Jetpack Compose, you can observe scroll position directly usingscrollState.value.
Provides access to health related data.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-health:version")Required Permissions:
BODY_SENSORS
CAMERA
Add the following to your AndroidManifest.xml:
android.permission.BODY_SENSORSandroid.permission.CAMERAandroid.permission.health.READ_HEART_RATE (Optional: for Health Connect / API 36+)Add the following keys to your Info.plist:
NSCameraUsageDescription: Required for Camera PPG.NSHealthUpdateUsageDescription & NSHealthShareUsageDescription: Required for HealthKit data.Data Models (Wrapped in KSensorResponse):
HeartRate(heartRate: Float, source: HeartRateSource, confidence: Float, quality: Float)
The Health plugin implements a robust fallback strategy for heart rate detection on phones:
What is PPG? PPG is a non-invasive method that uses a light source (the phone's flash) and a photodetector (the phone's camera) to measure the volumetric variations of blood circulation. By analyzing the "redness" of your finger over the camera lens, KSensor can estimate user heart rate with high precision using an advanced digital signal processing pipeline (Butterworth filters and adaptive peak detection).
These plugins provide monitoring for various device system and connectivity states.
Provides information about network connectivity and telephony call state on the device.
Dependency:
implementation("io.github.shadadman:ksensor-states-network:version")Required Permissions:
READ_PHONE_STATE (Only required if using callState())Add the following to your AndroidManifest.xml if using callState():
android.permission.READ_PHONE_STATEData Models (Wrapped in KSensorResponse):
ConnectivityStatus(isConnected: Boolean)
CurrentActiveNetwork(activeNetwork: ActiveNetwork) (Values: WIFI, CELLULAR, NONE)CallStateStatus(state: CallState, isInCall: Boolean) (CallState values: IDLE, RINGING, OFFHOOK, UNKNOWN)Provides access to general device system states like battery and volume.
Dependency:
implementation("io.github.shadadman:ksensor-states-system:version")Required Permissions: None
Data Models (Wrapped in KSensorResponse):
BatteryStatus(levelPercent: Int?, chargingState: ChargingState, health: BatteryHealth?, temperatureC: Float?)
VolumeStatus(volumePercentage: Int)
LocaleStatus(languageCode: String, countryCode: String, fullLocaleString: String, displayName: String, isRTL: Boolean)
ScreenStatus(isScreenOn: Boolean)
BrightnessStatus(screenBrightness: Int)
LockStatus(isDeviceLocked: Boolean)
PowerSaveStatus(isPowerSaveMode: Boolean)
StorageStatus(totalBytes: Long, usedBytes: Long, freeBytes: Long)
ResourcesStatus(cpuUsagePercent: Double, appCpuUsagePercent: Double, systemLoadAverage: List<Double>, memoryPressure: MemoryPressureLevel, memoryUsage: MemoryUsage)
Provides monitoring for BLE connection and discovery events.
Dependency:
implementation("io.github.shadadman:ksensor-states-bluetooth:version")Required Permissions:
BLUETOOTH
Add the following to your AndroidManifest.xml:
android.permission.BLUETOOTH_SCAN (API 31+)android.permission.BLUETOOTH_CONNECT (API 31+)android.permission.ACCESS_FINE_LOCATION (Required for discovery on older versions)Data Models (Wrapped in KSensorResponse):
BleConnectionStatus(connectedDevices: List<BleDevice>)
BleDiscoversStatus(discoveredDevices: List<BleDevice>)
BleDevice(id: String, name: String)
Tracks the visibility and lifecycle state of the application.
Dependency:
implementation("io.github.shadadman:ksensor-states-lifecycle:version")Required Permissions: None
Data Models (Wrapped in KSensorResponse):
AppVisibilityStatus(isAppVisible: Boolean)
KSensor registry to retrieve the plugin and observe its data using Kotlin Flow.Example to observe using State:
@Composable
fun OrientationSampleUsingState() {
// Register a plugin
val plugin = remember {
KSensor.get<PositioningPlugin>(PluginId.POSITIONING)
?: createPositioningPlugin().also { KSensor.register(it) }
}
// Use state
val orientation by plugin.orientation().collectAsState(null)
println("OrientationData as state: ${orientation?.data}")
}Example to observe using Effect:
@Composable
fun OrientationSampleUsingEffect() {
// Register a plugin
val plugin = remember {
KSensor.get<PositioningPlugin>(PluginId.POSITIONING)
?: createPositioningPlugin().also { KSensor.register(it) }
}
// Use effect
LaunchedEffect(plugin) {
plugin.orientation().collect {
println("OrientationData in effect: ${it.data}")
}
}
}Example to unregister a plugin:
KSensor.unregister(PluginId.POSITIONING)Some plugins require system permissions to function. Each plugin exposes a requiredPermissions list indicating what it needs, as well as permissionMetadata providing structured platform-level details (such as minSdkVersion/maxSdkVersion for Android and Info.plist usage description keys for iOS).
Instead of manually writing AndroidManifest.xml tags and iOS Info.plist usage descriptions, KSensor provides pure helper functions in the Core module to generate template-ready permission entries for all registered plugins (or a specified list of plugins).
// Generate AndroidManifest.xml uses-permission tags
val androidManifestSnippet: String = KSensor.permissionManifest(
includeOptional = true,
includeComments = true
)
// Generate iOS Info.plist usage description entries
val iosInfoPlistSnippet: String = KSensor.iosInfoPlistEntries(
includeOptional = true,
includeComments = true
)
// Debug utility to print permission entries for all registered plugins to console
KSensor.printPermissionManifests()File Path: composeApp/src/androidMain/AndroidManifest.xml (or app/src/main/AndroidManifest.xml)
Placement: Inside the <manifest> root tag, before or outside the <application> tag.
<!-- AndroidManifest.xml permissions for KSensor plugins -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:minSdkVersion="31" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" android:minSdkVersion="31" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />File Path: iosApp/iosApp/Info.plist (or iosApp/Info.plist)
Placement: Inside the top-level <dict> tag.
<!-- Info.plist permission entries for KSensor plugins -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app requires access to location services to track positioning data.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app requires background location access to track positioning data.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app requires Bluetooth access to observe Bluetooth state and connected devices.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires Microphone access to measure ambient sound levels.</string>Each permission requirement is represented as a structured PermissionMetadata instance with:
platform: TargetPlatform (ANDROID, IOS, or COMMON).permissionName: Platform identifier (e.g., android.permission.BLUETOOTH_SCAN or NSLocationWhenInUseUsageDescription).usageDescriptionKey & usageDescriptionDefault: Keys and default descriptions for iOS Info.plist or rationale dialogs.isRequired: Flag indicating whether the permission is strictly required or optional for the plugin.minSdkVersion & maxSdkVersion: Platform SDK version limits (e.g., Android API 31+ for Bluetooth scanning).To help AI agents (like Claude, GPT, or IDE assistants) understand and work with KSensor more effectively, we provide a SKILL section. You can inject these documents into your LLM's context to get high-quality code generation and architectural advice specific to KSensor.
SKILL.md and CONTRIBUTING_SKILL.md into your LLM's system prompt or context window.SKILL/ folder to provide the agent with deep knowledge of KSensor's plugin system and implementation details.CONTRIBUTING_SKILL.md when you want the LLM to help you write a new custom plugin for a specific sensor or platform state.Copyright (c) 2026 KSensor
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
KSensor is a Kotlin Multiplatform library for observing device sensors and system states. Each sensor or state is grouped into its own plugin, allowing you to include only the features you need. This prevents pulling in unnecessary code and permissions.
All data emitted by plugins is wrapped in a KSensorResponse<T> which includes:
data: The actual sensor or state data.platform: The platform type (Android or iOS).timestamp: The system time when the data was collected.[!NOTE] Permissions: Plugins declare structured permission metadata. You can auto-generate
AndroidManifest.xmland iOSInfo.plistpermission snippets usingKSensor.permissionManifest()andKSensor.iosInfoPlistEntries(). For complete details and examples, see Permissions Handling.
The foundation of the library. It is required for all plugins.
Dependency:
implementation("io.github.shadadman:ksensor-core:version")object KSensor {
/**
* Flag to enable/disable "start on boot" for the entire library.
*/
var startOnBoot: Boolean
/**
* Registers a plugin.
* @param startOnBoot If true, this plugin will be marked to start automatically on device boot.
*/
fun register(plugin: KSensorPlugin, startOnBoot: Boolean = false)
/**
* Unregisters a plugin.
*/
fun unregister(id: PluginId)
/**
* Marks a plugin to start on boot or removes the mark.
*/
fun setStartOnBoot(id: PluginId, enable: Boolean)
/**
* Starts all plugins marked as "start on boot".
* Used only in Application class on Android and to achieve "start on boot" behavior on iOS.
*/
fun start()
/**
* Generates AndroidManifest.xml uses-permission tags snippet for registered or specified plugins.
*/
fun permissionManifest(
plugins: List<KSensorPlugin> = getRegisteredPlugins(),
includeOptional: Boolean = true,
includeComments: Boolean = true
): String
/**
* Generates iOS Info.plist usage description entries snippet for registered or specified plugins.
*/
fun iosInfoPlistEntries(
plugins: List<KSensorPlugin> = getRegisteredPlugins(),
includeOptional: Boolean = true,
includeComments: Boolean = true
): String
/**
* Debug utility that prints permission manifest entries for Android and iOS to stdout/console.
*/
fun printPermissionManifests(
plugins: List<KSensorPlugin> = getRegisteredPlugins()
)
}[!IMPORTANT] Android: To use "Start on Boot", you must register your plugins and call
KSensor.start()in yourApplicationclass. While the library handles the system boot broadcast automatically, callingstart()in your application class ensures that observations are resumed whenever the app process is created.iOS: iOS does not allow arbitrary code execution on boot. To achieve "Start on Boot" behavior, you must call
KSensor.start()in yourAppDelegate'sdidFinishLaunchingWithOptions. If you have background modes enabled (like Location or HealthKit), the system will relaunch your app into the background after a reboot, and callingKSensor.start()will resume observations.
These plugins provide access to hardware sensors for monitoring movement, environment, and health.
Provides access to hardware sensors for tracking movement.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-motion:version")Required Permissions:
ACTIVITY_RECOGNITION (Required for Step Counter)ACTIVITY_RECOGNITION (Motion & Fitness)Add the following to your AndroidManifest.xml:
android.permission.ACTIVITY_RECOGNITIONAdd the following key to your Info.plist:
NSMotionUsageDescription: Required for Step Counter and movement detection.Data Models (Wrapped in KSensorResponse):
Accelerometer(values: Vector3)
Gyroscope(values: Vector3)
StepCounter(steps: Int)
MotionDetector(type: MotionType) (Detects Walking, Running, Cycling, etc.)Provides data from sensors that monitor the ambient environment, such as pressure, light, proximity, and ambient noise.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-environment:version")Required Permissions:
RECORD_AUDIO (Only required if using the NoisePlugin)Add the following to your AndroidManifest.xml if you are using NoisePlugin:
android.permission.RECORD_AUDIOAdd the following key to your Info.plist if you are using NoisePlugin:
NSMicrophoneUsageDescription: Required for ambient noise measurement.Data Models (Wrapped in KSensorResponse):
Barometer(pressure: Float)
LightIlluminance(illuminance: Float)
Proximity(distanceInCM: Float, isNear: Boolean)
Noise(dB: Float, isLoud: Boolean, timestamp: Long?)
Provides location services and spatial orientation data.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-positioning:version")Required Permissions:
LOCATION
Add the following to your AndroidManifest.xml:
android.permission.ACCESS_FINE_LOCATIONandroid.permission.ACCESS_COARSE_LOCATIONData Models (Wrapped in KSensorResponse):
Location(latitude: Double?, longitude: Double?, altitude: Double?)
Magnetometer(values: Vector3)
Orientation(orientation: DeviceOrientation, orientationInt: Int)
Heading(magneticHeading: Double, trueHeading: Double, deviceHeading: Double, courseOverGround: Double)
LocationStatus(isLocationOn: Boolean)
Provides high-level data related to user input gestures.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-interaction:version")Required Permissions: None
Data Models (Wrapped in KSensorResponse):
TouchGestures(x: Float, y: Float, type: TouchGestureType)
ScrollStatus(horizontalPosition: Float, verticalPosition: Float, isScrolling: Boolean) (via scroll())[!NOTE]
scroll()reports the position of the most recently scrolled native container (Android:ScrollView,HorizontalScrollView,RecyclerView,ListView,WebView, ...; iOS: anyUIScrollView). Positions are in pixels on Android and points on iOS.isScrollingbecomesfalseonce scrolling has been idle for 300 ms.Important: This scroll observation is for native containers (
AndroidViewandUIKitView), not Jetpack Compose components. For Jetpack Compose, you can observe scroll position directly usingscrollState.value.
Provides access to health related data.
Dependency:
implementation("io.github.shadadman:ksensor-sensors-health:version")Required Permissions:
BODY_SENSORS
CAMERA
Add the following to your AndroidManifest.xml:
android.permission.BODY_SENSORSandroid.permission.CAMERAandroid.permission.health.READ_HEART_RATE (Optional: for Health Connect / API 36+)Add the following keys to your Info.plist:
NSCameraUsageDescription: Required for Camera PPG.NSHealthUpdateUsageDescription & NSHealthShareUsageDescription: Required for HealthKit data.Data Models (Wrapped in KSensorResponse):
HeartRate(heartRate: Float, source: HeartRateSource, confidence: Float, quality: Float)
The Health plugin implements a robust fallback strategy for heart rate detection on phones:
What is PPG? PPG is a non-invasive method that uses a light source (the phone's flash) and a photodetector (the phone's camera) to measure the volumetric variations of blood circulation. By analyzing the "redness" of your finger over the camera lens, KSensor can estimate user heart rate with high precision using an advanced digital signal processing pipeline (Butterworth filters and adaptive peak detection).
These plugins provide monitoring for various device system and connectivity states.
Provides information about network connectivity and telephony call state on the device.
Dependency:
implementation("io.github.shadadman:ksensor-states-network:version")Required Permissions:
READ_PHONE_STATE (Only required if using callState())Add the following to your AndroidManifest.xml if using callState():
android.permission.READ_PHONE_STATEData Models (Wrapped in KSensorResponse):
ConnectivityStatus(isConnected: Boolean)
CurrentActiveNetwork(activeNetwork: ActiveNetwork) (Values: WIFI, CELLULAR, NONE)CallStateStatus(state: CallState, isInCall: Boolean) (CallState values: IDLE, RINGING, OFFHOOK, UNKNOWN)Provides access to general device system states like battery and volume.
Dependency:
implementation("io.github.shadadman:ksensor-states-system:version")Required Permissions: None
Data Models (Wrapped in KSensorResponse):
BatteryStatus(levelPercent: Int?, chargingState: ChargingState, health: BatteryHealth?, temperatureC: Float?)
VolumeStatus(volumePercentage: Int)
LocaleStatus(languageCode: String, countryCode: String, fullLocaleString: String, displayName: String, isRTL: Boolean)
ScreenStatus(isScreenOn: Boolean)
BrightnessStatus(screenBrightness: Int)
LockStatus(isDeviceLocked: Boolean)
PowerSaveStatus(isPowerSaveMode: Boolean)
StorageStatus(totalBytes: Long, usedBytes: Long, freeBytes: Long)
ResourcesStatus(cpuUsagePercent: Double, appCpuUsagePercent: Double, systemLoadAverage: List<Double>, memoryPressure: MemoryPressureLevel, memoryUsage: MemoryUsage)
Provides monitoring for BLE connection and discovery events.
Dependency:
implementation("io.github.shadadman:ksensor-states-bluetooth:version")Required Permissions:
BLUETOOTH
Add the following to your AndroidManifest.xml:
android.permission.BLUETOOTH_SCAN (API 31+)android.permission.BLUETOOTH_CONNECT (API 31+)android.permission.ACCESS_FINE_LOCATION (Required for discovery on older versions)Data Models (Wrapped in KSensorResponse):
BleConnectionStatus(connectedDevices: List<BleDevice>)
BleDiscoversStatus(discoveredDevices: List<BleDevice>)
BleDevice(id: String, name: String)
Tracks the visibility and lifecycle state of the application.
Dependency:
implementation("io.github.shadadman:ksensor-states-lifecycle:version")Required Permissions: None
Data Models (Wrapped in KSensorResponse):
AppVisibilityStatus(isAppVisible: Boolean)
KSensor registry to retrieve the plugin and observe its data using Kotlin Flow.Example to observe using State:
@Composable
fun OrientationSampleUsingState() {
// Register a plugin
val plugin = remember {
KSensor.get<PositioningPlugin>(PluginId.POSITIONING)
?: createPositioningPlugin().also { KSensor.register(it) }
}
// Use state
val orientation by plugin.orientation().collectAsState(null)
println("OrientationData as state: ${orientation?.data}")
}Example to observe using Effect:
@Composable
fun OrientationSampleUsingEffect() {
// Register a plugin
val plugin = remember {
KSensor.get<PositioningPlugin>(PluginId.POSITIONING)
?: createPositioningPlugin().also { KSensor.register(it) }
}
// Use effect
LaunchedEffect(plugin) {
plugin.orientation().collect {
println("OrientationData in effect: ${it.data}")
}
}
}Example to unregister a plugin:
KSensor.unregister(PluginId.POSITIONING)Some plugins require system permissions to function. Each plugin exposes a requiredPermissions list indicating what it needs, as well as permissionMetadata providing structured platform-level details (such as minSdkVersion/maxSdkVersion for Android and Info.plist usage description keys for iOS).
Instead of manually writing AndroidManifest.xml tags and iOS Info.plist usage descriptions, KSensor provides pure helper functions in the Core module to generate template-ready permission entries for all registered plugins (or a specified list of plugins).
// Generate AndroidManifest.xml uses-permission tags
val androidManifestSnippet: String = KSensor.permissionManifest(
includeOptional = true,
includeComments = true
)
// Generate iOS Info.plist usage description entries
val iosInfoPlistSnippet: String = KSensor.iosInfoPlistEntries(
includeOptional = true,
includeComments = true
)
// Debug utility to print permission entries for all registered plugins to console
KSensor.printPermissionManifests()File Path: composeApp/src/androidMain/AndroidManifest.xml (or app/src/main/AndroidManifest.xml)
Placement: Inside the <manifest> root tag, before or outside the <application> tag.
<!-- AndroidManifest.xml permissions for KSensor plugins -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:minSdkVersion="31" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" android:minSdkVersion="31" />
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />File Path: iosApp/iosApp/Info.plist (or iosApp/Info.plist)
Placement: Inside the top-level <dict> tag.
<!-- Info.plist permission entries for KSensor plugins -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app requires access to location services to track positioning data.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app requires background location access to track positioning data.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app requires Bluetooth access to observe Bluetooth state and connected devices.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires Microphone access to measure ambient sound levels.</string>Each permission requirement is represented as a structured PermissionMetadata instance with:
platform: TargetPlatform (ANDROID, IOS, or COMMON).permissionName: Platform identifier (e.g., android.permission.BLUETOOTH_SCAN or NSLocationWhenInUseUsageDescription).usageDescriptionKey & usageDescriptionDefault: Keys and default descriptions for iOS Info.plist or rationale dialogs.isRequired: Flag indicating whether the permission is strictly required or optional for the plugin.minSdkVersion & maxSdkVersion: Platform SDK version limits (e.g., Android API 31+ for Bluetooth scanning).To help AI agents (like Claude, GPT, or IDE assistants) understand and work with KSensor more effectively, we provide a SKILL section. You can inject these documents into your LLM's context to get high-quality code generation and architectural advice specific to KSensor.
SKILL.md and CONTRIBUTING_SKILL.md into your LLM's system prompt or context window.SKILL/ folder to provide the agent with deep knowledge of KSensor's plugin system and implementation details.CONTRIBUTING_SKILL.md when you want the LLM to help you write a new custom plugin for a specific sensor or platform state.Copyright (c) 2026 KSensor
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.