This guide shows how to install carp_mobile_sensing and configure a Flutter app on Android and iOS.

Install Package

Add CAMS dependencies to pubspec.yaml and fetch packages.

Configure Android

Configure permissions, services, and Gradle settings.

Configure iOS

Add Info.plist keys and AppDelegate notification setup.

Validate Setup

Build and verify permissions on physical devices.

1) Install the package

Add dependencies in pubspec.yaml:
environment:
  sdk: ">=3.10.0 <4.0.0"
  flutter: ">=3.19.0"
  
dependencies:
  flutter:
    sdk: flutter
  carp_serializable: ^latest
  carp_core: ^latest
  carp_mobile_sensing: ^latest
Then run:
flutter pub get
Use the example app as baseline:
  • /android/app/src/main/AndroidManifest.xml
  • /android/app/build.gradle.kts
  • /ios/Runner/Info.plist
  • /ios/Runner/AppDelegate.swift

2) Android configuration

1

Add required permissions

Include permissions for activity recognition, notifications, foreground execution, and battery behavior.
2

Configure plugin services/receivers

Add both flutter_background and flutter_local_notifications declarations in <application>.
3

Enable desugaring in Gradle

Add isCoreLibraryDesugaringEnabled = true and the desugar dependency in android/app/build.gradle.kts.

Android manifest permissions

Add permissions for:
  • activity recognition
  • notifications (including scheduled notifications)
  • foreground/background execution
  • foreground service types used by flutter_background
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>

<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" />

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
FOREGROUND_SERVICE_SPECIAL_USE must be aligned with the service subtype description shown to users.

Android services/receivers

Inside <application>, declare both plugin services:

flutter_background

<service
    android:name="de.julianassmann.flutter_background.IsolateHolderService"
    android:exported="false"
    android:foregroundServiceType="dataSync|specialUse">
    <property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
        android:value="Collection of data while app is in background."/>
</service>

flutter_local_notifications

<service
    android:name="com.dexterous.flutterlocalnotifications.ForegroundService"
    android:exported="false"
    android:stopWithTask="false"/>

<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>

Android Gradle setup

In android/app/build.gradle.kts, enable desugaring and add dependency (required by local notifications):
android {
  compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
  }
}

dependencies {
  coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
}

Android ic_launcher.png

Both the flutter_local_notification and the flutter_background plugins use the ic_launcher.png as the icon for notifications. Hence, this icon should be added as a drawable resource to the the Android head project in the android/app/src/main/res/drawable/ folder. You typically copy the /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png icon.

3) iOS configuration

1

Add Info.plist permissions

Add motion permission for step tracking and optional file-sharing keys.
2

Configure notifications in AppDelegate

Register flutter_local_notifications callback and keep plugin registration.

Info.plist keys

Add motion permission for step tracking:
<key>NSMotionUsageDescription</key>
<string>This application tracks your steps</string>
Optional (used in example to expose files in Finder):
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>

AppDelegate notification setup

For flutter_local_notifications, add plugin registrant callback:
import flutter_local_notifications

FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
  GeneratedPluginRegistrant.register(with: registry)
}
if #available(iOS 10.0, *) {
  UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
Then keep:
GeneratedPluginRegistrant.register(with: self)

4) Final checks

1

Refresh and resolve dependencies

flutter clean
flutter pub get
2

Build on each platform

flutter run -d android
flutter run -d ios
3

Verify runtime permissions

Grant notification and motion/activity permissions on device and confirm background behavior.
Important: Explicit plugin dependencies may be neededAs discussed in Issue #530, some projects may need to explicitly add plugin dependencies that CAMS uses transitively.If you see build/runtime plugin registration issues, add the required plugins directly in your app pubspec.yaml (for example flutter_local_notifications and flutter_background) and run:
flutter clean
flutter pub get