I've developed an application that needs to continuously track and share a user's location and speed with a server in real-time. For this purpose, the app runs a foreground service and utilizes WebSocket for live data sharing. However, I've encountered two main challenges:
- There might be instances when the device loses internet connectivity while attempting to send data.
- The user may not use their phone for several hours, leading to the device's screen turning off.
Approaches to solve these challenges:
For the first challenge, if the device lacks internet access, the data is temporarily stored in the local database. Once internet connectivity is restored, the stored data is automatically sent to the server.
For the second challenge, I request additional permissions from the user and include them in the Manifest.xml, such as android.permission.WAKE_LOCK to keep the phone awake and android.permission.ACCESS_BACKGROUND_LOCATION to receive location updates in the background.
Issue:
The problem occurs when the application successfully receives data for about an hour and a half but then fails to continue operating in the foreground, leading to the service being terminated.
Code Snippets:
I'm using flutter_foreground_task. Below is a snippet from the CustomTaskHandler class, where I send the data to the server in the onRepeatEvent method. This method retrieves the current location of the user and attempts to send it via WebSocket. If the transmission fails, the data is saved in the local database.
class CustomTaskHandler extends TaskHandler {
...
@override
void onRepeatEvent(DateTime timestamp, SendPort? sendPort) async {
final locationData = await locationService.getCurrentLocation();
if (locationData != null) {
log(">> Current Location: (${locationData.latitude}, ${locationData.longitude})");
FlutterForegroundTask.updateService(
notificationTitle: 'Current Location ($count): (${locationData.latitude}, ${locationData.longitude})',
);
final formattedTimestamp = DateFormat('yyyy-MM-dd HH:mm:ss').format(timestamp);
final locationMap = {
'latitude': locationData.latitude,
'longitude': locationData.longitude,
'speed': locationData.speed,
'created_at': formattedTimestamp.toString()
};
final hasInternetConnection = await checkInternetConnection();
if (hasInternetConnection) {
log(">> Send via websocket.");
_initWebsocket();
websocket.sendMessage(locationMap);
} else {
locationRepository.insertRecord(
speed: locationMap['speed'].toString(),
latitude: locationMap['latitude'].toString(),
longitude: locationMap['longitude'].toString(),
createdAt: locationMap['created_at'].toString(),
)
.then((_) => log(">> Record inserted successfully"))
.catchError((error) => log(">> Error inserting record: $error"));
}
sendPort?.send(locationMap);
}
}
The complete code, along with a demo, is available on my repository.
Question:
Do you have any suggestions on how to ensure that the foreground service continues to run and transmit data without being interrupted, especially after long periods of inactivity or when the device is not in use?