PitelVoIP Integration Guide
Version: 2.1.0
Platform: iOS 14.0+
Language: Swift 5.5+
📋 Table of Contents
- Overview
- Prerequisites
- Step-by-Step Integration
- API Reference
- Customize CallScreen UI
- Essential Tips
- Troubleshooting
Overview
PitelVoIP Framework is a comprehensive VoIP solution for iOS applications, built on top of PJSIP with CallKit integration and push notification support.
✨ Key Features
- ✅ One-Line Integration - Add full VoIP capabilities in minutes.
- ✅ CallKit Native UI - Seamless system call experience.
- ✅ VoIP Push & Auto-Login - Reliable background call receiving.
- ✅ SwiftUI Ready - Modern ViewModels and Modifiers included.
- ✅ Call Controls - Complete feature set (Mute, Hold, Transfer, DTMF).
Prerequisites
System Requirements
- iOS: 14.0 or later
- Xcode: 13.0 or later
- Swift: 5.5 or later
- Firebase SDK: for FCM integration
Xcode Configuration
1. Enable Required Capabilities
Go to Target → Signing & Capabilities and add:
Background Modes:
- ✅ Voice over IP
- ✅ Background fetch
- ✅ Remote notifications
Push Notifications:
- ✅ Enable push notifications
2. Configure Info.plist
Add the following keys to your Info.plist:
<!-- Background Modes -->
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
<!-- Permissions -->
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone to make VoIP calls.</string>
3. VoIP Push Certificate
- Go to Apple Developer Portal
- Create a VoIP Services Certificate
- Download and install the certificate
- Export as
.p12file for your push server
Step-by-Step Integration
Step 1: Add Framework to Your Project
Manual Installation
- Download or clone the PitelVoIP framework
- Drag
IOSPitelVoIPFrameworkinto your Xcode project - Add the framework to Frameworks, Libraries, and Embedded Content
- Set to Embed & Sign
Step 2: Create AppDelegate
Create an AppDelegate class that inherits from PitelVoIPDelegate:
import UIKit
import PitelVoIPFramework
import Firebase
import FirebaseMessaging
class AppDelegate: PitelVoIPDelegate, MessagingDelegate {
static let shared = AppDelegate()
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// ✅ Parent class automatically configures PJSIP
_ = super.application(application, didFinishLaunchingWithOptions: launchOptions)
// Initialize Firebase
FirebaseApp.configure()
Messaging.messaging().delegate = self
// Setup incoming call handler
self.onIncomingCall = { [weak self] name, callerId, uuid in
self?.handleIncomingCall(name: name, callerId: callerId, uuid: uuid)
}
return true
}
// Override to integrate FCM
override func onAPNsTokenReceived(_ deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
// Firebase Messaging delegate
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
if let token = fcmToken {
onFCMTokenReceived(token)
}
}
// Handle incoming call
func handleIncomingCall(name: String, callerId: String, uuid: UUID) {
print("📞 Incoming call from \(name)")
}
}
Step 3: Setup App with Lifecycle Modifier
In your main app file:
import SwiftUI
import PitelVoIPFramework
@main
struct YourApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
.pitelVoIPLifecycle()
}
}
}
That's it! ✅ Your app is now ready to make and receive VoIP calls.
API Reference
1. Login with Builder Pattern
Quick Login (Recommended)
import SwiftUI
import PitelVoIPFramework
struct ContentView: View {
@StateObject var viewModel = AccountViewModel()
var body: some View {
VStack {
Button("Login") {
PitelVoIP.login(
accountViewModel: viewModel
) { builder in
builder
.setExtension("YOUR_EXTENSION")
.setPassword("YOUR_PASSWORD")
.setDomain("YOUR_DOMAIN") // e.g., sip.pitel.vn
.setProxy("YOUR_PROXY") // Optional
.setPort("YOUR_PORT") // e.g., 50061
.setDisplayName("Your Name")
.setTeamId("YOUR_TEAM_ID")
.setAppId("com.yourcompany.app")
.setAppMode("dev") // or "production"
}
}
}
}
}
2. Making Calls
// Simple call
PitelVoIP.makeCall(to: "sip:101@sip.pitel.vn:50061")
// Call with display name
PitelVoIP.makeCall(
to: "sip:101@sip.pitel.vn:50061",
callerName: "Agent 101"
)
3. Handle Incoming Call UI
Add navigation to your call view:
@ObservedObject private var callManager = globalCallStatusManager
var body: some View {
NavigationLink(
destination: CallView(),
isActive: $callManager.isActiveCallPresented
) {
EmptyView()
}
}
4. Call Controls
PitelVoIP.mute() // Toggle mute
PitelVoIP.unmute()
PitelVoIP.hold() // Toggle hold
PitelVoIP.unhold()
PitelVoIP.hangup() // End call
PitelVoIP.sendDTMF("1") // Send DTMF
PitelVoIP.transferCall(to: "sip:102@sip.pitel.vn:50061") // Transfer call
5. Logout
PitelVoIP.logout(
accountViewModel: viewModel,
sipInfo: sipInfo
)
Customize CallScreen UI
PitelCallView is a complete, pre-built VoIP call screen that supports all essential features: Mute, Speaker, Hold, Transfer, Keypad, and End Call.
1. Basic Usage
Use the default configuration (Light Mode):
PitelCallView()
Use the Dark Mode configuration:
PitelCallView(config: .defaultDark)
2. Customization
You can fully customize the UI using PitelCallConfig.
let config = PitelCallConfig(
colors: .init(background: .blue), // Change background color
texts: .init(endCall: "Hang Up") // Change button text
)
PitelCallView(config: config)
3. Properties Reference
Colors (config.colors)
| Property | Type | Description | Default |
|---|---|---|---|
background | Color | Main screen background color | Soft White / Charcoal |
cardBackground | Color | Background color of the bottom action card | White / Dark Gray |
textPrimary | Color | Caller name color | Dark Gray / White |
textSecondary | Color | Timer and secondary text color | Gray |
textStatus | Color | Call status (Incoming/Outgoing) color | Gray |
buttonIconActive | Color | Icon color when button is ACTIVE | Orange |
buttonIconInactive | Color | Icon color when button is INACTIVE | Gray |
buttonBackgroundActive | Color | Button background when ACTIVE | Light Orange |
buttonBackgroundInactive | Color | Button background when INACTIVE | Soft Gray |
hangupButtonBackground | Color | Background color of the End Call button | Soft Red |
dialPadNumber | Color | Color of numbers on the keypad | Dark Gray |
dialPadButtonBackground | Color | Background color of keypad buttons | White |
Texts (config.texts)
| Property | Description | Default |
|---|---|---|
outgoing | Outgoing call status text | "Starting call..." |
incoming | Incoming call status text | "Incoming..." |
unknownCaller | Display name when CallerID is missing | "Unknown Caller" |
mute / unmute | Mute button label | "Mute" / "Unmute" |
speaker | Speaker button label | "Speaker" |
hold / unhold | Hold button label | "Hold" / "Unhold" |
transfer | Transfer button label | "Transfer" |
keypad | Keypad button label | "Keypad" |
endCall | End Call button label | "End Call" |
enterNumber | Placeholder for transfer number input | "Enter number" |
Fonts (config.fonts)
| Property | Description |
|---|---|
callerName | Font for the caller's name |
status | Font for call status (Incoming...) |
timer | Font for the call timer |
actionButtonLabel | Font for labels below action buttons |
dialPadNumber | Font for numbers on the keypad |
Icons (config.icons)
Uses system SF Symbols names.
| Property | Default |
|---|---|
mute / unmute | "mic.slash" / "mic" |
speakerOn / speakerOff | "speaker.wave.2" / "speaker" |
hold / unhold | "pause" / "play" |
hangup | "phone.down.fill" |
transfer | "arrowshape.turn.up.right" |
💡 Essential Tips
1. Store Credentials Securely
The framework automatically handles secure storage via ExtInfoStorage. Just call PitelVoIP.login().
2. Handle App Lifecycle
Always add .pitelVoIPLifecycle() to your root view. This ensures auto-login works when the app resumes or wakes up from VoIP push.
3. Use Global State
Observe call status easily anywhere in your app:
@ObservedObject var callManager = globalCallStatusManager
❓ Troubleshooting
| Issue | Solution |
|---|---|
| No VoIP Push | Check .p12 certificate & enable Background Modes (VoIP, Remote Notif). |
| Registration Fail | Ensure internet connection & verify SIP credentials. Check logs. |
| Audio Key Missing | Add NSMicrophoneUsageDescription to Info.plist. |
| Build Error | Set Framework to Embed & Sign in Target settings. |
📚 Resources
- README.md - Full Documentation
- GitHub Issues - Report Bugs
- Support: support@tel4vn.com
Made with ❤️ by the Pitel Team