Alaznah

Microphone, camera, and notification permissions for Alaznah Calling.

Permissions

Two layers:

  1. Native configInfo.plist / AndroidManifest.xml (required before the OS will prompt)
  2. RuntimerequestCallPermissions before the first call

Rebuild the native app after changing plist or manifest.

Which permissions do you need?

App offersNative micNative cameraRuntime call
Voice onlyYesNorequestCallPermissions('audio')
Video onlyYesYesrequestCallPermissions('video')
Voice and videoYesYes'audio' or 'video' for the upcoming call (or 'video' at startup for mic + camera)

Runtime (JavaScript)

ts
import { requestCallPermissions } from '@alaznah/calling';

// for audio call
const audio = await requestCallPermissions('audio');
if (!audio.microphone) {
  // show UI — mic denied
}

// for video call (mic + camera)
const video = await requestCallPermissions('video');
if (!video.microphone || !video.camera) {
  // show UI — denied
}

'audio' | 'video'. Returns { microphone, camera, bluetooth }.

On iOS, system prompts often appear on first getUserMedia; plist strings must still be present or the app can crash.

iOS — Info.plist

Add usage descriptions (edit ios/<AppName>/Info.plist or Xcode → Info):

xml
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is required for audio and video calls.</string>

<!-- Required if your app places or accepts video calls -->
<key>NSCameraUsageDescription</key>
<string>Camera access is required for video calls.</string>

Background modes (calling)

Xcode → Signing & Capabilities → Background Modes, enable at least:

  • Audio, AirPlay, and Picture in Picture (audio) — keep call audio in background
  • Voice over IP (voip) — VoIP / PushKit wake

Or in plist:

xml
<key>UIBackgroundModes</key>
<array>
  <string>audio</string>
  <string>voip</string>
  <string>remote-notification</string>
</array>

Also enable Push Notifications capability. CallKit / PushKit setup: Background Calling.

Voice-only vs video (iOS)

Key / capabilityVoice onlyVideo / both
NSMicrophoneUsageDescriptionRequiredRequired
NSCameraUsageDescriptionOptionalRequired
Background Modes → AudioRecommendedRecommended
Background Modes → VoIPFor kill/background ringFor kill/background ring

Android — AndroidManifest.xml

In android/app/src/main/AndroidManifest.xml, inside <manifest> (before <application>):

Minimum (voice)

xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Add for video (or voice + video app)

xml
<uses-permission android:name="android.permission.CAMERA" />
xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

@alaznah/calling already declares several of these in its library manifest; merging usually picks them up. If a permission is missing after install, add it explicitly in the app manifest as above.

Voice-only vs video (Android)

PermissionVoice onlyVideo / both
INTERNETRequiredRequired
RECORD_AUDIORequiredRequired
CAMERARequired
MODIFY_AUDIO_SETTINGSRecommendedRecommended
POST_NOTIFICATIONSAPI 33+ notifyAPI 33+ notify
BLUETOOTH_CONNECTHeadsetsHeadsets
Full-screen / FGSNative incoming + keep-aliveNative incoming + keep-alive + PiP

What the SDK adds automatically (no host Kotlin/Java)

After npm install @alaznah/calling, the library manifest merges into your app:

Merged by SDKPurpose
IncomingCallActivity, foreground services, action receiverNative incoming UI + call keep-alive
CallMessagingReceiver + removes default RN Firebase messaging receiverKill-state call invite/cancel before flaky headless JS (requires @react-native-firebase/messaging for non-call FCM)
android:supportsPictureInPicture on ${applicationId}.MainActivityAndroid video PiP on Home
AlaznahPipActivityAndroid Minimize-button system PiP

You do not add CallMessagingReceiver, PiP manifest flags, or MainActivity onUserLeaveHint overrides for a standard React Native app whose launcher Activity is named MainActivity. Full list: Native Modules.

Custom launcher Activity name? If your main Activity is not <applicationId>.MainActivity, add PiP support manually:

xml
<activity
  android:name=".YourMainActivity"
  android:supportsPictureInPicture="true"
  android:resizeableActivity="true" />

Push: Wire FCM in Firebase + Background Calling. The SDK receiver handles Alaznah call payloads; other FCM messages still flow to React Native Firebase when that package is installed.

iOS — Picture-in-Picture (video calls)

Dedicated guide: Picture in Picture. Host setup (plist, patch, rebuild): Native Modules.

No host AppDelegate / Swift PiP code. @alaznah/calling ships:

SDK native (automatic)Purpose
AlaznahCallingBootstrap (+load)CallKit + PushKit, WebRTC multitasking camera, CallKit ↔ WebRTC audio bridge
AlaznahCallingPip moduleReports PiP support to JS
enableBackgroundCamera / reportCallConnectedCamera + CallKit session for PiP mute/end chrome
ActiveCallScreen + react-native-webrtc iosPIPAVKit PiP on the remote video view when the app backgrounds

Host Info.plist only (see iOS — Info.plist above):

  • NSCameraUsageDescription + NSMicrophoneUsageDescription
  • Background Modes → Audio (audio in UIBackgroundModes) — required for video PiP while backgrounded
  • VoIP (voip) — kill/background incoming via PushKit (not PiP itself, but same calling stack)

Expo: the @alaznah/calling config plugin injects audio, voip, and remote-notification background modes.

Simulator: iOS Simulator does not support AVKit Picture-in-Picture. AlaznahCallingPip.isSupported() returns false on simulator — this is expected. Test PiP on a physical iPhone (iOS 15+). In-app minimize bubble still works on simulator.

Custom PiP: Do not add your own AVPictureInPictureController in the host app — the SDK + react-native-webrtc own the video PiP path.

Expo

Expo Go is not supported. Use a development build with the @alaznah/calling config plugin — Installation. Still verify the generated plist / manifest after prebuild.

Checklist

  1. Add Info.plist / AndroidManifest entries for the features you ship
  2. Rebuild the native app (Metro reload is not enough)
  3. Call requestCallPermissions('audio') or requestCallPermissions('video') before the first call
  4. Re-check after the user revokes permission in system Settings