Skip to main content

flutter_device_compass 2.2.0 copy "flutter_device_compass: ^2.2.0" to clipboard
flutter_device_compass: ^2.2.0 copied to clipboard

A Flutter compass plugin using device sensors. Heading is 0-360 degrees (0 = north).

flutter_device_compass #

pub package Platform License

A Flutter compass plugin using device sensors. Provides real-time device heading, orientation-compensated azimuth (0°–360°, where 0° is North), camera-mode heading for AR/camera overlays, and sensor accuracy.

Community-maintained fork of medyas/flutter_compass_v2 (lineage from hemanthrajv/flutter_compass), republished as flutter_device_compass on pub.dev for ongoing maintenance and modern Flutter (3.24+ / 3.44+) & Gradle/Kotlin compatibility.


Features #

  • 🧭 Heading Calculation: 0° to 360°, where 0° is North.
  • 📱 Orientation-Aware: Automatically compensates for device orientation changes (Portrait, Landscape Left, Landscape Right, Portrait Upside Down).
  • 📷 Camera Mode Heading: Heading out the back of the device (headingForCameraMode), ideal for Augmented Reality (AR) or camera overlays. On Android this uses SensorManager.remapCoordinateSystem(..., AXIS_X, AXIS_Z, ...) per platform docs.
  • 🎯 Sensor Accuracy: Exposes calibration and accuracy deviation in degrees (accuracy).
  • 🔍 Hardware Detection: Proactively check sensor availability via FlutterCompass.hasSensors before mounting compass views.
  • ⚡ Robust Sensor Fallbacks: Uses Sensor.TYPE_ROTATION_VECTOR on Android when available with low-pass filtered accelerometer + magnetometer fallback.
  • 🔋 Tunable updates: CompassUpdateOptions presets (fine 0.1° default, balanced 0.5°, batterySaver 1.0°) control heading filter, motion rate, and emit interval.
  • 🛡️ Crash-Resistant: Guarded against non-finite / NaN sensor readings and negative true headings.

Getting Started #

Add flutter_device_compass to your pubspec.yaml:

dependencies:
  flutter_device_compass: ^2.2.0

Platform Setup #

iOS #

iOS requires location permissions to deliver compass/heading updates via CoreLocation.

Add the following keys to your ios/Runner/Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to heading and compass data to orient the map.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to heading and compass data to orient the map.</string>

Note: Use a permission package like permission_handler to request location permissions at runtime before listening to compass events on iOS.

Android #

No additional permissions are strictly required for sensor access. However, if your app utilizes fine location for geomagnetic declination or maps alongside the compass, add the following to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Usage Examples #

Backward compatibility (no breaking change) #

Existing apps keep working with zero code changes:

// Legacy API — still valid. EventChannel listen args are null;
// native plugins apply built-in balanced defaults.
FlutterCompass.events?.listen((event) { /* ... */ });

New update tuning is opt-in via nullable [CompassUpdateOptions?]:

Call Platform listen arguments Behavior
FlutterCompass.events null Same as ≤2.1.1; native fine (0.1°) defaults
FlutterCompass.eventsFor() null Same as events
FlutterCompass.eventsFor(CompassUpdateOptions.balanced) { headingFilter, motionUpdateHz, updateIntervalMs } Custom profile
FlutterCompass.eventsFor(null) null Explicit legacy path

Native code treats each map field as optional: missing/null keys keep platform defaults. Old app binaries talking to a new plugin (or the reverse during upgrades) therefore stay safe as long as they use FlutterCompass.events.

1. Basic Stream Subscription #

import 'package:flutter_device_compass/flutter_device_compass.dart';

// Default — unchanged from older versions:
final subscription = FlutterCompass.events?.listen((CompassEvent event) {
  print('Heading: ${event.heading}°');
  print('Camera Mode Heading: ${event.headingForCameraMode}°');
  print('Accuracy Deviation: ±${event.accuracy}°');
});

// Optional new API (additive):
FlutterCompass.eventsFor(CompassUpdateOptions.balanced)?.listen((event) { /* ... */ });
FlutterCompass.eventsFor(CompassUpdateOptions.batterySaver)?.listen((event) { /* ... */ });
FlutterCompass.eventsFor(const CompassUpdateOptions(
  headingFilter: 0.1,
  motionUpdateHz: 30,
  updateIntervalMs: 33,
))?.listen((event) { /* ... */ });

// Cancel when no longer needed
// subscription?.cancel();
// Before switching profiles: cancel listeners, then FlutterCompass.resetEvents();
Preset headingFilter Typical feel Battery Defaults applied
CompassUpdateOptions.fine (default) 0.1° Very smooth / chatty needle; historical default Higher motion 30 Hz, emit ≥33 ms
CompassUpdateOptions.balanced 0.5° Smooth enough for most UIs Medium motion 20 Hz, emit ≥50 ms
CompassUpdateOptions.batterySaver 1.0° Slightly steppier; fewer callbacks Lower motion 15 Hz, emit ≥66 ms
  • iOS: headingFilter → CLLocationManager.headingFilter; motionUpdateHz → CoreMotion sample rate (camera heading); updateIntervalMs caps Flutter events.
  • Android: headingFilter is a minimum heading delta between emissions; updateIntervalMs sets emit throttle and sensor delay hint; motionUpdateHz is ignored.
  • When switching options at runtime, cancel the previous subscription (or call FlutterCompass.resetEvents() after cancel) so the EventChannel can restart with new args.

2. Building a Rotating Compass UI (StreamBuilder) #

import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_device_compass/flutter_device_compass.dart';

class CompassWidget extends StatelessWidget {
  const CompassWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<CompassEvent>(
      stream: FlutterCompass.events,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Center(child: Text('Error: ${snapshot.error}'));
        }

        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        }

        final heading = snapshot.data?.heading;

        // On devices without compass sensors, heading will be null
        if (heading == null) {
          return const Center(
            child: Text('Device does not have compass sensors'),
          );
        }

        return Center(
          child: Transform.rotate(
            angle: (heading * (math.pi / 180) * -1),
            child: Image.asset(
              'assets/compass.png',
              width: 250,
              height: 250,
            ),
          ),
        );
      },
    );
  }
}

3. Check Sensor Availability #

Before initiating compass-dependent features, you can verify if the device hardware supports compass sensors:

final bool? isSupported = await FlutterCompass.hasSensors;

if (isSupported == true) {
  print('Compass sensor is available on this device');
} else {
  print('Device does not support compass/heading sensors');
}

4. Read Current Heading Once #

If you only need a single heading snapshot (e.g. when capturing a photo or logging location):

Future<void> logCurrentHeading() async {
  final CompassEvent event = await FlutterCompass.events!.first;
  print('Current heading is: ${event.heading}°');
}

CompassEvent Reference #

Property Type Description
heading double? The device heading in degrees around its Z-axis (pointing direction of the top of the phone). Range: 0.0 to 360.0, where 0.0 is North. null if sensor is unavailable.
headingForCameraMode double? The heading in degrees out the back of the phone (rear camera / AR). Ideal for camera overlays.
accuracy double? Estimated deviation error in degrees (±). null if uncalibrated or unavailable.

Releases #

GitHub Releases / tags track pub.dev versions. Check Releases for changelogs per version.

Maintainer #

Maintained with ❤️ by Nafis Kabbo.

Contributions, issues, and feature requests are welcome on GitHub!

6
likes
160
points
7.68k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter compass plugin using device sensors. Heading is 0-360 degrees (0 = north).

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_device_compass

Packages that implement flutter_device_compass