> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.jambonz.org/sdks/webrtc-react-native/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.jambonz.org/_mcp/server. # React Native Guide This guide walks you through building a voice calling app for iOS and Android using React Native. > **Note** > > The SDK works on both simulators/emulators and physical devices. A physical device is recommended for real call testing with audio. ## Step 1: Create a React Native Project ```bash npx @react-native-community/cli init MyJambonzApp cd MyJambonzApp ``` ## Step 2: Install the SDK ```bash npm install @jambonz/client-sdk-react-native react-native-webrtc ``` For iOS: ```bash cd ios && pod install && cd .. ``` ## Step 3: Android Permissions Add to `android/app/src/main/AndroidManifest.xml` inside ``: ```xml ``` ## Step 4: iOS Permissions Add to `ios/MyJambonzApp/Info.plist`: ```xml NSMicrophoneUsageDescription Required for voice calls ``` ## Step 5: Connect to the SBC ```tsx // App.tsx import React, { useState } from 'react'; import { View, Text, TextInput, Pressable } from 'react-native'; import { createJambonzClient, JambonzClient, ClientState, } from '@jambonz/client-sdk-react-native'; function App() { const [client, setClient] = useState(null); const [state, setState] = useState(ClientState.Disconnected); const connect = async () => { const c = createJambonzClient({ server: 'wss://sbc.example.com:8443', username: 'your-username', password: 'your-password', }); c.on('stateChanged', (s) => setState(s)); c.on('error', (err) => console.log('Error:', err.message)); await c.connect(); setClient(c); }; return ( Status: {state} Connect ); } export default App; ``` Run on your device: ```bash # Android npx react-native run-android # iOS (physical device only) npx react-native run-ios --device ``` ## Step 6: Make an Outbound Call ```tsx const [call, setCall] = useState(null); const [callState, setCallState] = useState(null); const makeCall = (target: string) => { if (!client) return; const newCall = client.call(target); newCall.on('stateChanged', (s) => setCallState(s)); newCall.on('ended', () => { setCall(null); setCallState(null); }); newCall.on('failed', () => { setCall(null); setCallState(null); }); setCall(newCall); }; // In your JSX: makeCall('+15551234567')}> Call call?.hangup()}> Hang Up ``` ## Step 7: Handle Incoming Calls Use React Native's `Alert` for a simple incoming call prompt: ```tsx import { Alert } from 'react-native'; // After creating the client: c.on('incoming', (incomingCall) => { Alert.alert( 'Incoming Call', `From: ${incomingCall.remoteIdentity}`, [ { text: 'Decline', style: 'destructive', onPress: () => incomingCall.hangup(), }, { text: 'Answer', onPress: () => { incomingCall.answer(); setCall(incomingCall); // Bind call events... }, }, ], ); }); ``` ## Step 8: Add Call Controls ```tsx const [isMuted, setIsMuted] = useState(false); const [isHeld, setIsHeld] = useState(false); // Bind events on the call: newCall.on('mute', (muted) => setIsMuted(muted)); newCall.on('hold', (held) => setIsHeld(held)); // In your JSX: call?.toggleMute()}> {isMuted ? 'Unmute' : 'Mute'} isHeld ? call?.unhold() : call?.hold()}> {isHeld ? 'Resume' : 'Hold'} ``` ## Step 9: Call Different Targets ```tsx // Call another registered user client.callUser('alice'); // Take a call from a queue client.callQueue('support'); // Join a conference room client.callConference('standup-meeting'); // Call a jambonz application client.callApplication('your-app-sid'); ``` ## Step 10: Using React Hooks (Alternative) ```tsx import { useJambonzClient, useCall } from '@jambonz/client-sdk-react-native'; function Phone() { const client = useJambonzClient({ server: 'wss://sbc.example.com:8443', username: 'your-username', password: 'your-password', }); const call = useCall(client.client); return ( Status: {client.state} {!client.isRegistered && ( Connect )} {client.isRegistered && !call.isActive && ( call.makeCall('+15551234567')}> Call )} {call.isActive && ( <> Call: {call.state} {call.isMuted ? 'Unmute' : 'Mute'} Hang Up )} ); } ``` ## Android Notes * **JDK 17+** required — install via `brew install --cask zulu@17` * **USB debugging** must be enabled for physical devices * Works on both emulator and physical device ## iOS Notes * **Xcode 15+** required * You must configure **code signing** in Xcode (Signing & Capabilities tab) * Add **microphone permission** in Info.plist * Works on both simulator and physical device (physical device recommended for real calls) ## Run the Full Example App The repo includes a complete softphone example with a dark theme UI, DTMF dial pad, incoming call handling, mute/hold/hangup controls. ```bash # 1. Clone the repo git clone https://github.com/jambonz/webrtc-sdk.git cd webrtc-sdk # 2. Install and build the SDK npm install npm run build # 3. Install the React Native example cd examples/react-native npm install # 4. Generate the native projects npx @react-native-community/cli init JambonzExample --directory /tmp/JambonzExample --skip-install cp -r /tmp/JambonzExample/android ./android cp -r /tmp/JambonzExample/ios ./ios rm -rf /tmp/JambonzExample ``` After generating, add the required permissions: **Android** — add to `android/app/src/main/AndroidManifest.xml` inside ``: ```xml ``` **iOS** — add to `ios/JambonzExample/Info.plist` before ``: ```xml NSMicrophoneUsageDescription Required for voice calls ``` #### Run on Android ```bash # Start Metro bundler npx react-native start # In another terminal — run on device or emulator npx react-native run-android ``` #### Run on iOS ```bash # Install CocoaPods cd ios && pod install && cd .. # Open Xcode to configure signing open ios/JambonzExample.xcworkspace # → Select your Team in Signing & Capabilities # → Change Bundle Identifier to something unique # Start Metro bundler npx react-native start # In another terminal — run on device or simulator npx react-native run-ios # Or for a specific device: npx react-native run-ios --device ``` #### What the example includes The example app has clean separation between SDK logic and UI: * **`src/useJambonz.ts`** — all SDK interactions (connect, call, mute, hold, transfer, incoming calls). **Read this file to learn the SDK.** * **`src/App.tsx`** — wires SDK state to UI components * **`src/components/`** — reusable UI: ConnectionForm, DialerView, ActiveCallView, IncomingCallView, DtmfPad * **`src/theme.ts`** — shared color palette #### How to use it 1. Enter your jambonz SBC WebSocket URL (e.g. `wss://sbc.example.com:8443`) 2. Enter your SIP username and password 3. Tap **Connect** — status dot turns green when registered 4. Enter a number or SIP target and tap **Call** 5. Use the in-call controls: mute, hold, DTMF pad, hang up 6. Incoming calls show an answer/decline prompt Source: [github.com/jambonz/webrtc-sdk/tree/main/examples/react-native](https://github.com/jambonz/webrtc-sdk/tree/main/examples/react-native) > Build an iOS + Android softphone with the jambonz WebRTC SDK