Swift杀死应用后台重启后Badge计数不生效问题求助
Hey there, let’s break down this badge count issue you’re hitting when your app runs in the background after being fully killed. I’ve tackled similar problems before, so here are some targeted fixes and things to check based on common platform-specific quirks:
iOS Specific Checks & Fixes
- Don’t rely on in-memory counts or UserDefaults alone: When your app is killed, in-memory data gets wiped, and UserDefaults might not sync immediately on background launch. Use Keychain instead for persistent badge count storage—it’s designed to retain data even after app termination.
- Leverage APNs badge payload where possible: If you’re using Apple Push Notification service, include the
badgefield directly in your push payload. iOS will automatically update the app badge without needing your app to process the notification in the background (even when killed). This is the most reliable method for remote pushes. - Verify background notification permissions: Ensure your app has "Remote notifications" enabled in the Background Modes capability, and that the user hasn’t disabled background app refresh for your app. Without these, your app won’t wake up to process notifications in the background after being killed.
- Check your notification delegate logic: For cases where you need custom counting logic, make sure
userNotificationCenter(_:didReceive:withCompletionHandler:)is properly implemented. When the app is killed, this delegate method will still fire if the user interacts with the notification, and you should update your persisted count here.
Example of Keychain-based count storage in Swift:
// Save badge count to Keychain func saveBadgeCount(_ count: Int) { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "AppBadgeCount", kSecValueData as String: Data(bytes: &count, count: MemoryLayout<Int>.size) ] SecItemDelete(query as CFDictionary) SecItemAdd(query as CFDictionary, nil) } // Retrieve badge count from Keychain func getBadgeCount() -> Int { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "AppBadgeCount", kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne ] var data: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &data) if status == errSecSuccess, let data = data as? Data { var count: Int = 0 data.copyBytes(to: &count, count: MemoryLayout<Int>.size) return count } return 0 }
Android Specific Checks & Fixes
- Handle vendor-specific background restrictions: Many Android manufacturers (Xiaomi, Huawei, Samsung) have aggressive battery optimization that kills background services. You’ll need to guide users to whitelist your app from battery optimization, or use a foreground service if your use case warrants it.
- Persist counts to SharedPreferences/Room: Just like iOS, in-memory counts are lost when the app is killed. Store your badge count in SharedPreferences (for simple values) or a Room database (for more complex tracking) to retain it across app restarts.
- Use the correct badge API for each vendor: Android doesn’t have a universal badge system—each manufacturer has its own API. For example, Xiaomi uses
NotificationCompat.Builder.setNumber(), while Samsung requires a specific intent. Make sure you’re calling the right API for the devices you support. - Verify FCM (or your push service) setup: If using Firebase Cloud Messaging, ensure your
FirebaseMessagingServiceis properly registered in the manifest. When the app is killed, some devices will still deliver notifications to this service, but only if you haven’t opted out of background delivery.
Example of SharedPreferences-based count storage in Kotlin:
// Save badge count fun saveBadgeCount(context: Context, count: Int) { val prefs = context.getSharedPreferences("BadgePrefs", Context.MODE_PRIVATE) prefs.edit().putInt("badge_count", count).apply() } // Retrieve badge count fun getBadgeCount(context: Context): Int { val prefs = context.getSharedPreferences("BadgePrefs", Context.MODE_PRIVATE) return prefs.getInt("badge_count", 0) } // Update badge in FCM service override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) val currentCount = getBadgeCount(applicationContext) val newCount = currentCount + 1 saveBadgeCount(applicationContext, newCount) // Example for Xiaomi devices val notification = NotificationCompat.Builder(this, "your_channel_id") .setContentTitle(remoteMessage.notification?.title) .setContentText(remoteMessage.notification?.body) .setSmallIcon(R.drawable.ic_notification) .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL) .setNumber(newCount) .build() val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(1, notification) }
Universal Troubleshooting Tips
- Test with real device scenarios: Emulators don’t always replicate real-world background behavior, especially on Android with vendor restrictions. Test on physical devices after fully killing the app.
- Log every step: Add logs for when notifications are received, counts are updated, and persisted. Use Xcode console (iOS) or Logcat (Android) to verify that your logic is firing even in the background.
- Reset badge count correctly: Don’t forget to handle cases where the user opens the app—you should reset the badge count to 0 and update both the persisted value and the system badge.
If you’re still stuck, sharing more details like which platform you’re targeting (iOS/Android/Flutter), which push service you’re using, and any existing code snippets would help narrow things down further!
内容的提问来源于stack exchange,提问作者Monyneath MOL
相关产品推荐
相关产品推荐

