One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

Screen capture

Observe screen capture and save a PNG of the app window or a React Native view.

One.ScreenCapture reports the capture state and notifies your app after a person takes a screenshot. It requires an iOS or Android native build. On Android the screenshot callback needs API 34+, the recording state needs API 35+, and capture needs API 26+; both detect permissions are install-time and ride the library manifest.

import { One } from 'one'
const state = await One.ScreenCapture.getState()
const removeState = One.ScreenCapture.addStateListener((nextState) => {
// hide sensitive content while nextState is 'active'
})
const removeScreenshot = One.ScreenCapture.addScreenshotListener((timestampMs) => {
// record an audit event after the screenshot was taken
})
// call both removers when this screen no longer needs updates
removeState()
removeScreenshot()

To save the current app window as a PNG, call captureWindow() while the app is foregrounded. The returned uri is a local file:// URL under Library/Caches/OneScreenCapture on iOS and the app cache’s OneScreenCapture folder on Android. width and height are pixels at the window’s native scale; size is the PNG file size in bytes. Remove the file when finished with it.

const image = await One.ScreenCapture.captureWindow()
try {
// use image.uri with a file upload, share sheet, or image view
} finally {
await One.FileSystem.delete(image.uri)
}

The PNG contains the app window’s rendered content. It excludes system UI drawn in other windows, including the status bar. It does not take an OS screenshot or trigger addScreenshotListener.

To capture one mounted React Native view, pass its native tag from findNodeHandle() to captureView(). Set collapsable={false} on the target view: Fabric can otherwise mount its children beside it, and a view-only PNG can silently omit those children. The returned file has the same { uri, width, height, size } shape as captureWindow(). Its dimensions are the target’s bounds in pixels at the active window’s native scale.

import { useRef, type ComponentRef } from 'react'
import { findNodeHandle, View } from 'react-native'
import { One } from 'one'
const target = useRef<ComponentRef<typeof View>>(null)
// render <View ref={target} collapsable={false}>...</View> before capturing
const tag = findNodeHandle(target.current)
if (tag == null) throw new Error('target view is not mounted')
const image = await One.ScreenCapture.captureView(tag)
try {
// use image.uri with a file upload, share sheet, or image view
} finally {
await One.FileSystem.delete(image.uri)
}

Capture the tag while the view is mounted. captureView() renders that view’s subtree at call time. It does not include sibling views or system UI. On Android the tag must resolve to a view attached to the current activity’s window; PixelCopy then copies that view’s bounds.

getState() resolves to active when the scene is being recorded or mirrored, inactive when it is not, and unspecified when the platform has not determined a state. On iOS the state comes from UIKit’s scene capture state; on Android API 35+ it comes from the window manager’s recording visibility for this app, and below API 35 it is always unspecified. addStateListener() reports changes after registration; call getState() to read the current state. The screenshot listener receives a Unix timestamp in milliseconds stamped when the notification arrives. On Android the screenshot notification comes from the API 34 activity callback and is activity-scoped: ADB and instrumentation captures do not trigger it, and below API 34 the listener stays silent.

getState() rejects with E_SCREEN_CAPTURE_SCENE if there is no active window scene. captureWindow() uses that scene and rejects with E_SCREEN_CAPTURE_SCENE when there is no app window, E_SCREEN_CAPTURE_RENDER if the platform cannot draw it, E_SCREEN_CAPTURE_ENCODE if PNG encoding fails, or E_SCREEN_CAPTURE_FILE if the file cannot be saved. captureView() uses the same scene and PNG errors; it rejects with E_SCREEN_CAPTURE_VIEW if the tag no longer resolves to a mounted view in the active app window. Its JS wrapper throws TypeError for a non-integer, non-positive, or out-of-range tag. A direct Nitro call instead rejects with E_SCREEN_CAPTURE_INPUT for those values. On Android below API 26 both capture calls reject with E_SCREEN_CAPTURE_RENDER and an explicit unsupported-platform message.

Screenshot notification arrives after the image is captured, so it cannot prevent or redact that screenshot. For recording and mirroring, update your own content when the capture state changes. Verify screenshot and recording behavior on a physical device: simulator command-line capture reads the host framebuffer without exercising in-app notifications or scene state.

Screen capture is implemented on iOS and Android. On web, getState() resolves unspecified, listeners return a remover that does nothing, and capture calls reject with ScreenCapture.<verb> needs an iOS or Android build.

Edit this page on GitHub.