UNPKG

react-native-nitro-screen-recorder

Version:

A library to capture screen recordings with react-native powered by NitroModules.

373 lines (350 loc) 11.6 kB
import { NitroModules } from 'react-native-nitro-modules'; import type { NitroScreenRecorder } from './NitroScreenRecorder.nitro'; import type { ScreenRecordingFile, PermissionResponse, InAppRecordingInput, ScreenRecordingEvent, PermissionStatus, GlobalRecordingInput, BroadcastPickerPresentationEvent, } from './types'; import { Platform } from 'react-native'; const NitroScreenRecorderHybridObject = NitroModules.createHybridObject<NitroScreenRecorder>('NitroScreenRecorder'); const isAndroid = Platform.OS === 'android'; // ============================================================================ // PERMISSIONS // ============================================================================ /** * Gets the current camera permission status without requesting permission. * * @platform iOS, Android * @returns The current permission status for camera access * @example * ```typescript * const status = getCameraPermissionStatus(); * if (status === 'granted') { * // Camera is available * } * ``` */ export function getCameraPermissionStatus(): PermissionStatus { return NitroScreenRecorderHybridObject.getCameraPermissionStatus(); } /** * Gets the current microphone permission status without requesting permission. * * @platform iOS, Android * @returns The current permission status for microphone access * @example * ```typescript * const status = getMicrophonePermissionStatus(); * if (status === 'granted') { * // Microphone is available * } * ``` */ export function getMicrophonePermissionStatus(): PermissionStatus { return NitroScreenRecorderHybridObject.getMicrophonePermissionStatus(); } /** * Requests camera permission from the user if not already granted. * Shows the system permission dialog if permission hasn't been determined. * * @platform iOS, Android * @returns Promise that resolves with the permission response * @example * ```typescript * const response = await requestCameraPermission(); * if (response.status === 'granted') { * // Permission granted, can use camera * } * ``` */ export async function requestCameraPermission(): Promise<PermissionResponse> { return NitroScreenRecorderHybridObject.requestCameraPermission(); } /** * Requests microphone permission from the user if not already granted. * Shows the system permission dialog if permission hasn't been determined. * * @platform iOS, Android * @returns Promise that resolves with the permission response * @example * ```typescript * const response = await requestMicrophonePermission(); * if (response.status === 'granted') { * // Permission granted, can record audio * } * ``` */ export async function requestMicrophonePermission(): Promise<PermissionResponse> { return NitroScreenRecorderHybridObject.requestMicrophonePermission(); } // ============================================================================ // IN-APP RECORDING // ============================================================================ /** * Starts in-app screen recording with the specified configuration. * Records only the current app's content, not system-wide screen content. * * @platform iOS * @param input Configuration object containing recording options and callbacks * @returns Promise that resolves when recording starts successfully * @example * ```typescript * await startInAppRecording({ * options: { * enableMic: true, * enableCamera: true, * cameraDevice: 'front', * cameraPreviewStyle: { width: 100, height: 150, top: 30, left: 10 } * }, * onRecordingFinished: (file) => { * console.log('Recording saved:', file.path); * } * }); * ``` */ export async function startInAppRecording( input: InAppRecordingInput ): Promise<void> { if (isAndroid) { console.warn('`startInAppRecording` is only supported on iOS.'); return; } if ( input.options.enableMic && getMicrophonePermissionStatus() !== 'granted' ) { throw new Error('Microphone permission not granted.'); } if (input.options.enableCamera && getCameraPermissionStatus() !== 'granted') { throw new Error('Camera permission not granted.'); } // Handle camera options based on enableCamera flag if (input.options.enableCamera) { return NitroScreenRecorderHybridObject.startInAppRecording( input.options.enableMic, input.options.enableCamera, input.options.cameraPreviewStyle ?? {}, input.options.cameraDevice, input.onRecordingFinished // input.onRecordingError ); } else { return NitroScreenRecorderHybridObject.startInAppRecording( input.options.enableMic, input.options.enableCamera, {}, 'front', input.onRecordingFinished // input.onRecordingError ); } } /** * Stops the current in-app recording and saves the recorded video. * The recording file will be provided through the onRecordingFinished callback. * * @platform iOS-only * @example * ```typescript * stopInAppRecording(); // File will be available in onRecordingFinished callback * ``` */ export async function stopInAppRecording(): Promise< ScreenRecordingFile | undefined > { if (isAndroid) { console.warn('`stopInAppRecording` is only supported on iOS.'); return; } return NitroScreenRecorderHybridObject.stopInAppRecording(); } /** * Cancels the current in-app recording without saving the video. * No file will be generated and onRecordingFinished will not be called. * * @platform iOS-only * @example * ```typescript * cancelInAppRecording(); // Recording discarded, no file saved * ``` */ export async function cancelInAppRecording(): Promise<void> { if (isAndroid) { console.warn('`cancelInAppRecording` is only supported on iOS.'); return; } return NitroScreenRecorderHybridObject.cancelInAppRecording(); } // ============================================================================ // GLOBAL RECORDING // ============================================================================ /** * Starts global screen recording that captures the entire device screen. * Records system-wide content, including other apps and system UI. * Requires screen recording permission on iOS. * * @platform iOS, Android * @example * ```typescript * startGlobalRecording(); * // User can now navigate to other apps while recording continues * ``` */ export function startGlobalRecording(input: GlobalRecordingInput): void { // On IOS, the user grants microphone permission via a picker toggle // button, so we don't need this check first if ( input.options?.enableMic && isAndroid && getMicrophonePermissionStatus() !== 'granted' ) { throw new Error('Microphone permission not granted.'); } return NitroScreenRecorderHybridObject.startGlobalRecording( input?.options?.enableMic ?? false, input?.onRecordingError ); } /** * Stops the current global screen recording and saves the video. * The recorded file can be retrieved using retrieveLastGlobalRecording(). * * @platform Android/ios * @param options.settledTimeMs A "delay" time to wait before the function * tries to retrieve the file from the asset writer. It can take some time * to finish completion and correclty return the file. Default = 500ms * @example * ```typescript * const file = await stopGlobalRecording({ settledTimeMs: 1000 }); * if (file) { * console.log('Global recording saved:', file.path); * } * ``` */ export async function stopGlobalRecording(options?: { settledTimeMs: number; }): Promise<ScreenRecordingFile | undefined> { let settledTimeMs = 500; if (options?.settledTimeMs) { if ( typeof options.settledTimeMs !== 'number' || options.settledTimeMs <= 0 ) { console.warn( 'Provided invalid value to `settledTimeMs` in `stopGlobalRecording` function, value will be ignored. Please use a value >0' ); } else { settledTimeMs = options.settledTimeMs; } } return NitroScreenRecorderHybridObject.stopGlobalRecording(settledTimeMs); } /** * Retrieves the most recently completed global recording file. * Returns undefined if no global recording has been completed. * * @platform iOS, Android * @returns The last global recording file or undefined if none exists * @example * ```typescript * const lastRecording = retrieveLastGlobalRecording(); * if (lastRecording) { * console.log('Duration:', lastRecording.duration); * console.log('File size:', lastRecording.size); * } * ``` */ export function retrieveLastGlobalRecording(): ScreenRecordingFile | undefined { return NitroScreenRecorderHybridObject.retrieveLastGlobalRecording(); } // ============================================================================ // EVENT LISTENERS // ============================================================================ /** * Adds a listener for screen recording events (began, ended, etc.). * Returns a cleanup function to remove the listener when no longer needed. * * @platform iOS, Android * @param listener Callback function that receives screen recording events * @returns Cleanup function to remove the listener * @example * ```typescript * useEffect(() => { * const removeListener = addScreenRecordingListener((event: ScreenRecordingEvent) => { * console.log("Event type:", event.type, "Event reason:", event.reason) * }); * // Later, remove the listener * return () => removeListener(); * },[]) * ``` */ export function addScreenRecordingListener({ listener, ignoreRecordingsInitiatedElsewhere = false, }: { listener: (event: ScreenRecordingEvent) => void; ignoreRecordingsInitiatedElsewhere: boolean; }): () => void { let listenerId: number; listenerId = NitroScreenRecorderHybridObject.addScreenRecordingListener( ignoreRecordingsInitiatedElsewhere, listener ); return () => { NitroScreenRecorderHybridObject.removeScreenRecordingListener(listenerId); }; } /** * Adds a listener for ios only to track whether (start, stop, error, etc.). * Returns a cleanup function to remove the listener when no longer needed. * * @platform iOS * @param listener Callback function that receives the status of the BroadcastPickerView * on ios * @returns Cleanup function to remove the listener * @example * ```typescript * useEffect(() => { * const removeListener = addBroadcastPickerListener((event: BroadcastPickerPresentationEvent) => { * console.log("Picker status", event) * }); * // Later, remove the listener * return () => removeListener(); * },[]) * ``` */ export function addBroadcastPickerListener( listener: (event: BroadcastPickerPresentationEvent) => void ): () => void { if (Platform.OS === 'android') { // return a no-op cleanup function return () => {}; } let listenerId: number; listenerId = NitroScreenRecorderHybridObject.addBroadcastPickerListener(listener); return () => { NitroScreenRecorderHybridObject.removeBroadcastPickerListener(listenerId); }; } // ============================================================================ // UTILITIES // ============================================================================ /** * Clears all cached recording files to free up storage space. * This will delete temporary files but not files that have been explicitly saved. * * @platform iOS, Android * @example * ```typescript * clearCache(); // Frees up storage by removing temporary recording files * ``` */ export function clearCache(): void { return NitroScreenRecorderHybridObject.clearRecordingCache(); }