Getting Started with RealtimeKit
Konten ini belum tersedia dalam bahasa Anda.
This guide will walk you through integrating the Capacitor RealtimeKit plugin to add video conferencing powered by Cloudflare Calls to your application.
Installation
Install the plugin using npm:
npm install @capgo/capacitor-realtimekitnpx cap syncDependencies
This plugin uses the Cloudflare RealtimeKit SDK:
- iOS: RealtimeKitCoreiOS (automatically installed via Swift Package Manager)
- Android:
com.cloudflare.realtimekit:ui-androidversion0.2.2
Customizing Android RealtimeKit Version
In your app’s build.gradle:
buildscript { ext { realtimekitUiVersion = '0.2.2' // or your desired version }}iOS Configuration
Add the following to your app’s Info.plist:
<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>Android Configuration
Add the following permissions to your 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" />Basic Usage
Import the Plugin
import { CapacitorRealtimekit } from '@capgo/capacitor-realtimekit';Initialize the Plugin
async function initializeRealtimeKit() { try { await CapacitorRealtimekit.initialize(); console.log('RealtimeKit initialized'); } catch (error) { console.error('Failed to initialize RealtimeKit:', error); }}Start a Meeting
async function startMeeting(meetingUrl: string) { try { await CapacitorRealtimekit.startMeeting({ url: meetingUrl }); console.log('Meeting started'); } catch (error) { console.error('Failed to start meeting:', error); }}Complete Example
Here’s a comprehensive video conferencing service:
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'; } }}
// Usageconst videoService = new VideoConferenceService();
// Initialize on app startawait videoService.initialize();
// Start a meetingawait videoService.startMeeting({ url: 'https://your-cloudflare-calls-url.com/meeting/123'});
// Join an existing meetingawait videoService.joinMeeting( 'https://your-cloudflare-calls-url.com/meeting/456', 'John Doe');Cloudflare Calls Setup
To use this plugin, you need to set up Cloudflare Calls:
1. Create Cloudflare Account
Sign up at Cloudflare if you don’t have an account.
2. Enable Calls API
- Navigate to your Cloudflare dashboard
- Go to Calls section
- Enable the Calls API
- Get your API credentials
3. Create Meeting URLs
You need a backend service to create meeting URLs. Example using Cloudflare Workers:
// Cloudflare Worker exampleexport 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);}Advanced Usage
Meeting with Custom Configuration
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 }); } }}Handling Permissions
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 meetingconst hasPermissions = await checkAndRequestPermissions();if (hasPermissions) { await videoService.startMeeting({ url: meetingUrl });}React Integration
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> );}Vue Integration
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 }; }};Best Practices
- Initialize Early: Initialize RealtimeKit when your app starts
- Handle Errors: Always wrap calls in try-catch blocks
- Request Permissions: Ensure camera/microphone permissions before starting
- Test Network: Check internet connectivity before joining
- Background Audio: Configure background modes for iOS
- User Experience: Show loading states during initialization
- Clean URLs: Validate meeting URLs before use
Common Issues
Meeting Not Starting
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); }}Permission Denied
On iOS, ensure Info.plist has all required usage descriptions. On Android, verify AndroidManifest.xml permissions are present.
Audio Issues on iOS
Ensure background audio mode is configured in Info.plist:
<key>UIBackgroundModes</key><array> <string>audio</string> <string>voip</string></array>Next Steps
- Explore the API Reference for complete method documentation
- Read Cloudflare Calls Documentation
- Check out the example app
- See the tutorial for complete implementation