Motion Activity
Getting Started
Section titled “Getting Started”| GitHub | |
| Downloads |
Shiny provides cross-platform motion activity recognition, allowing your app to detect whether the user is walking, running, cycling, driving, or stationary.
- On iOS, this uses
CMMotionActivityManagerfrom the CoreMotion framework. - On Android, this uses Google Play Services Activity Recognition API.
Register motion activity recognition in MauiProgram.cs:
// Without a background delegateservices.AddMotionActivity();
// With a background delegate for processing activity changes in the backgroundservices.AddMotionActivity<MyMotionActivityDelegate>();Platform Permissions
Section titled “Platform Permissions”iOS: Add to Info.plist:
<key>NSMotionUsageDescription</key><string>This app uses motion activity to detect your movement type</string>Android: The ACTIVITY_RECOGNITION permission is required and will be requested automatically via RequestAccess().
Observing Motion Activity
Section titled “Observing Motion Activity”Foreground (C# Event)
Section titled “Foreground (C# Event)”Subscribe to MotionActivityReadingReceived to observe activity changes in the UI. Rx has been removed from Shiny.Locations — this is a plain event EventHandler<MotionActivityReading>.
public class MyViewModel : IDisposable{ readonly IMotionActivityManager activityManager;
public MyViewModel(IMotionActivityManager activityManager) { this.activityManager = activityManager; }
public async Task Start() { var access = await this.activityManager.RequestAccess(); if (access != AccessState.Available) return;
await this.activityManager.StartListener(); this.activityManager.MotionActivityReadingReceived += this.OnReading; }
public async Task Stop() { this.activityManager.MotionActivityReadingReceived -= this.OnReading; await this.activityManager.StopListener(); }
void OnReading(object? sender, MotionActivityReading reading) { // reading.Activity → MotionActivityType (Walking, Running, Cycling, etc.) // reading.Confidence → MotionActivityConfidence (Low, Medium, High) // reading.Timestamp → DateTimeOffset }
public void Dispose() => this.activityManager.MotionActivityReadingReceived -= this.OnReading;}Background (Delegate)
Section titled “Background (Delegate)”Implement IMotionActivityDelegate for processing activity changes even when the app is backgrounded:
public class MyMotionActivityDelegate : IMotionActivityDelegate{ readonly ILogger<MyMotionActivityDelegate> logger;
public MyMotionActivityDelegate(ILogger<MyMotionActivityDelegate> logger) { this.logger = logger; }
public Task OnReading(MotionActivityReading reading) { this.logger.LogInformation( "Activity: {Activity}, Confidence: {Confidence}", reading.Activity, reading.Confidence ); return Task.CompletedTask; }}Register the delegate:
services.AddMotionActivity<MyMotionActivityDelegate>();Surviving a process restart
Section titled “Surviving a process restart”IsListening is saved to Shiny’s settings store. If the OS ends the process while the listener is running, Shiny registers for activity updates again when the app next starts, and IsListening stays true until you call StopListener(). So check IsListening before calling StartListener(), which throws if a listener is already running:
if (!activityManager.IsListening) await activityManager.StartListener();On Android, the last reading is saved too, so GetLastReading() returns it after a restart. On iOS and Mac Catalyst, GetLastReading() asks CoreMotion for the last 10 minutes of activity instead.
API Reference
Section titled “API Reference”IMotionActivityManager
Section titled “IMotionActivityManager”| Member | Return Type | Description |
|---|---|---|
IsListening |
bool |
Whether the manager is listening. Saved across app restarts |
GetCurrentStatus() |
AccessState |
Get current permission status without prompting |
RequestAccess() |
Task<AccessState> |
Request permission to use motion activity |
GetLastReading() |
Task<MotionActivityReading?> |
Get the last known reading, querying the platform if needed |
MotionActivityReadingReceived |
event EventHandler<MotionActivityReading> |
Foreground stream of activity changes |
StartListener() |
Task |
Start listening for activity changes |
StopListener() |
Task |
Stop listening for activity changes |
MotionActivityType
Section titled “MotionActivityType”| Value | Description |
|---|---|
Unknown |
Activity could not be determined |
Stationary |
Device is not moving |
Walking |
User is walking |
Running |
User is running |
Cycling |
User is cycling |
Automotive |
User is in a vehicle |
MotionActivityConfidence
Section titled “MotionActivityConfidence”| Value | Description |
|---|---|
Low |
Low confidence in the detected activity |
Medium |
Medium confidence |
High |
High confidence |
AI Coding Assistant
Section titled “AI Coding Assistant”Step 1 — Add the marketplace:
claude plugin marketplace add shinyorg/skillsStep 2 — Install the plugin:
claude plugin install shiny@shinyOne plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.
Step 1 — Add the marketplace:
copilot plugin marketplace add https://github.com/shinyorg/skillsStep 2 — Install the plugin:
copilot plugin install shiny@shinyOne plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.


