wifi_ftm
A Flutter plugin for high-precision WiFi Fine Timing Measurement (FTM) and Round-Trip-Time (RTT) ranging on Android.
This package supports both the legacy IEEE 802.11mc standard and the new IEEE 802.11az (Next Generation Positioning) introduced in Android 15.
Warning
This package is only compatible with the Android platform. Support for other platforms will be implemented once the respective native APIs and OS vendor support are available.
Developed at UCLan Cyprus.
Features
- Capabilities Detection: Check if the device hardware supports WiFi RTT and 802.11az.
- Access Point Scanning: Discover nearby WiFi APs and identify RTT responders (MC/AZ).
- High-Precision Ranging: Sub-meter accuracy ranging to one or more access points simultaneously.
- Auto-Negotiation: Automatically uses 802.11az when both device and AP support it, falling back to 802.11mc.
- Detailed Metrics: Get distance, RSSI, standard deviation, and success rate for every ranging session.
Getting Started
Android Requirements
- Minimum SDK: 24 (Android 7.0)
- Compile SDK: 35 (Android 15) for 802.11az support.
- Hardware: The device must support the
PackageManager.FEATURE_WIFI_RTTsystem feature.
Permissions
Add the following permissions to your AndroidManifest.xml:
<!-- Required for WiFi Scanning and RTT -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- Required for Android 13+ -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
Note: WiFi RTT also requires Location Services to be enabled on the device.
Usage
Check Support and Capabilities
Before ranging, check if the device supports RTT and if permissions are granted.
final wifiFtm = WifiFtm();
// Quick support check
bool supported = await wifiFtm.isSupported();
// Detailed capabilities profile
FtmCapabilities capabilities = await wifiFtm.getCapabilities();
print("Android SDK: ${capabilities.androidVersion}");
print("Permissions Granted: ${capabilities.permissionsGranted}");
if (capabilities.isWifi80211azSupported) {
print("Next Gen Positioning (802.11az) is supported!");
}
Scan for Access Points
Scan to find responders that support the FTM protocol.
List<APScanResult> scanResults = await wifiFtm.scanAccessPoints();
for (var ap in scanResults) {
if (ap.is80211mcResponder || ap.is80211azResponder) {
print("Found RTT-capable AP: ${ap.ssid} (${ap.bssid})");
print("Security: ${ap.capabilities.join(', ')}");
}
}
Perform Ranging
Perform ranging towards a list of BSSIDs. The plugin handles the native RTT request and returns detailed results.
List<String> targets = ["00:11:22:33:44:55"];
List<RangingResult> results = await wifiFtm.startRanging(targets);
for (var res in results) {
if (res.status == RangingStatus.success) {
print("Distance: ${res.distanceMeters}m (+/- ${res.distanceStdDevMm}mm)");
print("RSSI: ${res.rssi} dBm");
print("Protocol: ${res.is80211azResult ? '802.11az' : '802.11mc'}");
} else {
print("Ranging failed for ${res.macAddress}");
}
}
Data
FtmCapabilities
Provides information about the device's RTT environment.
status: Map ofCapabilityenums (wifiRtt, wifi80211az).permissionsGranted: Current state of native permissions.androidVersion: System SDK level.isWifiRttSupported/isWifi80211azSupported: Convenience getters.
APScanResult
Represents an Access Point discovered during a scan.
ssid/bssid: Network identifiers.level: Signal strength (RSSI).frequency: Channel frequency in MHz.is80211mcResponder/is80211azResponder: Protocol support flags.capabilities: A parsedList<String>of security and network features (e.g.,WPA2-PSK,ESS).
RangingResult
The result of a ranging request to a specific AP.
distanceMm: Distance in millimeters.distanceMeters: Distance in meters (convenience getter).distanceStdDevMm: Standard deviation of the measurement.rssi: Signal strength during ranging.numSuccessfulMeasurements: Number of successful bursts.is80211azResult: True if the measurement used the 802.11az protocol.
Example & Permission handling
WiFi RTT operations are sensitive and require both system-level permissions and enabled services. For a complete implementation, check out the example project.
To manage permissions and services effectively in your app, we recommend using the following plugins:
- permission_handler: To request
Permission.locationandPermission.nearbyWifiDevices. - geolocator: To check if system-level Location Services are enabled.
- app_settings: To redirect users to system settings if permissions are denied.
Contributing
Contributions and suggestions are welcome! Please feel free to submit an issue/pull request.
License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.