Cả hai hệ điều hành đều hạn chế chạy nền để giữ pin — app không được tự chạy tuỳ ý, mà phải "xin" hệ thống qua API chuyên dụng. Điểm khác là mức độ kiểm soát:
Android — chọn theo loại việc:
- Việc ngắn khi app còn mở → coroutine/thread; không đảm bảo xong nếu app bị đóng.
- Việc hoãn được nhưng phải chạy chắc chắn (sync, upload log) → WorkManager: đặt constraint (có mạng, pin không yếu), tự retry, sống qua reboot. Việc định kỳ tối thiểu 15 phút.
- Việc dài người dùng đang theo dõi (phát nhạc, dẫn đường, ghi hình) → foreground service kèm notification bắt buộc.
iOS — chặt hơn:
- BGTaskScheduler: BGAppRefreshTask (làm mới ngắn) và BGProcessingTask (việc nặng, thường chạy khi sạc). Bạn chỉ xin, hệ thống tự quyết định giờ chạy dựa trên pin và thói quen dùng.
- Background modes khai báo trong Info.plist cho audio, location, VoIP — chỉ dùng khi app thật sự có tính năng đó, nếu không sẽ bị App Review từ chối.
- Người dùng vuốt tắt app trong app switcher → app bị dừng hẳn, task không chạy nữa.
App cross-platform: dùng thư viện bọc hai API trên, ví dụ expo-background-task (WorkManager + BGTaskScheduler; không chạy trên iOS simulator) hoặc workmanager cho Flutter. Việc cần chạy ngay theo sự kiện từ server → gửi push notification (data/silent push) thay vì poll.
Lưu ý: thiết kế theo hướng "chạy lúc nào cũng được": tác vụ phải idempotent, lưu tiến độ, và không hứa với người dùng một lịch chạy chính xác trên iOS.