Installation
Add movesense_plus to a Flutter app and configure Android and iOS for Bluetooth.
Setting up movesense_plus takes four steps: add the dependency, configure Android, configure iOS and request the Bluetooth permissions at runtime.
Add the dependency
The plugin requires Dart 3.12 or later and Flutter 3.44 or later. It bundles the Movesense mobile library (MDS) for both platforms: the mdslib AAR for Android and MovesenseMDS.xcframework for iOS. There is no Movesense SDK to download.
Upgrading from 1.x
Version 2.0 bundles the Movesense library and has a new API. Remove the library that you added for 1.x: the pod 'Movesense' line in ios/Podfile and the mdslib AAR in android/libs/ with its flatDir repository. See Migrate from 1.x.
Configure Android
The plugin and RxAndroidBle, the Bluetooth library that MDS uses, add these permissions to your app's manifest:
| Permission | Android versions | Purpose |
|---|---|---|
BLUETOOTH_SCAN | 12 or later | Find the sensor. The neverForLocation flag tells Android that the app does not derive location from scans. |
BLUETOOTH_CONNECT | 12 or later | Connect to the sensor. |
BLUETOOTH, BLUETOOTH_ADMIN | 11 and lower | Scan for and connect to the sensor before Android 12. |
ACCESS_FINE_LOCATION | 11 and lower | Get scan results before Android 12. |
ACCESS_COARSE_LOCATION | All | Declared by RxAndroidBle. The plugin does not need it. |
You do not add these permissions for the plugin, but your app must request some of them at runtime. See Request permissions at runtime.
If your app declares ACCESS_FINE_LOCATION itself, the manifest merger copies the plugin's android:maxSdkVersion="30" onto that entry. The app then has no precise location on Android 12 or later. To keep precise location for your app's own features, add tools:remove to the entry and declare the tools namespace:
The merger also adds the neverForLocation flag to a BLUETOOTH_SCAN entry of your own. If your app derives location from Bluetooth scans, add tools:remove="android:usesPermissionFlags" to that entry.
The plugin needs minSdk 24 or later. If android/app/build.gradle.kts sets a lower value, set minSdk to 24 or later.
The bundled Movesense library contains native code for arm64-v8a, armeabi-v7a and x86, but not for x86_64. Flutter builds Android apps for x86_64 as well, and that build fails at launch, when the plugin starts MDS. To leave x86 and x86_64 out of the APK and the app bundle, exclude their native libraries, as the plugin's example app does:
Restricting abiFilters in defaultConfig is not enough: Flutter adds x86_64 to the filters itself. An x86_64 Android emulator cannot run the app either way, so test on a physical phone, which Bluetooth needs anyway.
Configure iOS
Add the Bluetooth usage description to ios/Runner/Info.plist, inside the top-level <dict>:
iOS shows the text in its Bluetooth permission dialog, and it terminates an app that uses Bluetooth without the key. The plugin starts Core Bluetooth when the app starts, so iOS asks for Bluetooth access at the first launch, not at the first scan.
To keep data from the sensor coming while the app is in the background, also add the bluetooth-central mode:
If your app uses the sensor only in the foreground, leave the mode out.
In Xcode, the mode is Uses Bluetooth LE accessories under Signing & Capabilities → Background Modes. If UIBackgroundModes already exists, add bluetooth-central to its array.
The plugin needs iOS 15.0 or later. If your app targets an earlier version, select Runner → General in Xcode and set Minimum Deployments to 15.0 or later. The plugin builds with both CocoaPods and Swift Package Manager.
MovesenseMDS.xcframework has no build for the simulator on Apple silicon Macs, and the simulator has no Bluetooth, so run the app on an iPhone.
Request permissions at runtime
The plugin requests no permissions itself. On Android, your app must request these permissions before the first scan:
| Android version | Permissions | Reason |
|---|---|---|
| 12 or later | Permission.bluetoothScan, Permission.bluetoothConnect | Scanning needs BLUETOOTH_SCAN, and connecting needs BLUETOOTH_CONNECT. Android asks for both in one nearby devices dialog. |
| 11 and lower | Permission.locationWhenInUse | Scans return no results without location access. |
RxAndroidBle declares ACCESS_COARSE_LOCATION for every version, so on Android 12 or later a location request shows an approximate location dialog. The plugin does not need location on those versions, so the function below requests it only on Android 11 and lower.
On iOS, the system asks for Bluetooth access at the first launch, so your app requests nothing.
The function below uses permission_handler and device_info_plus. Add both plugins:
permission_handler requires compileSdk 37 or later. With a lower value, such as Flutter 3.47's default of 36, the Android build fails at the AAR metadata check. Set compileSdk in android/app/build.gradle.kts:
This function requests the permissions that the Android version needs:
API level 31 is Android 12. The function returns true on iOS and when the user allows every permission. Call it before startScan().
Without the permissions, a scan reports an error on Android 12 or later and finds no sensors on Android 11 and lower. On Android 11 and lower, a scan may also find nothing while location is turned off in the phone's settings.
The plugin's example app requests only the scan and connect permissions. To run it on Android 11 and lower, allow location for it in the system settings.
Troubleshooting
Set compileSdk to 37 or later, as Request permissions at runtime shows. permission_handler requires it, and Gradle stops with:
Run the app on a physical phone. The bundled Movesense library has no native code for x86_64, so the app cannot start on an x86_64 emulator. See Configure Android.
Request the location permission, and turn on location in the phone's settings. On Android 11 and lower, scans return results only with location access, and may return none while location is off. See Request permissions at runtime.
Remove movesense_plus from an app that uses carp_movesense_package 3.1.0. carp_movesense_package 3.1.0 depends on carp_movesense_flutter 0.1.x, the earlier name of this plugin, which bundles the same Movesense library. With Swift Package Manager, flutter build ios then fails with:
To find sensors in such an app, see Find the sensor.
Run the app on an iPhone. MovesenseMDS.xcframework has no build for the simulator on Apple silicon Macs, so linking fails:
Add NSBluetoothAlwaysUsageDescription to ios/Runner/Info.plist, as Configure iOS shows. The plugin starts Core Bluetooth when the app starts, and iOS terminates an app that uses Bluetooth without the key.
Next step
Quickstart
Build an app that prints the heart rate from a sensor.