Why Silent Push Fails: Real-World Cases
Silent push is a powerful tool for background sync, but implementation is full of pitfalls. According to statistics, improper silent push configuration leads to 40% of missed notifications on Android and up to 60% on iOS in complex scenarios. One of our clients, a delivery service with 500,000 users, faced an issue where after updating to Android 13, background notifications stopped waking the app — Doze Mode with new restrictions blocked high-priority messages due to the absence of setForegroundAsync call in an expedited worker. We reconfigured the handling and added the call — the problem was resolved. In this article, we’ll break down how to reliably set up background sync without user interaction and show how to avoid common mistakes. Our experience: 10+ years in mobile development, 50+ projects with push infrastructure.
Silent Push on iOS: Technical Details
On iOS, silent push requires the content-available: 1 flag in the payload and the “Remote notifications” Background Mode enabled in Xcode Capabilities.
APNs payload:
{ "aps": { "content-available": 1 }, "sync_type": "messages", "last_known_id": "msg_8823" } No alert, no sound — a pure background call. Handling in AppDelegate:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { guard let syncType = userInfo["sync_type"] as? String else { completionHandler(.noData) return } Task { do { let hasNewData = try await SyncManager.shared.sync(type: syncType) completionHandler(hasNewData ? .newData : .noData) } catch { completionHandler(.failed) } } } Critical point: iOS gives about 30 seconds for execution. If completionHandler is not called, the task is forcefully terminated. iOS also does not guarantee delivery when the battery is low (Low Power Mode) and after the app has been force-quit. Force quit completely blocks silent push until the app is manually launched — this is documented iOS behavior and cannot be bypassed, as documented by Apple.
Silent Push on Android: FCM Data Message and WorkManager
On Android, the role of silent push is played by FCM Data Message — it reaches FirebaseMessagingService.onMessageReceived regardless of app state (if not killed by system Doze).
class AppFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(message: RemoteMessage) { val syncType = message.data["sync_type"] ?: return val workRequest = OneTimeWorkRequestBuilder<SyncWorker>() .setInputData(workDataOf("sync_type" to syncType)) .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build() WorkManager.getInstance(applicationContext).enqueue(workRequest) } } setExpedited() requests immediate execution. On Android 12+, inside an expedited worker, you must call setForegroundAsync(), otherwise a long operation may cause an ANR.
Doze Mode restricts background activity. FCM high-priority messages bypass Doze if you specify android.priority: "HIGH" in the payload:
{ "message": { "token": "device_fcm_token", "android": { "priority": "HIGH" }, "data": { "sync_type": "messages", "payload": "{...}" } } } More about Doze Mode
Doze Mode activates when the device is idle and not charging. High-priority messages bypass it, but if requests are too frequent, the system may start ignoring them — maintain intervals of at least 10 minutes between silent pushes.How to Update Badge Without Notifying the User?
A common case is updating the badge number without showing a notification. On iOS via silent push:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { if let badge = userInfo["badge"] as? Int { UNUserNotificationCenter.current().setBadgeCount(badge) { _ in } } completionHandler(.newData) } On Android, there is no universal API — use the ShortcutBadger library or NotificationManagerCompat.setNumber(), but support depends on the launcher (Samsung, Xiaomi, Huawei).
Limits and Quotas
iOS 13+ introduced BGTaskScheduler and background processing quota. If an app requests background execution too often without benefit to the user, the system will throttle calls. Calling completionHandler(.noData) when there is no new data is critical for correct quota system operation. On Android, a similar mechanism exists — WorkManager throttles frequent tasks. Adhere to intervals and use exponential backoff on errors.
Platform Comparison
| Feature | iOS | Android |
|---|---|---|
| Mechanism | Silent Push (content-available) | FCM Data Message |
| Background execution | Background Modes + 30s limit | WorkManager + expedited |
| Force quit | Not delivered | Delivered (if not killed by system) |
| Doze Mode | Throttling by quota | High priority bypasses Doze |
| Badge update | UNUserNotificationCenter.setBadgeCount |
ShortcutBadger / launcher-specific |
Common Errors and Solutions
| Error | Solution |
|---|---|
| Silent push not delivered on iOS after force quit | Explain to the user that the app needs to be launched manually |
| FCM Data Message not waking app on Android 12+ | Add setForegroundAsync() in expedited worker |
| Badge not updating on Android Xiaomi | Use ShortcutBadger with explicit Xiaomi support |
| Background execution quota exceeded on iOS | Reduce silent push frequency to once every 5-10 minutes |
What’s Included in Our Silent Push Setup Service
When you order our service, you get:
- Architecture design for push infrastructure (APNs + FCM)
- Implementation of handlers on iOS and Android with edge cases covered
- Configuration of Background Modes, WorkManager, high-priority topics
- Integration of badge counter updates on both platforms
- Documentation and team training
- Post-launch support (1 month)
Why Trust Our Setup?
We specialize in mobile development with over 10 years of experience. We have implemented more than 50 projects with push infrastructure, including high-load apps with millions of users. Our solutions pass App Store Review and Google Play Console without issues. We use the latest versions of Swift, Kotlin, Flutter — the stack is selected based on your project.
Timelines and Cost
Silent push setup for one platform (iOS or Android) takes 3–5 business days. A cross-platform solution takes 5–9 days. The cost is calculated individually based on integration complexity and required stack. We offer a free project evaluation — simply contact us.
Get a consultation — reach out by email or through the form on our website. We’ll help you set up silent push so that data updates even under the harshest conditions.







