Hello,
I wish to implement a countdown timer in Expo that counts down a number, second by second, and continues to do so when an app is out of focus / minimised. SetInterval does not work when an app is minimised (on Android 10+). This is natural behaviour for that OS due to power saving features etc.
Usually a foreground service would remedy this, as can be done in Java / Kotlin. It appears Expo does not support foreground services however, except for specific contexts such as location tracking and notifications.
I imagined Expo TaskManager would be the library to use for this scenario, but it also appears this is limited to location tracking and ‘background fetch’ tasks. Background-fetch tasks are designed to be run every 10/15 minutes on android, not second by second however, ruling this out.
May someone clarify:
-
Is ExpoTask Manager only available for use with ‘Location’ and ‘BackgroundFetch tasks’? The documentation says ‘Here is a list of Expo modules that use TaskManager’ and lists Location and BackgroundFetch. But that does not read as necessarily saying it only works with those two modules; just that those two modules make use of TaskManager… and a whole universe of custom code may work with it too. However, my attempts to write an ExpoTask which simply emits a console.log every second have failed… see sample below.
-
How would one go about building a function that can run at a frequent interval and continue once an app is minimised (no longer in ‘focus’)? Again a foreground service would be the answer, but as far as I can tell this is not supported in Expo without a location/notification use case.
This feels like a common enough scenario - to wish to continue running code, unrelated to location, when an app is not in focus. So I imagine Expo’s libraries can handle it.
Any thoughts much appreciated. I’ve tried putting SetInterval in all sorts of locations to no effect.
- SDK Version: 47.0.12
- Android/IOS
import React from "react";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import * as TaskManager from "expo-task-manager";
import { useKeepAwake } from 'expo-keep-awake';
const COUNTDOWN = "myTask";
var counter=50
var hasStarted=true
let MyTimer=undefined;
function ABackgroundTask() {
console.log("ABackgroundTask running")
useKeepAwake();
const startMyFunction = () => {
setInterval(() => {
counter-=1
console.log('Interval triggered. Counter is '+counter);
}, 1000);
//
};
const startCounting = () => {
hasStarted=true
startMyFunction();
};
return (
<View>
<TouchableOpacity onPress={startCounting}>
<Text style={styles.btnText}>Start Count</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
btnText: {
fontSize: 20,
backgroundColor: "green",
color: "white",
paddingHorizontal: 30,
paddingVertical: 10,
borderRadius: 5,
marginTop: 10,
},
});
TaskManager.defineTask(COUNTDOWN, () => {
MyTimer = setInterval(() => {
counter-=1
console.log('Alternative interval triggered. Counter is '+counter);
}, 1000);
MyTimer()
});
function myTask() {
setInterval(() => {
counter-=1
console.log('Second alternative interval triggered. Counter is '+counter);
}, 1000);
}
export default ABackgroundTask;