Absolute Sensor Flutter Plugin

pub.dev

Absolute Sensor provides unified access to device motion and orientation sensors on Android, iOS, and Web with strongly-typed data models.

🚀 App using Gyroscope to power the card animation 🚀

Features

  • RPC Methods

    • isSensorAvailable(int sensorType) → Future<bool>

    • setSensorUpdateInterval(int sensorType, int intervalMicros) → Future<void>

  • Streams

    • Accelerometer → Stream<SensorData>

    • User Accelerometer (Linear Acceleration) → Stream<SensorData>

    • Gyroscope → Stream<SensorData>

    • Magnetometer → Stream<SensorData>

    • Orientation → Stream<OrientationData> (roll, yaw, pitch relative to device)

    • Absolute Orientation → Stream<OrientationData> (roll, yaw, pitch relative to magnetic north)

    • Screen Orientation → Stream<double> (0°, 90°, 180°, –90°)

  • Data Models

    class SensorData {
      final double x, y, z;
      SensorData({ required this.x, required this.y, required this.z });
    }
    
    class OrientationData {
      final double roll, yaw, pitch;
      OrientationData({ required this.roll, required this.yaw, required this.pitch });
    }
    

Installation

  1. Add to pubspec.yaml

    
    dependencies:
      absolute_sensor: ^1.0.1
    
    
  2. Fetch dependencies

    
    flutter pub get
    
    

Usage

Import

'package:absolute_sensor/absolute_sensor.dart';

Check Sensor Availability

const TYPE_ACCELEROMETER        = 1;
const TYPE_MAGNETIC_FIELD       = 2;
const TYPE_GYROSCOPE            = 4;
const TYPE_USER_ACCELEROMETER   = 10;
const TYPE_ORIENTATION          = 11;
const TYPE_ABSOLUTE_ORIENTATION = 15;

bool hasAccel = await AbsoluteSensor.isSensorAvailable(TYPE_ACCELEROMETER);

Set Update Interval

// interval in microseconds (e.g. 16000 ≈ 60 Hz)
await AbsoluteSensor.setSensorUpdateInterval(TYPE_ACCELEROMETER, 16000);

Listen to Sensor Streams

// Accelerometer
final subAccel = AbsoluteSensor.accelerometerEvents.listen((SensorData d) {
  print('Accel → x:${d.x}, y:${d.y}, z:${d.z}');
});

// Orientation
final subOrient = AbsoluteSensor.orientationEvents.listen((OrientationData o) {
  print('Orientation → roll:${o.roll}, yaw:${o.yaw}, pitch:${o.pitch}');
});

// Screen rotation
final subScreen = AbsoluteSensor.screenOrientationEvents.listen((angle) {
  print('Screen rotated to $angle°');
});

Remember to cancel your subscriptions in dispose():

subAccel.cancel();
subOrient.cancel();
subScreen.cancel();

Platform Notes

Android & iOS

  • No additional setup required.

  • iOS: CoreMotion APIs require no special permissions.

  • Android: Sensors are available on most devices; check availability first.

Web

  • Uses package:web + dart:js_interop.

  • No dart:html import.

  • Listens to browser events:

    • devicemotion for accelerometer & gyroscope

    • deviceorientation for orientation

    • screen.orientation.change for screen rotation

  • Requires HTTPS or localhost for real device sensors.


Example

import 'dart:async';

import 'package:absolute_sensor/absolute_sensor.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _text = 'Waiting…';
  late StreamSubscription<SensorData> _accelSub;

  @override
  void initState() {
    super.initState();
    AbsoluteSensor.isSensorAvailable(1).then((ok) {
      if (ok) {
        _accelSub = AbsoluteSensor.accelerometerEvents.listen((d) {
          setState(() {
            _text = 'x:${d.x.toStringAsFixed(1)}, '
                'y:${d.y.toStringAsFixed(1)}, '
                'z:${d.z.toStringAsFixed(1)}';
          });
        });
      } else {
        setState(() => _text = 'No accelerometer');
      }
    });
  }

  @override
  void dispose() {
    _accelSub.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext c) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('AbsoluteSensor Demo')),
        body: Center(child: Text(_text, style: const TextStyle(fontSize: 24))),
      ),
    );
  }
}

Feel free to adapt and contribute via pull requests!