Flutter移动感知插件carp_mobile_sensing的使用
Flutter移动感知插件carp_mobile_sensing的使用
简介
carp_mobile_sensing
是一个用于跨平台(iOS和Android)移动感知的核心Flutter包。它支持通过定义研究协议来收集各种传感器数据。
使用步骤
-
添加依赖: 在你的
pubspec.yaml
文件中添加以下依赖:dependencies: carp_core: ^latest carp_mobile_sensing: ^latest
-
配置应用:
- CAMS依赖于
flutter_local_notifications
插件,因此需要根据其文档进行配置。 - 对于Android和iOS平台,需要在相应的配置文件中添加权限和接收器。
- CAMS依赖于
Android集成
-
设置最低SDK版本为26,并在
build.gradle
文件中设置minSdkVersion
,compileSdkVersion
和targetSdkVersion
。 -
在
manifest.xml
中添加必要的权限:<!-- 用于活动识别(步数统计) --> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/> <!-- 用于发送和调度通知 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.USE_EXACT_ALARM" /> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" android:maxSdkVersion="32" />
-
在
<application>
标签之间添加以下内容以显示计划的通知:<!-- 用于调度通知 --> <receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" /> <receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/> <action android:name="android.intent.action.QUICKBOOT_POWERON" /> <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/> </intent-filter> </receiver>
iOS集成
-
在
Info.plist
文件中添加以下键值对:<key>NSMotionUsageDescription</key> <string>此应用程序跟踪您的步数</string>
示例代码
以下是一个简单的示例,展示了如何使用 carp_mobile_sensing
进行步数、环境光、屏幕事件和电池事件的采样:
import 'package:carp_serializable/carp_serializable.dart';
import 'package:carp_core/carp_core.dart';
import 'package:carp_mobile_sensing/carp_mobile_sensing.dart';
import 'package:flutter/material.dart' hide TimeOfDay;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
CarpMobileSensing.ensureInitialized();
runApp(const CARPMobileSensingApp());
}
class CARPMobileSensingApp extends StatelessWidget {
const CARPMobileSensingApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) => MaterialApp(
title: 'CARP Mobile Sensing Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const ConsolePage(title: 'CARP Mobile Sensing Demo'),
);
}
class ConsolePage extends StatefulWidget {
final String title;
const ConsolePage({super.key, required this.title});
[@override](/user/override)
Console createState() => Console();
}
class Console extends State<ConsolePage> {
String _log = '';
[@override](/user/override)
void initState() {
super.initState();
Settings().debugLevel = DebugLevel.debug;
Settings().init().then((_) {
Sensing().init().then((_) {
log('Client state : ${SmartPhoneClientManager().state}');
});
});
}
[@override](/user/override)
void dispose() {
Sensing().dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: SingleChildScrollView(
child: StreamBuilder(
stream: SmartPhoneClientManager().measurements,
builder: (context, AsyncSnapshot<Measurement> snapshot) => Text(
(snapshot.hasData)
? _log += toJsonString(snapshot.data)
: _log),
),
),
floatingActionButton: FloatingActionButton(
onPressed: restart,
tooltip: '开始/停止研究',
child: Sensing().isRunning
? const Icon(Icons.stop)
: const Icon(Icons.play_arrow),
),
);
void log(String msg) => setState(() => _log += '$msg\n');
void clearLog() => setState(() => _log = '');
void restart() {
debug('>> status: ${Sensing().isRunning}');
Sensing().isRunning ? Sensing().stop() : Sensing().start();
setState(() {}); // 更新播放/停止图标
}
}
class Sensing {
static final Sensing _instance = Sensing._();
Sensing._() {
ExecutorFactory().registerTriggerFactory(RemoteTriggerFactory());
}
factory Sensing() => _instance;
Study? study;
Future<void> init() async {
final protocol = await LocalStudyProtocolManager().getStudyProtocol('');
SmartPhoneClientManager().configure().then((_) => SmartPhoneClientManager()
.addStudyFromProtocol(protocol)
.then((value) => study = value));
SmartPhoneClientManager()
.measurements
.listen((data) => print(toJsonString(data)));
}
bool get isRunning =>
SmartPhoneClientManager().state == ClientManagerState.started;
void start() => SmartPhoneClientManager().start();
void stop() => SmartPhoneClientManager().stop();
void dispose() => SmartPhoneClientManager().dispose();
}
class LocalStudyProtocolManager implements StudyProtocolManager {
[@override](/user/override)
Future<void> initialize() async {}
[@override](/user/override)
Future<SmartphoneStudyProtocol> getStudyProtocol(String id) async {
SmartphoneStudyProtocol protocol = SmartphoneStudyProtocol(
ownerId: 'AB',
name: 'Protocol - id: $id',
dataEndPoint: SQLiteDataEndPoint());
var phone = Smartphone();
protocol.addPrimaryDevice(phone);
protocol.addParticipantRole(ParticipantRole('Participant'));
protocol.addTaskControl(
ImmediateTrigger(),
BackgroundTask(measures: [
Measure(type: DeviceSamplingPackage.FREE_MEMORY)
..overrideSamplingConfiguration = IntervalSamplingConfiguration(
interval: const Duration(seconds: 10)),
Measure(type: DeviceSamplingPackage.BATTERY_STATE),
Measure(type: DeviceSamplingPackage.SCREEN_EVENT),
Measure(type: SensorSamplingPackage.STEP_COUNT),
Measure(type: SensorSamplingPackage.AMBIENT_LIGHT)
..overrideSamplingConfiguration = PeriodicSamplingConfiguration(
interval: const Duration(seconds: 20),
duration: const Duration(seconds: 5),
),
]),
phone,
);
return protocol;
}
[@override](/user/override)
Future<bool> saveStudyProtocol(String studyId, StudyProtocol protocol) async {
throw UnimplementedError();
}
}
更多关于Flutter移动感知插件carp_mobile_sensing的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter移动感知插件carp_mobile_sensing的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用Flutter移动感知插件carp_mobile_sensing
的示例代码案例。这个插件允许开发者从用户的移动设备上收集各种传感器数据,例如加速度计、陀螺仪、位置信息等。
首先,确保你已经在pubspec.yaml
文件中添加了carp_mobile_sensing
依赖:
dependencies:
flutter:
sdk: flutter
carp_mobile_sensing: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
以下是一个简单的示例应用,展示了如何使用carp_mobile_sensing
插件来收集加速度计数据:
import 'package:flutter/material.dart';
import 'package:carp_core/carp_core.dart';
import 'package:carp_mobile_sensing/carp_mobile_sensing.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late SensingManager _sensingManager;
@override
void initState() {
super.initState();
// 初始化SensingManager
_sensingManager = SensingManager()
..registerTasks([
// 注册一个加速度计任务
AccelerometerTask(
name: 'accelerometer',
sampleRate: SampleRate(type: SampleRateType.fixed, value: 5.0), // 每秒5次采样
),
]);
// 开始收集数据
_sensingManager.start();
}
@override
void dispose() {
// 停止收集数据并清理资源
_sensingManager.stop();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('CARP Mobile Sensing Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Data collection is running...'),
ElevatedButton(
onPressed: () {
// 示例:停止并重新开始数据收集
_sensingManager.stop();
_sensingManager.start();
},
child: Text('Restart Data Collection'),
),
],
),
),
),
);
}
}
// 监听并处理数据
class AccelerometerTask extends Task {
@override
List<Probe> get requiredProbes => [
AccelerometerProbe(
name: 'accelerometer_probe',
sampleRate: sampleRate,
),
];
@override
void onData(DataPoint data) {
if (data is AccelerometerDataPoint) {
// 处理收集到的加速度计数据
print('Accelerometer Data: ${data.toJson()}');
}
}
}
注意:
AccelerometerTask
类实际上应该继承自Task
并覆盖其方法,但在这个例子中,为了简单起见,直接在MyApp
类中注册了加速度计任务。在实际应用中,你可能需要创建自己的任务类来管理不同的数据收集逻辑。onData
方法在这里没有直接在AccelerometerTask
中实现,因为carp_mobile_sensing
的API设计通常要求你通过ProbeSubscription
或类似机制来订阅数据。在这个简化的例子中,我们省略了这部分实现,仅用于展示如何注册任务。- 在实际应用中,你需要根据具体需求来处理数据,例如保存到数据库、发送到服务器等。
由于carp_mobile_sensing
的API可能会随着版本更新而变化,建议查阅最新的官方文档以获取最准确的信息和最佳实践。