本地通知添加背景震动及PushKit视频通话通知实现方案咨询
Hey there! I’ve worked through similar scenarios with PushKit and local notifications when CallKit isn’t an option, so let’s walk through how to build this out step by step.
1. Background Vibration for Local Notifications
First, to add that double-vibration effect when the initial notification triggers, you’ll need to create a custom sound object that includes a vibration pattern. iOS lets you define vibration patterns directly in the UNNotificationSound setup:
// Define the vibration pattern: [silence, vibrate, silence, vibrate] // Timings are in seconds – adjust as needed to match WhatsApp's feel let vibrationPattern = [0.0, 0.2, 0.5, 0.2] guard let customSound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "call_tone.wav"), withVibrationPattern: vibrationPattern) else { // Fallback to default sound/vibration if custom setup fails return } // Build your initial notification content let content = UNMutableNotificationContent() content.title = "Incoming Video Call" content.body = "John Doe is calling you" content.sound = customSound content.categoryIdentifier = "INCOMING_CALL" // Optional, for action buttons
This will trigger two short vibrations when the notification first appears. If you don’t want a custom audio tone, you can use the system’s default ringtone and just attach the vibration pattern.
2. PushKit Integration (Without CallKit)
Since you’re using PushKit for background push delivery (critical for video call alerts when the app is backgrounded), here’s how to trigger the initial notification and its delayed override in the PushKit delegate method:
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { // Parse your push payload to get call details (sender name, call ID, etc.) let callDetails = parsePushPayload(payload) // Create the initial notification request with a unique identifier let callNotificationID = "incoming_call_\(callDetails.callID)" let initialContent = buildInitialCallContent(callDetails) let initialRequest = UNNotificationRequest(identifier: callNotificationID, content: initialContent, trigger: nil) // Add the initial notification UNUserNotificationCenter.current().add(initialRequest) { error in if let error = error { print("Failed to add initial call notification: \(error)") } } // Schedule the second notification to override the first after 2 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 2) { let updatedContent = buildUpdatedCallContent(callDetails) // Reuse the SAME identifier to override the initial notification let updatedRequest = UNNotificationRequest(identifier: callNotificationID, content: updatedContent, trigger: nil) UNUserNotificationCenter.current().add(updatedRequest) { error in if let error = error { print("Failed to update call notification: \(error)") } } } completion() } // Helper functions to build notification content private func buildInitialCallContent(_ details: CallDetails) -> UNMutableNotificationContent { let content = UNMutableNotificationContent() content.title = "Incoming Video Call" content.body = "\(details.senderName) is calling you" // Add the double-vibration sound we defined earlier content.sound = createDoubleVibrationSound() return content } private func buildUpdatedCallContent(_ details: CallDetails) -> UNMutableNotificationContent { let content = UNMutableNotificationContent() content.title = "Incoming Video Call" content.body = "Tap to answer or decline" // Updated message matching WhatsApp's second alert // Optional: Keep the vibration or adjust it for the update content.sound = createDoubleVibrationSound() return content } private func createDoubleVibrationSound() -> UNNotificationSound { let vibrationPattern = [0.0, 0.2, 0.5, 0.2] if let customSound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "default_ringtone.wav"), withVibrationPattern: vibrationPattern) { return customSound } // Fallback to default critical sound/vibration if custom setup fails return UNNotificationSound.defaultCritical }
3. How WhatsApp’s Implementation Likely Works
From observing its behavior, here’s the breakdown of what’s happening under the hood:
- Initial Push Trigger: When the PushKit payload arrives, WhatsApp immediately fires a local notification with a custom double-vibration pattern and an initial message (e.g., "X is calling").
- Delayed Override: After ~2 seconds, they send a second local notification using the same identifier as the first. This replaces the original alert with updated text (often more explicit about answering/declining) – and since it uses the same identifier, iOS replaces the existing notification instead of stacking it.
- Background Persistence: Since PushKit wakes the app briefly in the background, this delayed override logic runs reliably even when the app isn’t active.
Key Notes
- Notification Identifiers: Reusing the same identifier is critical for overriding the initial notification. If you use a new ID, you’ll end up with two separate alerts instead of an update.
- Vibration Patterns: Adjust the timing in
vibrationPatternto match WhatsApp’s exact feel – you may need to tweak the intervals (0.2s vibrate, 0.5s silence, etc.) to get it right. - PushKit Permissions: Make sure you’ve enabled the
Voice over IPbackground mode in your app’s capabilities and requested the necessary PushKit permissions, as these are required for receiving pushes in the background.
内容的提问来源于stack exchange,提问作者NDM

