Skip to content
Shiny.NET
Commercial SupportGuaranteed response times on Shiny bug fixes, straight from the maintainers. Plans from US$1,500 a year.See the plans

Motion Activity

GitHub GitHub stars for shinyorg/shiny
Downloads NuGet downloads for Shiny.Gps
Frameworks
.NET MAUI
Operating Systems
Android
iOS

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 CMMotionActivityManager from the CoreMotion framework.
  • On Android, this uses Google Play Services Activity Recognition API.

Register motion activity recognition in MauiProgram.cs:

// Without a background delegate
services.AddMotionActivity();
// With a background delegate for processing activity changes in the background
services.AddMotionActivity<MyMotionActivityDelegate>();

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().

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;
}

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>();

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.

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
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
Value Description
Low Low confidence in the detected activity
Medium Medium confidence
High High confidence
claude plugin marketplace add shinyorg/skills
claude plugin install shiny@shiny

One 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.

copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny@shiny

One 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.

View shiny-locations Skill