アプリがバックグラウンドに入るとJSのタイマーが止まってしまう
前回の記事ではJavaScriptでタイマーを実装しましたが、それだとユーザーが端末のホームボタンを押して、iOSアプリがバックグラウンドに入るとタイマーが止まってしまいました。
上記のiOSアプリの前提としては、UIBackgroundModes
の設定がONになっていて、バックグラウンドで音源を再生し続ける機能を持っています。 (その条件なら)iOSネイティブのNSTimerを使えばタイマーがバックグラウンドで動作し続けるのですが、せっかくなのでReact Nativeのライブラリがないか探してみました。
今回はreact-native-background-timerというライブラリを見つけたので、それを使ってみました。
react-native-background-timer
react-native-background-timerの[iOSの実装](react-native-background-timer/RNBackgroundTimer.m at master · ocetnik/react-native-background-timer)を見たところ、beginBackgroundTaskWithName
を使ってバックグラウンドタスクを登録するようです。
iOSの仕様上、UIBackgroundModes
の一部のモード以外ではOSが長時間のバックグラウンド処理を止めてしまうということになっています。このライブラリを導入する際は、ネイティブ側も適切に設定する必要がありそうです(iOSのドキュメントやIssuesを参考)。
ライブラリ導入前
JavaScriptのタイマーを動かしていました。
let timer = null;
runPauseTimer(sec) {
clearTimeout(timer);
timer = setInterval(()=> {
// 略
}, 1000)
stopPauseTimer() {
clearTimeout(timer);
// 略
}
ライブラリ導入後
react-native-background-timerを導入します。
元の記述と殆ど変わっていませんが、BackgroundTimer
のclearTimeout
やsetInterval
を使います。
import BackgroundTimer from 'react-native-background-timer';
let timer = null;
runPauseTimer(sec) {
BackgroundTimer.clearTimeout(timer);
timer = BackgroundTimer.setInterval(()=> {
// 略
}, 1000)
stopPauseTimer() {
BackgroundTimer.clearTimeout(timer);
// 略
}
これで、アプリがバックグラウンドに入ってもタイマーが動作し続けるようになりました。
タイマー以外のバックグラウンドタスク系ライブラリ
余談ですが、Locationやbackground fetchなど、用途によっていくつかあるようです。
- transistorsoft/react-native-background-geolocation: Sophisticated, battery-conscious background-geolocation with motion-detection
- transistorsoft/react-native-background-fetch: iOS Background Fetch API Implementation