Memulai
Instalasi
Section titled “Instalasi”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 syncPrasyarat
Section titled “Prasyarat”Anda memerlukan akun Twilio dan token akses untuk autentikasi. Daftar di Twilio jika Anda belum memiliki akun.
Konfigurasi Platform
Section titled “Konfigurasi Platform”Tambahkan izin yang diperlukan ke Info.plist Anda:
<key>NSMicrophoneUsageDescription</key><string>This app needs microphone access for voice calls</string>Untuk panggilan masuk dengan PushKit:
- Aktifkan Push Notifications di capabilities Xcode
- Tambahkan mode background VoIP
- Konfigurasi sertifikat VoIP di konsol Twilio
Android
Section titled “Android”Tambahkan izin yang diperlukan ke AndroidManifest.xml Anda:
<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" />Konfigurasi Firebase untuk notifikasi push:
- Tambahkan
google-services.jsonke proyek Android Anda - Konfigurasi FCM di konsol Twilio
Contoh Penggunaan
Section titled “Contoh Penggunaan”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();Referensi API
Section titled “Referensi API”login(options)
Section titled “login(options)”login(options: { accessToken: string }) => Promise<void>Autentikasi dengan Twilio menggunakan token akses.
| Param | Type |
|---|---|
options | { accessToken: string } |
logout()
Section titled “logout()”logout() => Promise<void>Akhiri sesi pengguna dan bersihkan status panggilan.
isLoggedIn()
Section titled “isLoggedIn()”isLoggedIn() => Promise<{ loggedIn: boolean }>Periksa status autentikasi saat ini.
Returns: Promise<{ loggedIn: boolean }>
makeCall(options)
Section titled “makeCall(options)”makeCall(options: { to: string; params?: Record<string, string> }) => Promise<{ callSid: string }>Mulai panggilan keluar ke nomor yang ditentukan.
| 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>Terima panggilan masuk.
| Param | Type |
|---|---|
options | { callSid: string } |
rejectCall(options)
Section titled “rejectCall(options)”rejectCall(options: { callSid: string }) => Promise<void>Tolak panggilan masuk.
| Param | Type |
|---|---|
options | { callSid: string } |
endCall(options?)
Section titled “endCall(options?)”endCall(options?: { callSid?: string }) => Promise<void>Akhiri panggilan aktif.
| Param | Type |
|---|---|
options | { callSid?: string } (optional) |
muteCall(options)
Section titled “muteCall(options)”muteCall(options: { muted: boolean; callSid?: string }) => Promise<void>Bisukan atau aktifkan suara panggilan.
| Param | Type |
|---|---|
options | { muted: boolean; callSid?: string } |
setSpeaker(options)
Section titled “setSpeaker(options)”setSpeaker(options: { enabled: boolean }) => Promise<void>Toggle output speaker.
| Param | Type |
|---|---|
options | { enabled: boolean } |
sendDigits(options)
Section titled “sendDigits(options)”sendDigits(options: { digits: string; callSid?: string }) => Promise<void>Kirim nada DTMF selama panggilan.
| Param | Type |
|---|---|
options | { digits: string; callSid?: string } |
Event Listeners
Section titled “Event Listeners”Event yang Tersedia
Section titled “Event yang Tersedia”registered- Berhasil terdaftar dengan Twiliounregistered- Tidak terdaftar dari TwilioregistrationFailed- Pendaftaran gagalincomingCall- Panggilan masuk diterimacallConnected- Panggilan berhasil terhubungcallDisconnected- Panggilan terputuscallRinging- Panggilan keluar berderingcallReconnecting- Panggilan sedang terhubung kembalicallReconnected- Panggilan terhubung kembali setelah gangguanqualityWarning- Peringatan kualitas panggilanerror- Terjadi kesalahan
Contoh Event
Section titled “Contoh Event”// 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();Contoh Lengkap
Section titled “Contoh Lengkap”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();Praktik Terbaik
Section titled “Praktik Terbaik”- Ambil token akses dari server backend Anda, jangan pernah menanamkannya di aplikasi
- Implementasikan logika refresh token untuk sesi yang berjalan lama
- Tangani gangguan jaringan dengan logika reconnection
- Berikan umpan balik visual untuk status panggilan
- Uji pada perangkat nyata dengan notifikasi push
- Implementasikan penanganan error yang tepat
- Bersihkan listener ketika komponen di-unmount
- Minta izin mikrofon sebelum melakukan panggilan
Pertimbangan Keamanan
Section titled “Pertimbangan Keamanan”- Jangan pernah menyimpan kredensial Twilio di aplikasi
- Buat token akses di backend Anda
- Implementasikan kadaluarsa dan refresh token
- Gunakan HTTPS untuk semua permintaan token
- Validasi panggilan masuk di sisi server
Pemecahan Masalah
Section titled “Pemecahan Masalah”Panggilan Tidak Terhubung
Section titled “Panggilan Tidak Terhubung”- Verifikasi token akses valid dan tidak kadaluarsa
- Periksa konektivitas jaringan
- Pastikan izin mikrofon diberikan
- Verifikasi akun Twilio dikonfigurasi dengan benar
Notifikasi Push Tidak Berfungsi
Section titled “Notifikasi Push Tidak Berfungsi”- Verifikasi sertifikat PushKit/FCM dikonfigurasi di Twilio
- Periksa perangkat terdaftar untuk notifikasi push
- Uji dengan sertifikat produksi
Masalah Audio
Section titled “Masalah Audio”- Periksa izin mikrofon
- Verifikasi pengaturan speaker/bluetooth
- Uji routing audio pada perangkat nyata
Tampilan Nama Pemanggil (CapacitorTwilioCallerName)
Section titled “Tampilan Nama Pemanggil (CapacitorTwilioCallerName)”Secara default, panggilan masuk menampilkan nomor telepon atau ID klien pemanggil. Anda dapat menyesuaikan ini dengan mengirimkan parameter CapacitorTwilioCallerName dari backend TwiML Anda untuk menampilkan nama ramah sebagai gantinya.
Pengaturan Backend
Section titled “Pengaturan Backend”Saat menghasilkan respons TwiML Anda untuk dial <Client>, tambahkan parameter CapacitorTwilioCallerName:
// 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);Cara Kerjanya
Section titled “Cara Kerjanya”- Ketika backend Anda menerima panggilan masuk, ia menghasilkan TwiML untuk merutekan panggilan
- Sertakan parameter
CapacitorTwilioCallerNamedengan nama tampilan pemanggil - Plugin secara otomatis mengekstrak parameter ini dan menggunakannya untuk:
- Layar panggilan masuk iOS CallKit
- Notifikasi panggilan masuk Android
- Field
fromdalam eventincomingCall - Array
pendingInvitesdalam status panggilan
Jika CapacitorTwilioCallerName tidak disediakan, plugin akan kembali ke nomor telepon atau ID klien pemanggil.