Vai al contenuto

Iniziare con RealtimeKit

Questa guida ti guiderà attraverso l’integrazione del plug-in Capacitor RealtimeKit per aggiungere videoconferenze basate su Cloudflare Calls alla tua applicazione.

Installa il plug-in utilizzando npm:

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

Questo plugin utilizza Cloudflare RealtimeKit SDK:

  • iOS: RealtimeKitCoreiOS (installato automaticamente tramite Swift Package Manager)
  • Android: com.cloudflare.realtimekit:ui-android versione 0.2.2

Personalizzazione della versione Android RealtimeKit

Section titled “Personalizzazione della versione Android RealtimeKit”

Nel build.gradle della tua app:

buildscript {
ext {
realtimekitUiVersion = '0.2.2' // or your desired version
}
}

Aggiungi quanto segue al Info.plist della tua app:

<key>NSCameraUsageDescription</key>
<string>We need camera access for video calls</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need microphone access for audio calls</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need photo library access to share images</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>We need Bluetooth access for audio routing</string>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>voip</string>
<string>fetch</string>
<string>remote-notification</string>
</array>

Aggiungi le seguenti autorizzazioni al tuo AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
import { CapacitorRealtimekit } from '@capgo/capacitor-realtimekit';
async function initializeRealtimeKit() {
try {
await CapacitorRealtimekit.initialize();
console.log('RealtimeKit initialized');
} catch (error) {
console.error('Failed to initialize RealtimeKit:', error);
}
}
async function startMeeting(meetingUrl: string) {
try {
await CapacitorRealtimekit.startMeeting({
url: meetingUrl
});
console.log('Meeting started');
} catch (error) {
console.error('Failed to start meeting:', error);
}
}

Ecco un servizio di videoconferenza completo:

import { CapacitorRealtimekit } from '@capgo/capacitor-realtimekit';
export interface MeetingConfig {
url: string;
displayName?: string;
audioEnabled?: boolean;
videoEnabled?: boolean;
}
export class VideoConferenceService {
private isInitialized = false;
private currentMeetingUrl: string | null = null;
async initialize(): Promise<boolean> {
if (this.isInitialized) {
console.log('RealtimeKit already initialized');
return true;
}
try {
await CapacitorRealtimekit.initialize();
this.isInitialized = true;
console.log('RealtimeKit initialized successfully');
return true;
} catch (error) {
console.error('Failed to initialize RealtimeKit:', error);
return false;
}
}
async startMeeting(config: MeetingConfig): Promise<void> {
if (!this.isInitialized) {
const initialized = await this.initialize();
if (!initialized) {
throw new Error('Failed to initialize RealtimeKit');
}
}
try {
await CapacitorRealtimekit.startMeeting({
url: config.url
});
this.currentMeetingUrl = config.url;
console.log('Meeting started:', config.url);
} catch (error) {
console.error('Failed to start meeting:', error);
throw error;
}
}
async joinMeeting(meetingUrl: string, displayName?: string): Promise<void> {
const config: MeetingConfig = {
url: meetingUrl,
displayName: displayName
};
await this.startMeeting(config);
}
getCurrentMeetingUrl(): string | null {
return this.currentMeetingUrl;
}
isInMeeting(): boolean {
return this.currentMeetingUrl !== null;
}
async getPluginVersion(): Promise<string> {
try {
const result = await CapacitorRealtimekit.getPluginVersion();
return result.version;
} catch (error) {
console.error('Failed to get plugin version:', error);
return 'unknown';
}
}
}
// Usage
const videoService = new VideoConferenceService();
// Initialize on app start
await videoService.initialize();
// Start a meeting
await videoService.startMeeting({
url: 'https://your-cloudflare-calls-url.com/meeting/123'
});
// Join an existing meeting
await videoService.joinMeeting(
'https://your-cloudflare-calls-url.com/meeting/456',
'John Doe'
);

Per utilizzare questo plugin, devi configurare le chiamate Cloudflare:

Iscriviti a Cloudflare se non hai un account.

  1. Passa alla dashboard di Cloudflare
  2. Vai alla sezione Chiamate
  3. Abilita le chiamate API
  4. Ottieni le tue credenziali API

Hai bisogno di un servizio backend per creare URL delle riunioni. Esempio utilizzando Cloudflare Workers:

// Cloudflare Worker example
export default {
async fetch(request: Request): Promise<Response> {
const { pathname } = new URL(request.url);
if (pathname === '/create-meeting') {
const meetingId = generateMeetingId();
const meetingUrl = `https://your-app.calls.cloudflare.com/${meetingId}`;
return new Response(JSON.stringify({
meetingId,
meetingUrl
}), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not found', { status: 404 });
}
};
function generateMeetingId(): string {
return Math.random().toString(36).substring(2, 15);
}

Incontro con configurazione personalizzata

Section titled “Incontro con configurazione personalizzata”
class MeetingManager {
private videoService: VideoConferenceService;
constructor() {
this.videoService = new VideoConferenceService();
}
async createAndJoinMeeting(userName: string): Promise<string> {
// Initialize if needed
await this.videoService.initialize();
// Call your backend to create a meeting
const meetingUrl = await this.createMeetingOnBackend();
// Join the meeting
await this.videoService.joinMeeting(meetingUrl, userName);
return meetingUrl;
}
async createMeetingOnBackend(): Promise<string> {
const response = await fetch('https://your-api.com/create-meeting', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const data = await response.json();
return data.meetingUrl;
}
async shareMeetingLink(meetingUrl: string) {
// Use Capacitor Share API
if ('share' in navigator) {
await (navigator as any).share({
title: 'Join my meeting',
text: 'Join me for a video call',
url: meetingUrl
});
}
}
}
import { Capacitor } from '@capacitor/core';
async function checkAndRequestPermissions(): Promise<boolean> {
if (Capacitor.getPlatform() === 'web') {
// Request browser permissions
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true
});
// Stop the stream, we just needed permission
stream.getTracks().forEach(track => track.stop());
return true;
} catch (error) {
console.error('Permission denied:', error);
return false;
}
}
// On native platforms, permissions are requested automatically
return true;
}
// Use before starting a meeting
const hasPermissions = await checkAndRequestPermissions();
if (hasPermissions) {
await videoService.startMeeting({ url: meetingUrl });
}
import { useEffect, useState } from 'react';
import { VideoConferenceService } from './VideoConferenceService';
function VideoCallComponent() {
const [videoService] = useState(() => new VideoConferenceService());
const [isReady, setIsReady] = useState(false);
useEffect(() => {
videoService.initialize().then(setIsReady);
}, []);
const joinMeeting = async (meetingUrl: string) => {
if (!isReady) {
console.error('Video service not ready');
return;
}
try {
await videoService.joinMeeting(meetingUrl, 'User Name');
} catch (error) {
console.error('Failed to join meeting:', error);
}
};
return (
<div>
<button
onClick={() => joinMeeting('https://your-meeting-url')}
disabled={!isReady}
>
Join Meeting
</button>
</div>
);
}
import { ref, onMounted } from 'vue';
import { VideoConferenceService } from './VideoConferenceService';
export default {
setup() {
const videoService = new VideoConferenceService();
const isReady = ref(false);
onMounted(async () => {
isReady.value = await videoService.initialize();
});
const joinMeeting = async (meetingUrl: string) => {
if (!isReady.value) {
console.error('Video service not ready');
return;
}
try {
await videoService.joinMeeting(meetingUrl, 'User Name');
} catch (error) {
console.error('Failed to join meeting:', error);
}
};
return {
isReady,
joinMeeting
};
}
};
  1. Inizializza anticipatamente: inizializza RealtimeKit all’avvio dell’app
  2. Gestisci errori: racchiudi sempre le chiamate in blocchi try-catch
  3. Richiedi autorizzazioni: assicurati le autorizzazioni della fotocamera/microfono prima di iniziare
  4. Rete di prova: controlla la connettività Internet prima di accedere
  5. Audio di sottofondo: configura le modalità di sottofondo per iOS
  6. Esperienza utente: mostra gli stati di caricamento durante l’inizializzazione
  7. Pulisci URL: convalida gli URL delle riunioni prima dell’uso
async function troubleshootMeeting(meetingUrl: string) {
// Check initialization
const version = await videoService.getPluginVersion();
console.log('Plugin version:', version);
// Verify URL format
if (!meetingUrl.startsWith('https://')) {
console.error('Invalid meeting URL, must use HTTPS');
return;
}
// Try starting meeting
try {
await videoService.startMeeting({ url: meetingUrl });
} catch (error) {
console.error('Meeting failed:', error);
}
}

Su iOS, assicurati che Info.plist contenga tutte le descrizioni di utilizzo richieste. Su Android, verifica che siano presenti le autorizzazioni AndroidManifest.xml.

Assicurati che la modalità audio di sottofondo sia configurata in Info.plist:

<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>voip</string>
</array>