Passer au contenu

Commencer

Terminal window
npm install @capgo/capacitor-twilio-voice
npx cap sync

Vous aurez besoin d’un compte Twilio et de jetons d’accès pour l’authentification. Inscrivez-vous sur Twilio si vous n’avez pas de compte.

Ajoutez les permissions requises à votre Info.plist :

<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access for voice calls</string>

Pour les appels entrants avec PushKit :

  1. Activez les notifications push dans les capacités Xcode
  2. Ajoutez le mode en arrière-plan VoIP
  3. Configurez le certificat VoIP dans la console Twilio

Ajoutez les permissions requises à votre 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" />

Configurez Firebase pour les notifications push :

  1. Ajoutez google-services.json à votre projet Android
  2. Configurez FCM dans la console Twilio
import { TwilioVoice } from '@capgo/capacitor-twilio-voice';
// Authenticate with Twilio
await TwilioVoice.login({
accessToken: 'your-twilio-access-token'
});
// Make a call
await TwilioVoice.makeCall({
to: '+1234567890'
});
// Listen for call events
TwilioVoice.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 call
await TwilioVoice.muteCall({
muted: true,
callSid: 'current-call-sid'
});
// Toggle speaker
await TwilioVoice.setSpeaker({
enabled: true
});
// End call
await TwilioVoice.endCall({
callSid: 'current-call-sid'
});
// Logout
await TwilioVoice.logout();
login(options: { accessToken: string }) => Promise<void>

S’authentifier avec Twilio en utilisant un jeton d’accès.

ParamType
options{ accessToken: string }
logout() => Promise<void>

Terminer la session utilisateur et effacer l’état de l’appel.

isLoggedIn() => Promise<{ loggedIn: boolean }>

Vérifier l’état d’authentification actuel.

Retourne : Promise<{ loggedIn: boolean }>

makeCall(options: { to: string; params?: Record<string, string> }) => Promise<{ callSid: string }>

Initier un appel sortant vers un numéro spécifié.

ParamType
options{ to: string; params?: Record<string, string> }

Retourne : Promise<{ callSid: string }>

acceptCall(options: { callSid: string }) => Promise<void>

Accepter un appel entrant.

ParamType
options{ callSid: string }
rejectCall(options: { callSid: string }) => Promise<void>

Rejeter un appel entrant.

ParamType
options{ callSid: string }
endCall(options?: { callSid?: string }) => Promise<void>

Terminer un appel actif.

ParamType
options{ callSid?: string } (optionnel)
muteCall(options: { muted: boolean; callSid?: string }) => Promise<void>

Activer ou désactiver le son de l’appel.

ParamType
options{ muted: boolean; callSid?: string }
setSpeaker(options: { enabled: boolean }) => Promise<void>

Basculer la sortie haut-parleur.

ParamType
options{ enabled: boolean }
sendDigits(options: { digits: string; callSid?: string }) => Promise<void>

Envoyer des tonalités DTMF pendant un appel.

ParamType
options{ digits: string; callSid?: string }
  • registered - Enregistré avec succès auprès de Twilio
  • unregistered - Désenregistré de Twilio
  • registrationFailed - Échec de l’enregistrement
  • incomingCall - Appel entrant reçu
  • callConnected - Appel connecté avec succès
  • callDisconnected - Appel déconnecté
  • callRinging - L’appel sortant sonne
  • callReconnecting - L’appel se reconnecte
  • callReconnected - Appel reconnecté après une interruption
  • qualityWarning - Avertissement de qualité d’appel
  • error - Une erreur s’est produite
// Handle incoming calls
TwilioVoice.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 changes
TwilioVoice.addListener('callConnected', (data) => {
console.log('Call connected:', data.callSid);
startCallTimer();
});
TwilioVoice.addListener('callDisconnected', (data) => {
console.log('Call ended:', data.callSid);
stopCallTimer();
hideCallScreen();
});
// Handle quality warnings
TwilioVoice.addListener('qualityWarning', (data) => {
console.warn('Call quality warning:', data.warning);
showQualityWarning(data.warning);
});
// Handle errors
TwilioVoice.addListener('error', (error) => {
console.error('Twilio error:', error.message);
handleError(error);
});
// Remove listeners when done
const listener = await TwilioVoice.addListener('callConnected', (data) => {
console.log('Connected');
});
// Later...
listener.remove();
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);
}
}
// Usage
const voiceService = new VoiceCallService();
// Initialize with access token from your backend
const token = await fetchTwilioToken();
await voiceService.initialize(token);
// Make a call
await voiceService.makeCall('+1234567890');
// Control call
await voiceService.toggleMute();
await voiceService.toggleSpeaker();
await voiceService.sendDTMF('1');
// End call
await voiceService.endCall();
// Logout
await voiceService.logout();
  • Récupérez les jetons d’accès depuis votre serveur backend, ne les intégrez jamais dans l’application
  • Implémentez une logique de rafraîchissement des jetons pour les sessions de longue durée
  • Gérez les interruptions réseau avec une logique de reconnexion
  • Fournissez des retours visuels pour les états d’appel
  • Testez sur des appareils réels avec des notifications push
  • Implémentez une gestion appropriée des erreurs
  • Nettoyez les écouteurs lorsque les composants sont démontés
  • Demandez les permissions du microphone avant d’effectuer des appels
  • Ne stockez jamais les identifiants Twilio dans l’application
  • Générez les jetons d’accès sur votre backend
  • Implémentez l’expiration et le rafraîchissement des jetons
  • Utilisez HTTPS pour toutes les requêtes de jetons
  • Validez les appels entrants côté serveur
  • Vérifiez que le jeton d’accès est valide et n’a pas expiré
  • Vérifiez la connectivité réseau
  • Assurez-vous que les permissions du microphone sont accordées
  • Vérifiez que le compte Twilio est correctement configuré

Les notifications push ne fonctionnent pas

Section titled “Les notifications push ne fonctionnent pas”
  • Vérifiez que les certificats PushKit/FCM sont configurés dans Twilio
  • Vérifiez que l’appareil est enregistré pour les notifications push
  • Testez avec des certificats de production
  • Vérifiez les permissions du microphone
  • Vérifiez les paramètres du haut-parleur/bluetooth
  • Testez le routage audio sur des appareils réels

Affichage du nom de l’appelant (CapacitorTwilioCallerName)

Section titled “Affichage du nom de l’appelant (CapacitorTwilioCallerName)”

Par défaut, les appels entrants affichent le numéro de téléphone ou l’ID client de l’appelant. Vous pouvez personnaliser cela en passant un paramètre CapacitorTwilioCallerName depuis votre backend TwiML pour afficher un nom convivial à la place.

Lors de la génération de votre réponse TwiML pour le cadran <Client>, ajoutez le paramètre CapacitorTwilioCallerName :

// Java example
Parameter 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 example
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const response = new VoiceResponse();
const dial = response.dial();
dial.client({
name: 'CapacitorTwilioCallerName',
value: 'John Doe'
}, identity);
  1. Lorsque votre backend reçoit un appel entrant, il génère du TwiML pour acheminer l’appel
  2. Incluez le paramètre CapacitorTwilioCallerName avec le nom d’affichage de l’appelant
  3. Le plugin extrait automatiquement ce paramètre et l’utilise pour :
    • L’écran d’appel entrant iOS CallKit
    • La notification d’appel entrant Android
    • Le champ from dans les événements incomingCall
    • Le tableau pendingInvites dans l’état de l’appel

Si CapacitorTwilioCallerName n’est pas fourni, le plugin revient au numéro de téléphone ou à l’ID client de l’appelant.