Flutter原生传感器访问插件ios_native_sensors的使用
Flutter原生传感器访问插件ios_native_sensors的使用
由 fluttercommunity/plus_plugins 项目提交 8f132a2
平台支持
仅限iOS
使用
部分符号已更改,请参阅示例代码以获取更多详细信息。如果您可以帮助我维护此插件,请联系我 @normidar。
TODO
- iOS 姿态传感器
完整示例Demo
示例代码
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ios_native_sensors/ios_native_sensors.dart';
import 'snake.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations(
[
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
],
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sensors Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0x9f4376f8),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String? title;
const MyHomePage({super.key, this.title});
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const Duration _ignoreDuration = Duration(milliseconds: 20);
static const int _snakeRows = 20;
static const int _snakeColumns = 20;
static const double _snakeCellSize = 10.0;
MotionEvent? _motionEvent;
GravityEvent? _accelerometerEvent;
RotationRateEvent? _gyroscopeEvent;
MagnetometerEvent? _magnetometerEvent;
DateTime? _userAccelerometerUpdateTime;
DateTime? _accelerometerUpdateTime;
DateTime? _gyroscopeUpdateTime;
DateTime? _magnetometerUpdateTime;
int? _userAccelerometerLastInterval;
int? _accelerometerLastInterval;
int? _gyroscopeLastInterval;
int? _magnetometerLastInterval;
final _streamSubscriptions = <StreamSubscription<dynamic>>[];
Duration sensorInterval = SensorInterval.normalInterval;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sensors Plus Example'),
elevation: 4,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(width: 1.0, color: Colors.black38),
),
child: SizedBox(
height: _snakeRows * _snakeCellSize,
width: _snakeColumns * _snakeCellSize,
child: Snake(
rows: _snakeRows,
columns: _snakeColumns,
cellSize: _snakeCellSize,
),
),
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Table(
columnWidths: const {
0: FlexColumnWidth(4),
4: FlexColumnWidth(2),
},
children: [
const TableRow(
children: [
SizedBox.shrink(),
Text('X'),
Text('Y'),
Text('Z'),
Text('Interval'),
],
),
TableRow(
children: [
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('UserAccelerometer'),
),
Text(_motionEvent?.userAcceleration.vector.x.toStringAsFixed(1) ?? '?'),
Text(_motionEvent?.userAcceleration.vector.y.toStringAsFixed(1) ?? '?'),
Text(_motionEvent?.userAcceleration.vector.z.toStringAsFixed(1) ?? '?'),
Text('${_userAccelerometerLastInterval?.toString() ?? '?'} ms'),
],
),
TableRow(
children: [
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('Accelerometer'),
),
Text(_accelerometerEvent?.vector.x.toStringAsFixed(1) ?? '?'),
Text(_accelerometerEvent?.vector.y.toStringAsFixed(1) ?? '?'),
Text(_accelerometerEvent?.vector.z.toStringAsFixed(1) ?? '?'),
Text('${_accelerometerLastInterval?.toString() ?? '?'} ms'),
],
),
TableRow(
children: [
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('Gyroscope'),
),
Text(_gyroscopeEvent?.vector.x.toStringAsFixed(1) ?? '?'),
Text(_gyroscopeEvent?.vector.y.toStringAsFixed(1) ?? '?'),
Text(_gyroscopeEvent?.vector.z.toStringAsFixed(1) ?? '?'),
Text('${_gyroscopeLastInterval?.toString() ?? '?'} ms'),
],
),
TableRow(
children: [
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('Magnetometer'),
),
Text(_magnetometerEvent?.vector.x.toStringAsFixed(1) ?? '?'),
Text(_magnetometerEvent?.vector.y.toStringAsFixed(1) ?? '?'),
Text(_magnetometerEvent?.vector.z.toStringAsFixed(1) ?? '?'),
Text('${_magnetometerLastInterval?.toString() ?? '?'} ms'),
],
),
],
),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('Update Interval:'),
SegmentedButton(
segments: [
ButtonSegment(
value: SensorInterval.gameInterval,
label: Text('Game\n(${SensorInterval.gameInterval.inMilliseconds}ms)'),
),
ButtonSegment(
value: SensorInterval.uiInterval,
label: Text('UI\n(${SensorInterval.uiInterval.inMilliseconds}ms)'),
),
ButtonSegment(
value: SensorInterval.normalInterval,
label: Text('Normal\n(${SensorInterval.normalInterval.inMilliseconds}ms)'),
),
const ButtonSegment(
value: Duration(milliseconds: 500),
label: Text('500ms'),
),
const ButtonSegment(
value: Duration(seconds: 1),
label: Text('1s'),
),
],
selected: {sensorInterval},
showSelectedIcon: false,
onSelectionChanged: (value) {
setState(() {
sensorInterval = value.first;
motionEventStream(samplingPeriod: sensorInterval);
accelerometerEventStream(samplingPeriod: sensorInterval);
gyroscopeEventStream(samplingPeriod: sensorInterval);
magnetometerEventStream(samplingPeriod: sensorInterval);
});
},
),
],
),
],
),
);
}
[@override](/user/override)
void dispose() {
super.dispose();
for (final subscription in _streamSubscriptions) {
subscription.cancel();
}
}
[@override](/user/override)
void initState() {
super.initState();
_streamSubscriptions.add(
motionEventStream(samplingPeriod: sensorInterval).listen(
(MotionEvent event) {
final now = DateTime.now();
setState(() {
_motionEvent = event;
if (_userAccelerometerUpdateTime != null) {
final interval = now.difference(_userAccelerometerUpdateTime!);
if (interval > _ignoreDuration) {
_userAccelerometerLastInterval = interval.inMilliseconds;
}
}
});
_userAccelerometerUpdateTime = now;
},
onError: (e) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Sensor Not Found"),
content: Text("It seems that your device doesn't support User Accelerometer Sensor\n$e"),
);
});
},
cancelOnError: true,
),
);
_streamSubscriptions.add(
accelerometerEventStream(samplingPeriod: sensorInterval).listen(
(GravityEvent event) {
final now = DateTime.now();
setState(() {
_accelerometerEvent = event;
if (_accelerometerUpdateTime != null) {
final interval = now.difference(_accelerometerUpdateTime!);
if (interval > _ignoreDuration) {
_accelerometerLastInterval = interval.inMilliseconds;
}
}
});
_accelerometerUpdateTime = now;
},
onError: (e) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
title: Text("Sensor Not Found"),
content: Text("It seems that your device doesn't support Accelerometer Sensor"),
);
});
},
cancelOnError: true,
),
);
_streamSubscriptions.add(
gyroscopeEventStream(samplingPeriod: sensorInterval).listen(
(RotationRateEvent event) {
final now = DateTime.now();
setState(() {
_gyroscopeEvent = event;
if (_gyroscopeUpdateTime != null) {
final interval = now.difference(_gyroscopeUpdateTime!);
if (interval > _ignoreDuration) {
_gyroscopeLastInterval = interval.inMilliseconds;
}
}
});
_gyroscopeUpdateTime = now;
},
onError: (e) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
title: Text("Sensor Not Found"),
content: Text("It seems that your device doesn't support Gyroscope Sensor"),
);
});
},
cancelOnError: true,
),
);
_streamSubscriptions.add(
magnetometerEventStream(samplingPeriod: sensorInterval).listen(
(MagnetometerEvent event) {
final now = DateTime.now();
setState(() {
_magnetometerEvent = event;
if (_magnetometerUpdateTime != null) {
final interval = now.difference(_magnetometerUpdateTime!);
if (interval > _ignoreDuration) {
_magnetometerLastInterval = interval.inMilliseconds;
}
}
});
_magnetometerUpdateTime = now;
},
onError: (e) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
title: Text("Sensor Not Found"),
content: Text("It seems that your device doesn't support Magnetometer Sensor"),
);
});
},
cancelOnError: true,
),
);
}
}
更多关于Flutter原生传感器访问插件ios_native_sensors的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter原生传感器访问插件ios_native_sensors的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
ios_native_sensors
是一个 Flutter 插件,用于在 iOS 设备上访问原生传感器数据。它允许开发者直接从 iOS 设备的硬件传感器(如加速度计、陀螺仪、磁力计等)获取数据,并将其集成到 Flutter 应用中。
以下是如何使用 ios_native_sensors
插件的步骤:
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 ios_native_sensors
插件的依赖:
dependencies:
flutter:
sdk: flutter
ios_native_sensors: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 导入插件
在需要使用传感器的 Dart 文件中导入插件:
import 'package:ios_native_sensors/ios_native_sensors.dart';
3. 初始化传感器
在使用传感器之前,需要先初始化。通常,你可以在 initState
方法中进行初始化:
class SensorPage extends StatefulWidget {
@override
_SensorPageState createState() => _SensorPageState();
}
class _SensorPageState extends State<SensorPage> {
IosNativeSensors _sensors = IosNativeSensors();
StreamSubscription<SensorEvent>? _subscription;
@override
void initState() {
super.initState();
_initializeSensors();
}
void _initializeSensors() async {
bool isAvailable = await _sensors.checkSensorAvailability(SensorType.accelerometer);
if (isAvailable) {
_subscription = _sensors.sensorEvents.listen((event) {
print("Sensor Data: ${event.data}");
});
} else {
print("Accelerometer not available");
}
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sensor Example'),
),
body: Center(
child: Text('Check console for sensor data'),
),
);
}
}
4. 监听传感器数据
在上面的代码中,我们使用 _sensors.sensorEvents.listen
来监听传感器数据。当传感器数据发生变化时,回调函数会被触发,你可以在回调函数中处理传感器数据。
5. 处理传感器数据
在 listen
回调中,你可以获取到 SensorEvent
对象,它包含了传感器类型和数据:
_subscription = _sensors.sensorEvents.listen((event) {
if (event.type == SensorType.accelerometer) {
print("Accelerometer Data: ${event.data}");
} else if (event.type == SensorType.gyroscope) {
print("Gyroscope Data: ${event.data}");
}
});
6. 释放资源
在 dispose
方法中,记得取消订阅以释放资源:
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
7. 支持的传感器类型
ios_native_sensors
插件支持多种传感器类型,包括:
SensorType.accelerometer
:加速度计SensorType.gyroscope
:陀螺仪SensorType.magnetometer
:磁力计SensorType.deviceMotion
:设备运动传感器
你可以通过 checkSensorAvailability
方法来检查设备是否支持某个传感器。
8. 处理权限
在 iOS 上,访问某些传感器可能需要用户授权。你需要在 Info.plist
文件中添加相应的权限描述:
<key>NSMotionUsageDescription</key>
<string>We need access to the motion sensors to provide certain features.</string>