Native incoming call UI for iOS using CallKit and PushKit. Add real-time calling to your app with Rivium Push.
- Native CallKit incoming call screen
- PushKit VoIP push handling (wakes app even when killed)
- Customizable caller info (name, avatar, call type)
- Audio and video call support
- Call timeout handling
- China/restricted region fallback (local notification instead of CallKit)
- Custom ringtone support
- iOS 13.0+
- Swift 5.0+
- Xcode capabilities: Push Notifications, Background Modes (Voice over IP, Remote notifications)
pod 'RiviumPushVoip', '~> 0.1'dependencies: [
.package(url: "https://github.com/Rivium-co/rivium-push-voip-ios-sdk.git", from: "0.1.0")
]import RiviumPushVoip
let config = VoipConfig(
appName: "MyApp",
supportsVideo: true,
callTimeout: 30
)
RiviumPushVoip.shared.initialize(config: config)
RiviumPushVoip.shared.delegate = selfRiviumPushVoip.shared.registerForVoIPPushes()extension AppDelegate: RiviumPushVoipDelegate {
func voip(_ voip: RiviumPushVoip, didAcceptCall callData: VoipCallData) {
// User accepted the call — connect to your calling service (Jitsi, WebRTC, etc.)
print("Call accepted: \(callData.callerName)")
}
func voip(_ voip: RiviumPushVoip, didDeclineCall callData: VoipCallData) {
// User declined the call
print("Call declined: \(callData.callerName)")
}
func voip(_ voip: RiviumPushVoip, didTimeoutCall callData: VoipCallData) {
// Call timed out (no answer)
print("Call timed out: \(callData.callerName)")
}
func voip(_ voip: RiviumPushVoip, didReceiveIncomingCall callData: VoipCallData) {
// CallKit unavailable (e.g., China) — show your own call UI
print("Incoming call (no CallKit): \(callData.callerName)")
}
func voip(_ voip: RiviumPushVoip, didFailWithError error: String) {
print("VoIP error: \(error)")
}
}When you receive a VoIP push via Rivium Push SDK:
let callData = VoipCallData(
callId: "call_123",
callerName: "John Doe",
callerId: "user_456",
callerAvatar: "https://example.com/avatar.jpg",
callType: "video"
)
RiviumPushVoip.shared.showIncomingCall(callData: callData)// Report call as connected (after WebRTC/Jitsi connects)
RiviumPushVoip.shared.reportCallConnected(callId: "call_123")
// End call
RiviumPushVoip.shared.endCall(callId: "call_123")let config = VoipConfig(
appName: "MyApp", // App name shown in CallKit UI
vibrate: true, // Enable vibration on incoming call
callTimeout: 30, // Seconds before call times out
supportsVideo: true, // Enable video call support
ringtoneName: "custom_ring", // Custom ringtone file name (optional)
iconTemplateName: "CallIcon", // CallKit icon template (optional)
disableCallKit: false, // Force disable CallKit
callIdKey: "call_id", // Push payload key for call ID
callerNameKey: "caller_name", // Push payload key for caller name
callerIdKey: "caller_id", // Push payload key for caller ID
callerAvatarKey: "caller_avatar", // Push payload key for avatar URL
callTypeKey: "call_type" // Push payload key for call type
)Send a push with this data format from your server:
{
"call_id": "unique_call_id",
"caller_name": "John Doe",
"caller_id": "user_456",
"caller_avatar": "https://example.com/avatar.jpg",
"call_type": "video"
}The payload keys are configurable via VoipConfig.
// Check if app was launched from a VoIP call
if let initialCall = RiviumPushVoip.shared.getInitialCall() {
// Navigate to call screen
showCallScreen(callData: initialCall)
RiviumPushVoip.shared.clearInitialCall()
}CallKit is restricted in China. The SDK automatically detects this and falls back to a local notification with Accept/Decline actions. Handle this in:
func voip(_ voip: RiviumPushVoip, didReceiveIncomingCall callData: VoipCallData) {
// Show your own incoming call UI (CallKit not available)
}This SDK works alongside RiviumPush SDK for push delivery. RiviumPush handles the VoIP push registration and delivery, this SDK handles the CallKit UI.
- Rivium Push - Learn more about Rivium Push
- Documentation - VoIP documentation
- Rivium Console - Manage your push notifications
MIT License - see LICENSE for details.