UNPKG

react-native-nitro-screen-recorder

Version:

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

156 lines (145 loc) 5.09 kB
import { useState, useEffect } from 'react'; import { addBroadcastPickerListener, addScreenRecordingListener, retrieveLastGlobalRecording, } from '../functions'; import { ScreenRecordingFile } from '../types'; /** * A "modern" sleep statement. * * @param ms The number of milliseconds to wait. */ const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve as () => void, ms)); /** * Configuration options for the global recording hook. */ type GlobalRecordingHookInput = { /** * Callback invoked when a global screen recording begins. * Use this to update your UI to indicate recording is in progress. */ onRecordingStarted?: () => void; /** * Callback invoked when a global screen recording finishes. * Receives the recorded file (if successfully retrieved) or undefined if retrieval failed. * * @param file The screen recording file, or undefined if retrieval failed */ onRecordingFinished?: (file?: ScreenRecordingFile) => void; /** * A callback for iOS when the broadcast modal shows, in case you want to * perform some analytics or tasks. Is a no-op on android. */ onBroadcastModalShown?: () => void; /* A callback for iOS when the broadcast modal is dimissed, in case you want to * perform some analytics or tasks. Is a no-op on android. */ onBroadcastModalDismissed?: () => void; /** * Time in milliseconds to wait after recording ends before attempting to retrieve the file. * This allows the system time to finish writing the recording to disk. * * @default 500 */ settledTimeMs?: number; /** * This property is passed to the underlying listener to ignore recordings that were initiated by the * external system. This is useful if you only want to track global recordings that were started via the startGlobalRecording function. */ ignoreRecordingsInitiatedElsewhere?: boolean; }; /** * Return value from the global recording hook. */ type GlobalRecordingHookOutput = { /** * Whether a global screen recording is currently active. * Updates automatically as recordings start and stop. */ isRecording: boolean; }; /** * React hook for monitoring and responding to global screen recording events. * * This hook automatically tracks the state of global screen recordings (recordings * that capture the entire device screen, not just your app) and provides callbacks * for when recordings start and finish. It also manages the timing of file retrieval * to ensure the recording file is fully written before attempting to access it. * * **Key Features:** * - Automatically tracks global recording state * - Provides lifecycle callbacks for recording start/finish events * - Handles timing delays for safe file retrieval * - Filters out within-app recordings (only responds to global recordings) * * **Use Cases:** * - Show recording indicators in your UI * - Automatically upload or process completed recordings * - Trigger analytics events for recording usage * - Update app state based on recording activity * * @param props Configuration options for the hook * @returns Object containing the current recording state * * @example * ```tsx * const { isRecording } = useGlobalRecording({ * onRecordingStarted: () => { * analytics.track('recording_started'); * }, * onBroadcastModalShown: () => { * console.log("User tried to initiate recording") * }, * onBroadcastModalDismissed: () => { * redirectToAnotherApp() * }, * onRecordingFinished: async (file) => { * if (file) { * try { * await uploadRecording(file); * showSuccessToast('Recording uploaded successfully!'); * } catch (error) { * showErrorToast('Failed to upload recording'); * } * } * }, * }); * ``` */ export const useGlobalRecording = ( props?: GlobalRecordingHookInput ): GlobalRecordingHookOutput => { const [isRecording, setIsRecording] = useState(false); useEffect(() => { const unsubscribe = addScreenRecordingListener({ ignoreRecordingsInitiatedElsewhere: props?.ignoreRecordingsInitiatedElsewhere ?? false, listener: async (event) => { if (event.type === 'withinApp') return; if (event.reason === 'began') { setIsRecording(true); props?.onRecordingStarted?.(); } else { setIsRecording(false); // We add a small delay after the recording ends to allow the file to finish writing // to disk before trying to fetch it delay(props?.settledTimeMs ?? 500); const file = retrieveLastGlobalRecording(); props?.onRecordingFinished?.(file); } }, }); return unsubscribe; }, [props]); useEffect(() => { const unsubscribe = addBroadcastPickerListener((event) => { event === 'dismissed' ? props?.onBroadcastModalDismissed?.() : props?.onBroadcastModalShown?.(); }); return unsubscribe; }, [props]); return { isRecording }; };