Commencer
Installation
Section titled “Installation”npm install @capgo/capacitor-twilio-voicenpx cap syncyarn add @capgo/capacitor-twilio-voicenpx cap syncpnpm add @capgo/capacitor-twilio-voicenpx cap syncbun add @capgo/capacitor-twilio-voicenpx cap syncPrerequisites
Section titled “Prerequisites”You’ll need a Twilio Compte and access tokens for authentication. Sign up at Twilio if you don’t have an Compte.
Platform Configuration
Section titled “Platform Configuration”Add required permissions to your Info.plist:
<key>NSMicrophoneUsageDescription</key><string>This app needs microphone access for voice calls</string>For incoming calls with PushKit:
- Activer Pousser Notifications in Xcode capabilities
- Ajouter VoIP background mode
- Configure VoIP certificate in Twilio console
Android
Section titled “Android”Add required permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.RECORD_AUDIO" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />Configure Firebase for Pousser notifications:
- Add
google-services.jsonto your Android project - Configure FCM in Twilio console
Utilisation Exemple
Section titled “Utilisation Exemple”import { TwilioVoice } from '@capgo/capacitor-twilio-voice';
// Authenticate with Twilioawait TwilioVoice.login({ accessToken: 'your-twilio-access-token'});
// Make a callawait TwilioVoice.makeCall({ to: '+1234567890'});
// Listen for call eventsTwilioVoice.addListener('callConnected', (data) => { console.log('Call connected:', data.callSid);});
TwilioVoice.addListener('callDisconnected', (data) => { console.log('Call disconnected:', data.callSid);});
TwilioVoice.addListener('incomingCall', (data) => { console.log('Incoming call from:', data.from);
// Accept the call TwilioVoice.acceptCall({ callSid: data.callSid });
// Or reject it // TwilioVoice.rejectCall({ callSid: data.callSid });});
// Mute/unmute callawait TwilioVoice.muteCall({ muted: true, callSid: 'current-call-sid'});
// Toggle speakerawait TwilioVoice.setSpeaker({ enabled: true});
// End callawait TwilioVoice.endCall({ callSid: 'current-call-sid'});
// Logoutawait TwilioVoice.logout();API Référence
Section titled “API Référence”Connexion(Options)
Section titled “Connexion(Options)”login(options: { accessToken: string }) => Promise<void>Authenticate with Twilio using an access token.
| Param | Type |
|---|---|
options | { accessToken: string } |
Déconnexion()
Section titled “Déconnexion()”logout() => Promise<void>End Utilisateur session and clear call state.
isLoggedIn()
Section titled “isLoggedIn()”isLoggedIn() => Promise<{ loggedIn: boolean }>Vérifier current authentication status.
Returns: Promise<{ loggedIn: boolean }>
makeCall(Options)
Section titled “makeCall(Options)”makeCall(options: { to: string; params?: Record<string, string> }) => Promise<{ callSid: string }>Initiate an outgoing call to a specified number.
| Param | Type |
|---|---|
options | { to: string; params?: Record<string, string> } |
Returns: Promise<{ callSid: string }>
acceptCall(Options)
Section titled “acceptCall(Options)”acceptCall(options: { callSid: string }) => Promise<void>Accept an incoming call.
| Param | Type |
|---|---|
options | { callSid: string } |
rejectCall(Options)
Section titled “rejectCall(Options)”rejectCall(options: { callSid: string }) => Promise<void>Reject an incoming call.
| Param | Type |
|---|---|
options | { callSid: string } |
endCall(Options?)
Section titled “endCall(Options?)”endCall(options?: { callSid?: string }) => Promise<void>Terminate an Actif call.
| Param | Type |
|---|---|
options | { callSid?: string } (optional) |
muteCall(Options)
Section titled “muteCall(Options)”muteCall(options: { muted: boolean; callSid?: string }) => Promise<void>Mute or unmute call audio.
| Param | Type |
|---|---|
options | { muted: boolean; callSid?: string } |
setSpeaker(Options)
Section titled “setSpeaker(Options)”setSpeaker(options: { enabled: boolean }) => Promise<void>Toggle speaker output.
| Param | Type |
|---|---|
options | { enabled: boolean } |
sendDigits(Options)
Section titled “sendDigits(Options)”sendDigits(options: { digits: string; callSid?: string }) => Promise<void>Send DTMF tones during a call.
| Param | Type |
|---|---|
options | { digits: string; callSid?: string } |
Event Listeners
Section titled “Event Listeners”Disponible Events
Section titled “Disponible Events”registered- Successfully registered with Twiliounregistered- Unregistered from TwilioregistrationFailed- Registration failedincomingCall- Incoming call receivedcallConnected- Call successfully connectedcallDisconnected- Call disconnectedcallRinging- Outgoing call is ringingcallReconnecting- Call is reconnectingcallReconnected- Call reconnected after interruptionqualityWarning- Call quality warningerror- An error occurred
Event Exemples
Section titled “Event Exemples”// Handle incoming callsTwilioVoice.addListener('incomingCall', (data) => { console.log('Incoming call from:', data.from); console.log('Call SID:', data.callSid);
// Show incoming call UI showIncomingCallScreen({ from: data.from, callSid: data.callSid });});
// Handle call state changesTwilioVoice.addListener('callConnected', (data) => { console.log('Call connected:', data.callSid); startCallTimer();});
TwilioVoice.addListener('callDisconnected', (data) => { console.log('Call ended:', data.callSid); stopCallTimer(); hideCallScreen();});
// Handle quality warningsTwilioVoice.addListener('qualityWarning', (data) => { console.warn('Call quality warning:', data.warning); showQualityWarning(data.warning);});
// Handle errorsTwilioVoice.addListener('error', (error) => { console.error('Twilio error:', error.message); handleError(error);});
// Remove listeners when doneconst listener = await TwilioVoice.addListener('callConnected', (data) => { console.log('Connected');});
// Later...listener.remove();Terminé Exemple
Section titled “Terminé Exemple”import { TwilioVoice } from '@capgo/capacitor-twilio-voice';
class VoiceCallService { private currentCallSid: string | null = null; private isMuted = false; private isSpeakerOn = false;
async initialize(accessToken: string) { try { // Login to Twilio await TwilioVoice.login({ accessToken });
// Check login status const { loggedIn } = await TwilioVoice.isLoggedIn(); console.log('Login status:', loggedIn);
// Setup event listeners this.setupEventListeners();
} catch (error) { console.error('Failed to initialize:', error); } }
setupEventListeners() { // Registration events TwilioVoice.addListener('registered', () => { console.log('Successfully registered with Twilio'); });
TwilioVoice.addListener('registrationFailed', (error) => { console.error('Registration failed:', error); });
// Incoming call TwilioVoice.addListener('incomingCall', async (data) => { console.log('Incoming call from:', data.from);
const accepted = await this.showIncomingCallDialog(data.from);
if (accepted) { await TwilioVoice.acceptCall({ callSid: data.callSid }); this.currentCallSid = data.callSid; } else { await TwilioVoice.rejectCall({ callSid: data.callSid }); } });
// Call events TwilioVoice.addListener('callConnected', (data) => { console.log('Call connected'); this.currentCallSid = data.callSid; this.showCallScreen(); });
TwilioVoice.addListener('callDisconnected', () => { console.log('Call disconnected'); this.currentCallSid = null; this.hideCallScreen(); });
TwilioVoice.addListener('callRinging', () => { console.log('Call ringing...'); });
// Quality warnings TwilioVoice.addListener('qualityWarning', (data) => { console.warn('Call quality warning:', data.warning); this.showQualityIndicator(data.warning); }); }
async makeCall(phoneNumber: string) { try { const result = await TwilioVoice.makeCall({ to: phoneNumber, params: { // Optional custom parameters customerId: 'customer-123' } });
this.currentCallSid = result.callSid; console.log('Call initiated:', result.callSid); } catch (error) { console.error('Failed to make call:', error); } }
async endCall() { if (this.currentCallSid) { await TwilioVoice.endCall({ callSid: this.currentCallSid }); this.currentCallSid = null; } }
async toggleMute() { this.isMuted = !this.isMuted; await TwilioVoice.muteCall({ muted: this.isMuted, callSid: this.currentCallSid || undefined }); }
async toggleSpeaker() { this.isSpeakerOn = !this.isSpeakerOn; await TwilioVoice.setSpeaker({ enabled: this.isSpeakerOn }); }
async sendDTMF(digits: string) { if (this.currentCallSid) { await TwilioVoice.sendDigits({ digits, callSid: this.currentCallSid }); } }
async logout() { await TwilioVoice.logout(); }
private async showIncomingCallDialog(from: string): Promise<boolean> { // Show native dialog or custom UI return confirm(`Incoming call from ${from}`); }
private showCallScreen() { // Show call UI console.log('Showing call screen'); }
private hideCallScreen() { // Hide call UI console.log('Hiding call screen'); }
private showQualityIndicator(warning: string) { // Show quality warning console.log('Quality warning:', warning); }}
// Usageconst voiceService = new VoiceCallService();
// Initialize with access token from your backendconst token = await fetchTwilioToken();await voiceService.initialize(token);
// Make a callawait voiceService.makeCall('+1234567890');
// Control callawait voiceService.toggleMute();await voiceService.toggleSpeaker();await voiceService.sendDTMF('1');
// End callawait voiceService.endCall();
// Logoutawait voiceService.logout();Best Practices
Section titled “Best Practices”- Fetch access tokens from your backend server, never embed them in the Application
- Implement token Actualiser logic for long-running sessions
- Handle network interruptions with reconnection logic
- Provide visual Retour for call states
- Test on actual Appareils with Pousser notifications
- Implement proper Erreur handling
- Clean up listeners when components unmount
- Request microphone permissions before making calls
Sécurité Considerations
Section titled “Sécurité Considerations”- Never store Twilio credentials in the Application
- Generate access tokens on your backend
- Implement token expiration and Actualiser
- Use HTTPS for all token requests
- Valider incoming calls server-side
Dépannage
Section titled “Dépannage”Calls Not Connecting
Section titled “Calls Not Connecting”- Verify access token is valid and not expired
- Vérifier network connectivity
- Ensure microphone permissions are granted
- Verify Twilio Compte is properly configured
Pousser Notifications Not Working
Section titled “Pousser Notifications Not Working”- Verify PushKit/FCM certificates are configured in Twilio
- Vérifier Appareil is registered for Pousser notifications
- Test with Production certificates
Audio Issues
Section titled “Audio Issues”- Vérifier microphone permissions
- Verify speaker/bluetooth Paramètres
- Test audio routing on actual Appareils
Caller Name Display (CapacitorTwilioCallerName)
Section titled “Caller Name Display (CapacitorTwilioCallerName)”By default, incoming calls display the caller’s phone number or client ID. You can customize this by passing a CapacitorTwilioCallerName parameter from your TwiML backend to display a friendly name instead.
Backend Configuration
Section titled “Backend Configuration”When generating your TwiML response for the <Client> dial, add the CapacitorTwilioCallerName parameter:
// Java exampleParameter callerNameParam = new Parameter.Builder() .name("CapacitorTwilioCallerName") .value("John Doe") .build();
Client client = new Client.Builder(identity) .parameter(callerNameParam) .build();
Dial dial = new Dial.Builder() .client(client) .build();// Node.js exampleconst VoiceResponse = require('twilio').twiml.VoiceResponse;
const response = new VoiceResponse();const dial = response.dial();dial.client({ name: 'CapacitorTwilioCallerName', value: 'John Doe'}, identity);How It Works
Section titled “How It Works”- When your backend receives an incoming call, it generates TwiML to route the call
- Include the
CapacitorTwilioCallerNameparameter with the caller’s display name - The plugin automatically extracts this Paramètre and uses it for:
- iOS CallKit incoming call screen
- Android incoming call notification
- The
fromfield inincomingCallevents - The
pendingInvitesarray in call status
If CapacitorTwilioCallerName is not provided, the plugin falls back to the caller’s phone number or client ID.