Skip to content
CARP Docs
Ask AISystemLightDark
On this page

Quickstart

Build a Flutter app that collects step, battery and app lifecycle data with CARP Mobile Sensing.

Copy MarkdownOpen inOpen in GitHubView as MarkdownOpen in Scira AIOpen in ChatGPTOpen in ClaudeOpen in Cursor

Build a Flutter app that collects step events, battery state and app lifecycle events (the app being opened or closed), and lists each measurement as it arrives. The data stays on the phone; to store it elsewhere, see Storing data.

Prerequisites

Use a physical device

Simulators have no step counter or real battery, so they produce very little data.

Build the app

  1. Create a Flutter app

    flutter create my_first_carp_app
    cd my_first_carp_app
  2. Add the CARP packages

    This downloads the packages from pub.dev and adds them to pubspec.yaml:

    flutter pub add carp_core carp_mobile_sensing
  3. Configure Android and iOS

    CARP uses platform features that need configuration on each platform.

    AndroidiOS

    To allow the app to count steps, add the activity recognition permission to android/app/src/main/AndroidManifest.xml, directly above <application:

    android/app/src/main/AndroidManifest.xml
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>

    Then enable core library desugaring in android/app/build.gradle.kts by adding the marked lines:

    android/app/build.gradle.kts
    android {
        compileOptions {
            isCoreLibraryDesugaringEnabled = true
            // ...leave the existing lines as they are
        }
        // ...
    }
    
    dependencies { 
        coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") 
    } 

    CARP requires iOS 15 or newer. Open ios/Runner.xcworkspace in Xcode, select Runner → General, and set Minimum Deployments to 15.0.

    To allow the app to count steps, add a motion usage description to ios/Runner/Info.plist, inside the <dict>:

    ios/Runner/Info.plist
    <key>NSMotionUsageDescription</key>
    <string>This app counts your steps for a research study.</string>
  4. Replace the app code

    Replace the contents of lib/main.dart with:

    lib/main.dart
    import 'package:flutter/material.dart';
    import 'package:carp_core/carp_core.dart';
    import 'package:carp_mobile_sensing/carp_mobile_sensing.dart';
    
    void main() => runApp(const MaterialApp(home: StepsPage()));
    
    class StepsPage extends StatefulWidget {
      const StepsPage({super.key});
    
      @override
      State<StepsPage> createState() => _StepsPageState();
    }
    
    class _StepsPageState extends State<StepsPage> {
      final List<String> _log = [];
    
      @override
      void initState() {
        super.initState();
        _startSensing();
      }
    
      Future<void> _startSensing() async {
        // 1. The study protocol: WHAT to collect.
        final protocol = SmartphoneStudyProtocol.local(
          name: 'My first study',
          measures: [
            Measure(type: SensorSamplingPackage.STEP_EVENT),
            Measure(type: DeviceSamplingPackage.APP_LIFECYCLE_EVENT),
            Measure(type: DeviceSamplingPackage.BATTERY_STATE),
          ],
        );
    
        // 2. The client: the engine that runs studies on this phone.
        final client = SmartPhoneClientManager();
        await client.configure();
    
        // 3. Add the study, deploy it and start collecting.
        final study = await client.addStudyFromProtocol(protocol);
        await client.tryDeployment(study.studyDeploymentId, study.deviceRoleName);
        client.resume();
    
        // 4. Every piece of data arrives here as a "measurement".
        client.measurements.listen((measurement) {
          setState(() => _log.insert(0, measurement.data.dataType.name));
        });
      }
    
      @override
      Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('My first CARP app')),
        body: ListView(children: [for (final line in _log) ListTile(title: Text(line))]),
      );
    }
  5. Run the app

    Connect your phone with a cable and run:

    flutter run

    The app requests permissions for notifications and physical activity. Allow them. Walk around, switch to another app and back, and stepevent, applifecycleevent and batterystate appear in the list.

How it works

The four numbered comments in lib/main.dart map to the core CARP workflow:

Step in the codeWhat it does
1. ProtocolDefines what to collect. SmartphoneStudyProtocol.local(...) is a shortcut for a protocol with only this phone, one participant, and data saved on the phone.
2. ClientSmartPhoneClientManager is the CAMS runtime. configure() starts it with default settings.
3. Add, deploy, resumeaddStudyFromProtocol() hands the protocol to the client, tryDeployment() prepares the sensors, and resume() starts collecting.
4. Measurementsclient.measurements is a live stream of everything collected. You can display, store or forward each measurement.

Every measurement is also saved in a database on the phone, and no data leaves the device. To store data elsewhere, see Storing data.

Add more data types

To collect other kinds of data, add a sampling package. For example, carp_context_package adds location and activity (walking, cycling and so on):

flutter pub add carp_context_package
import 'package:carp_context_package/carp_context_package.dart';

// At the top of _startSensing(), before creating the protocol:
SamplingPackageRegistry().register(ContextSamplingPackage());

// ...then add measures like:
Measure(type: ContextSamplingPackage.LOCATION),
Measure(type: ContextSamplingPackage.ACTIVITY),

Package permissions

Each sampling package may need its own permissions, for example for location. The package's page on pub.dev lists the configuration to add for Android and iOS.

Measure types lists every available measure, and the API reference lists all packages.

Next steps

Choose where data goes

Keep data on the phone, upload it to CAWS, or send it to your own server.

Collect more kinds of data

All measures, and the sampling packages that add them.

Schedule data collection

Triggers: every hour, at 8:00, when the participant is walking…

Ask the participant questions

Surveys and tasks the user is notified about.

Keep collecting in the background

Battery, background mode and notifications on Android and iOS.

Apple Watch

Collect sensor data from an Apple Watch. Packages for Polar, Movesense and other wearables are listed in the API reference.

How CARP fits together

The components and the study lifecycle, with diagrams.

Get help

Quick links

Page · DocumentationCARP DocumentationPage · DocumentationIntroductionPage · DocumentationQuickstartPage · DocumentationTerminologyPage · DocumentationArchitecture