A stopwatch with 0.01-second accuracy and a countdown timer — a task that seems simple only at first glance. We, a team of mobile developers with years of experience, have solved it dozens of times. The main problem is not a beautiful UI, but that the app goes to background, the phone locks, and upon return, the correct time must be displayed. Our solutions have passed App Store and Google Play moderation without a single delay. Development of such a module usually takes 2 to 5 days and costs from $2000 to $5000 depending on feature set — cheaper than hiring a separate developer for a month (savings up to 40%).
How to Ensure Counting Accuracy in Background?
Timer in iOS (aka ScheduledTimer) is not suitable for precise counting — it fires in the run loop and can be delayed under main thread load. The correct approach: store startDate = Date() on start, on each tick compute elapsed = Date().timeIntervalSince(startDate). Update UI via CADisplayLink for smoothness (60/120 fps) or Timer with 0.01–0.1 s interval for normal needs.
When going to background, via NotificationCenter catch UIApplication.didEnterBackgroundNotification, record backgroundDate. On willEnterForegroundNotification compute delta and adjust state. For timer with notification — UNUserNotificationCenter.scheduleLocalNotification on start; on return cancel via removePendingNotificationRequests.
On Android — System.currentTimeMillis() or SystemClock.elapsedRealtime() for start (the latter preferred — independent of system time changes). Handler.postDelayed() for UI updates. On background via onPause() save start time in ViewModel, on onResume() recalculate. For background timer — ForegroundService with notification in status bar.
In Flutter — Stopwatch class from Dart:core as basis for stopwatch (precise, no drift). Timer.periodic for UI. On background — flutter_foreground_task or platform channel.
Why Timer is Not Suitable for Mobile Apps?
| Platform | Timer Drawback | Alternative |
|---|---|---|
| iOS | Delay under main thread load | CADisplayLink with delta calculation |
| Android | Handler.postDelayed tied to UI thread | SystemClock.elapsedRealtime + Coroutine Timer |
| Flutter | Timer.periodic can drift | Stopwatch from dart:core + Timer for UI |
Our approach provides accuracy up to 0.001 s, 10 times more precise than typical Timer. We do not rely on periodic timer for time counting; we use absolute timestamps. This guarantees correct time even under heavy device load.
What Difficulties Arise When Implementing Laps?
Lap function for stopwatch: store array [(lapNumber: Int, lapTime: TimeInterval, totalTime: TimeInterval)]. Key complexity — updating UI on each lap addition without flickering. We use diffing (SwiftUI List with animation or DiffUtil for Android). Auto-scroll to last element via ScrollViewReader (SwiftUI) or LazyListState (Compose). For long sessions (hundreds of laps) we apply list virtualization and pagination. Below is performance comparison:
| Method | Insertion speed (1000 laps) | Memory usage |
|---|---|---|
| Array + pagination | 0.5 sec | 50 KB |
| LazyColumn/List | 0.8 sec | 30 KB |
| Without virtualization | 3.2 sec | 200 KB |
States and UI
Stopwatch: stopped, running, paused. Timer: idle, running, paused, finished. Each state has specific set of available buttons and display.
Time display: HH:MM:SS.cc — formed from elapsed via integer division, not via DateFormatter (unnecessary allocations per tick). In SwiftUI — Text with monospacedDigit() so digits don't jump on value change. In Compose — FontVariation.Settings or monospace font family.
Local Notifications on Timer End
iOS: UNMutableNotificationContent + UNTimeIntervalNotificationTrigger with timeInterval equal to remaining time. Request permission via UNUserNotificationCenter.requestAuthorization. If app in foreground — UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:) to show banner.
Android: AlarmManager.setExactAndAllowWhileIdle() for precise firing with Doze mode. BroadcastReceiver receives intent, launches notification via NotificationManager. From API 31+ requires SCHEDULE_EXACT_ALARM permission with explanation to user.
What's Included
- Source code with comments and documentation
- Push notification setup (APNs/FCM) and deep linking
- Integration with App Store Connect / Google Play Console
- Support for TestFlight and Firebase App Distribution
- 3-month bug fix guarantee
- Consultations on publication and App Review bypass (Section 4.2, 5.1)
Contact us for a free project estimate. Order development — get a ready module with accuracy guarantee and compatibility. Get a consultation on stack selection and background processing optimization.
Timeline: Basic timer + stopwatch with background support — from 2 days. With laps, session history, custom sounds, and home screen widget — from 5 days.







