
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
react-native-torch-nitro
Advanced tools
A high-performance React Native library for controlling the device's flashlight/torch, powered by NitroModules.
https://github.com/user-attachments/assets/919be4f9-5d0b-45f0-a533-abf86ddd65f6
Try it yourself: Check out the full example app in the
example/folder.
useTorch() hookminSdk >= 23 (Android 6.0 Marshmallow) for basic torch functionalitycompileSdk >= 34 (required by react-native-nitro-modules)react-native-nitro-modules >= 0.3x.xUsing npm:
npm install react-native-torch-nitro react-native-nitro-modules
Using yarn:
yarn add react-native-torch-nitro react-native-nitro-modules
Using pnpm:
pnpm add react-native-torch-nitro react-native-nitro-modules
react-native-nitro-modulesis required as this library relies on Nitro Modules.
cd ios && pod install
No additional configuration required. Camera/flashlight access doesn't require special permissions on iOS for torch usage.
No additional permissions required! Since Android 6.0 (API 23), the CameraManager.setTorchMode() API doesn't require CAMERA permission.
Optionally, you can add a feature declaration to your AndroidManifest.xml to indicate flash support:
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
The
android:required="false"attribute allows your app to run on devices without a flash, but you should handleNoFlashAvailableerrors appropriately.
import React, { useState } from 'react'
import { View, Button, Text, Slider } from 'react-native'
import { useTorch } from 'react-native-torch-nitro'
export default function App() {
const [currentLevel, setCurrentLevel] = useState<number | null>(null)
const { on, off, setLevel, getMaxLevel } = useTorch({
onStateChanged: (state) => {
console.log('Torch is now:', state ? 'ON' : 'OFF')
},
onLevelChanged: (level) => {
console.log('Brightness level changed to:', level)
setCurrentLevel(level)
},
onError: (error) => {
console.error('Torch error:', error.code, error.message)
},
})
const maxLevel = getMaxLevel() // null if brightness control not supported
return (
<View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
<Text style={{ fontSize: 18, marginBottom: 20, textAlign: 'center' }}>
Torch is {currentLevel !== null ? 'ON 🔦' : 'OFF'}
</Text>
<Button title="Turn On" onPress={on} />
<Button title="Turn Off" onPress={off} />
{maxLevel && maxLevel > 1 && (
<View style={{ marginTop: 20 }}>
<Text>Brightness Level: {currentLevel ?? 'N/A'}</Text>
<Slider
minimumValue={1}
maximumValue={maxLevel}
step={1}
value={currentLevel ?? 1}
onValueChange={(value) => setLevel(value)}
/>
</View>
)}
</View>
)
}
useTorch(options?)React hook for controlling the device flashlight with real-time state updates.
Parameters:
interface UseTorchOptions {
/**
* Called when the torch state changes (true = on, false = off)
*/
onStateChanged?: (isOn: boolean) => void
/**
* Called when the torch brightness level changes
* null when torch is off, number (1 to maxLevel) when on
*/
onLevelChanged?: (level: number | null) => void
/**
* Called when an error occurs (e.g., no flash available, access denied)
*/
onError?: (error: TorchError) => void
}
Returns:
{
on: () => Promise<void> // Turn the torch on
off: () => Promise<void> // Turn the torch off
toggle: () => Promise<void> // Toggle the torch on/off
setLevel: (level: number) => Promise<void> // Set brightness level (1 to maxLevel)
getMaxLevel: (dynamic?: boolean) => number | null // Get max brightness level (null if not supported)
// dynamic: iOS only - if true, returns current available level (may be lower under thermal stress)
// - if false/undefined, returns hardware maximum (10)
// Android - parameter is ignored, always returns hardware maximum
}
Example:
const { on, off, toggle, setLevel, getMaxLevel } = useTorch({
onStateChanged: (state) => {
console.log('Torch state changed to:', state)
},
onLevelChanged: (level) => {
console.log('Brightness level:', level)
},
onError: (error) => {
if (error.code === 'NoFlashAvailable') {
Alert.alert('Error', 'Your device does not have a flashlight')
}
},
})
// Simple toggle
await toggle()
// Or use on/off explicitly
await on()
await off()
// Check if brightness control is supported
const maxLevel = getMaxLevel()
if (maxLevel && maxLevel > 1) {
// Device supports brightness control
await setLevel(maxLevel / 2) // Set to 50% brightness
}
// iOS: Check current available level (may be lower under thermal stress)
const currentMaxLevel = getMaxLevel(true) // iOS only - returns current available level
const hardwareMaxLevel = getMaxLevel() // or getMaxLevel(false) - returns hardware max (10 on iOS)
The library provides specific error codes for different failure scenarios:
enum TorchExceptionType {
/**
* Camera service is not available (Android specific)
*/
CameraServiceUnavailable = 'CameraServiceUnavailable',
/**
* Android API level is too low
* - For basic torch: < Android 6.0 (API 23)
* - For brightness control: < Android 13 (API 33)
*/
ApiLevelTooLow = 'ApiLevelTooLow',
/**
* Device does not have a flash/torch
*/
NoFlashAvailable = 'NoFlashAvailable',
/**
* Device does not support brightness control
* (FLASH_INFO_STRENGTH_MAXIMUM_LEVEL <= 1)
*/
BrightnessControlNotSupported = 'BrightnessControlNotSupported',
/**
* Failed to access or control the torch
*/
AccessFailed = 'AccessFailed',
}
Error Object:
interface TorchError {
message: string // Human-readable error message
code: TorchExceptionType // Error type code
}
function TorchToggle() {
const [isOn, setIsOn] = useState(false)
const { toggle } = useTorch({
onStateChanged: setIsOn,
})
return (
<Button
title={isOn ? 'Turn Off Flashlight' : 'Turn On Flashlight'}
onPress={toggle}
/>
)
}
function TorchManualControl() {
const [isOn, setIsOn] = useState(false)
const { on, off } = useTorch({
onStateChanged: setIsOn,
})
return (
<View>
<Button title="Turn On" onPress={on} disabled={isOn} />
<Button title="Turn Off" onPress={off} disabled={!isOn} />
</View>
)
}
function TorchBrightnessControl() {
const [level, setLevel] = useState<number | null>(null)
const { setLevel: setTorchLevel, getMaxLevel } = useTorch({
onLevelChanged: setLevel,
onError: (error) => {
if (error.code === 'BrightnessControlNotSupported') {
Alert.alert(
'Not Supported',
'Your device does not support brightness control'
)
}
},
})
const maxLevel = getMaxLevel()
if (!maxLevel || maxLevel <= 1) {
return <Text>Brightness control not supported on this device</Text>
}
return (
<View>
<Text>
Current Level: {level ?? 'Off'} / {maxLevel}
</Text>
<Slider
minimumValue={1}
maximumValue={maxLevel}
step={1}
value={level ?? 1}
onValueChange={setTorchLevel}
/>
<Button title="Set to Max" onPress={() => setTorchLevel(maxLevel)} />
<Button title="Set to Min" onPress={() => setTorchLevel(1)} />
</View>
)
}
function TorchWithErrorHandling() {
const [isOn, setIsOn] = useState(false)
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const { on, off } = useTorch({
onStateChanged: setIsOn,
onError: (error) => {
switch (error.code) {
case 'NoFlashAvailable':
setErrorMessage('Your device does not have a flashlight')
break
case 'CameraServiceUnavailable':
setErrorMessage('Camera service is not available')
break
case 'BrightnessControlNotSupported':
setErrorMessage('Brightness control not supported on this device')
break
case 'AccessFailed':
setErrorMessage('Failed to access flashlight')
break
default:
setErrorMessage(error.message)
}
},
})
return (
<View>
<Button title="Toggle Torch" onPress={isOn ? off : on} />
{errorMessage && <Text style={{ color: 'red' }}>{errorMessage}</Text>}
</View>
)
}
function TorchWithTracking() {
const [isOn, setIsOn] = useState(false)
const [history, setHistory] = useState<string[]>([])
const { on, off } = useTorch({
onStateChanged: (state) => {
setIsOn(state)
const timestamp = new Date().toLocaleTimeString()
const entry = `${timestamp}: Torch ${state ? 'ON' : 'OFF'}`
setHistory((prev) => [...prev, entry])
},
onLevelChanged: (level) => {
if (level !== null) {
const timestamp = new Date().toLocaleTimeString()
const entry = `${timestamp}: Level set to ${level}`
setHistory((prev) => [...prev, entry])
}
},
})
return (
<View>
<Button title="Toggle" onPress={isOn ? off : on} />
<Text>Current State: {isOn ? 'ON' : 'OFF'}</Text>
<Text>History:</Text>
{history.map((entry, index) => (
<Text key={index}>{entry}</Text>
))}
</View>
)
}
function TorchWithTimer() {
const [isOn, setIsOn] = useState(false)
const { on, off } = useTorch({
onStateChanged: setIsOn,
})
const turnOnWithTimer = async (seconds: number) => {
await on()
setTimeout(() => {
off()
}, seconds * 1000)
}
return (
<View>
<Button
title="Turn on for 5 seconds"
onPress={() => turnOnWithTimer(5)}
/>
<Button title="Turn off now" onPress={off} disabled={!isOn} />
</View>
)
}
AVCaptureDevice API for torch controlmaxAvailableTorchLevel (may reduce brightness under thermal stress)CameraManager API (API 23+)setTorchMode() doesn't require CAMERA permission since API 23FLASH_INFO_STRENGTH_MAXIMUM_LEVELnull from getMaxLevel() if not supportedBrightnessControlNotSupported error when trying to set level on unsupported devicesTorchCallback provides real-time updates for state and brightness changesThis usually means the camera service is in use by another app or the system is under heavy load. Try:
For basic torch control:
For brightness control:
getMaxLevel() to check if brightness control is available before calling setLevel()Your device's camera flash unit does not support variable brightness levels. This happens when FLASH_INFO_STRENGTH_MAXIMUM_LEVEL <= 1.
Solution:
const maxLevel = getMaxLevel()
if (maxLevel && maxLevel > 1) {
// Brightness control is supported
await setLevel(level)
} else {
// Fall back to basic on/off
await on()
}
Your device doesn't have a flashlight/flash unit. This is common on:
The iOS Simulator does not have a flashlight. Test on a physical device.
Thanks to NitroModules, all operations bypass the traditional React Native bridge:
TorchCallback for system-level event monitoringThe brightness control API allows you to adjust the flashlight intensity on supported devices:
Check support: Call getMaxLevel() to get the maximum brightness level
null if not supported (Android < 13, or device limitation)10 on iOS (all devices with torch support)Set level: Call setLevel(level) with a value from 1 to maxLevel
maxLevel is the maximum brightnessMonitor changes: Use onLevelChanged callback to track brightness changes
null when torch is offmaxLevel) when torch is onOn iOS, the library uses:
AVCaptureDevice.setTorchModeOn(level:) which accepts values from 0.0 to 1.0AVCaptureDevice.maxAvailableTorchLevel to respect thermal limitations (may be < 1.0 under thermal duress)Dynamic Level Detection (iOS only):
getMaxLevel() or getMaxLevel(false) - returns hardware maximum (always 10)getMaxLevel(true) - returns current available level based on thermal state
maxAvailableTorchLevel >= 1.0)Float.greatestFiniteMagnitude when there are no thermal limitations, which is automatically clamped to 10Important behavior:
onLevelChanged receives the brightness level (1 to 10)onLevelChanged receives nullonStateChanged and onLevelChanged callbacks are fired on every state/level changeOn Android 13+, the library uses:
CameraCharacteristics.FLASH_INFO_STRENGTH_MAXIMUM_LEVEL to detect supportCameraManager.turnOnTorchWithStrengthLevel() to set brightnessCameraManager.TorchCallback.onTorchStrengthLevelChanged() for real-time updatesImportant behavior:
onLevelChanged receives the brightness level (1 to maxLevel)onTorchStrengthLevelChanged() is not triggered (even though the strength level internally resets to FLASH_INFO_STRENGTH_DEFAULT_LEVEL)null to onLevelChanged when onTorchModeChanged detects the torch is offnull indicating the torch is offfunction ProgressiveBrightness() {
const { setLevel, getMaxLevel } = useTorch()
const maxLevel = getMaxLevel()
const fadeIn = async () => {
if (!maxLevel || maxLevel <= 1) return
for (let level = 1; level <= maxLevel; level++) {
await setLevel(level)
await new Promise((resolve) => setTimeout(resolve, 200))
}
}
return <Button title="Fade In" onPress={fadeIn} />
}
function ThermalAwareTorch() {
const [thermalLevel, setThermalLevel] = useState<number | null>(null)
const { setLevel, getMaxLevel } = useTorch()
// Check current thermal state
const checkThermalState = () => {
const currentMax = getMaxLevel(true) // iOS: get current available level
const hardwareMax = getMaxLevel() // Hardware maximum (10)
setThermalLevel(currentMax)
if (currentMax && hardwareMax && currentMax < hardwareMax) {
Alert.alert(
'Thermal Limitation',
`Device is hot. Max brightness limited to ${currentMax}/${hardwareMax}`
)
}
}
const setMaxBrightness = async () => {
// Use dynamic level to respect thermal limitations
const safeMaxLevel = getMaxLevel(true) ?? getMaxLevel() ?? 1
await setLevel(safeMaxLevel)
}
return (
<View>
<Button title="Check Thermal State" onPress={checkThermalState} />
<Button title="Set Max (Safe)" onPress={setMaxBrightness} />
{thermalLevel && <Text>Current max level: {thermalLevel}</Text>}
</View>
)
}
| Feature | iOS | Android | Notes |
|---|---|---|---|
| Basic On/Off | ✅ | ✅ | Works on all supported versions |
| Toggle | ✅ | ✅ | Toggle between on/off states |
| State Callbacks | ✅ | ✅ | Real-time native callbacks |
| Brightness Control | ✅ | ✅ | iOS: 10 levels, Android 13+: device dependent |
| Level Callbacks | ✅ | ✅ | iOS: all versions, Android 13+ only |
| Auto Detection | ✅ | ✅ | Automatically finds camera with flash |
| Permissions Required | ❌ | ❌ | No permissions required on either platform |
Before using brightness control, check if it's supported:
const { getMaxLevel, setLevel, on } = useTorch()
const maxLevel = getMaxLevel()
// Safe approach
const setBrightness = async (level: number) => {
if (maxLevel && maxLevel > 1) {
await setLevel(level)
} else {
// Fall back to basic on/off
console.warn('Brightness control not supported')
await on()
}
}
Always provide fallbacks for error scenarios:
const { on, off } = useTorch({
onError: (error) => {
switch (error.code) {
case 'NoFlashAvailable':
// Show UI message that device has no flash
showMessage('Your device does not have a flashlight')
break
case 'BrightnessControlNotSupported':
// Fall back to basic on/off mode
setUseBrightnessControl(false)
break
case 'CameraServiceUnavailable':
// Retry or show message to close other camera apps
showMessage('Please close other camera apps and try again')
break
default:
showMessage(`Error: ${error.message}`)
}
},
})
The hook automatically cleans up callbacks, but ensure torch is turned off when appropriate:
useEffect(() => {
return () => {
// Turn off torch when component unmounts
off()
}
}, [off])
Prefer callbacks over polling for better performance:
// ✅ Good - uses native callbacks
const [isOn, setIsOn] = useState(false)
const { on, off } = useTorch({
onStateChanged: setIsOn,
})
// ❌ Bad - polling/checking manually is not possible and unnecessary
Always validate user input before setting brightness:
const handleBrightnessChange = async (value: number) => {
const maxLevel = getMaxLevel()
if (!maxLevel || maxLevel <= 1) {
console.warn('Brightness control not available')
return
}
// Clamp value to valid range
const validLevel = Math.max(1, Math.min(maxLevel, Math.round(value)))
await setLevel(validLevel)
}
A: Yes! Both platforms support full torch functionality including brightness control. iOS supports 10 discrete brightness levels on all devices with a torch. Android requires API 33+ (Android 13) and device support for brightness control.
A: Call getMaxLevel(). If it returns a number greater than 1, brightness control is supported. If it returns null or 1, only basic on/off is available.
const maxLevel = getMaxLevel()
const supportsBrightness = maxLevel !== null && maxLevel > 1
on(), toggle(), and setLevel()?A:
on() - Turns the torch on at default brightness (works on all devices)off() - Turns the torch offtoggle() - Toggles the torch between on and off statessetLevel(level) - Turns the torch on at a specific brightness level (Android 13+ only, device must support it)A: No! Neither iOS nor Android require any permissions for using the flashlight/torch:
CameraManager.setTorchMode() works without CAMERA permissiongetMaxLevel() returning null on my Android device?A: This can happen for several reasons:
FLASH_INFO_STRENGTH_MAXIMUM_LEVEL <= 1)getMaxLevel() and getMaxLevel(true) on iOS?A:
getMaxLevel() or getMaxLevel(false) - returns the hardware maximum (always 10 on iOS)getMaxLevel(true) - returns the current available level based on thermal state
On Android, the dynamic parameter is ignored and always returns the hardware maximum.
A: Yes, the torch will stay on even if your app goes to the background. However, it's recommended to turn it off when the app is backgrounded to save battery.
A: The library automatically turns off the torch when the module is disposed. However, you should also handle it in your component cleanup:
useEffect(() => {
return () => off()
}, [off])
A: Thanks to NitroModules, this library has:
A: Make sure you've installed both packages:
npm install react-native-torch-nitro react-native-nitro-modules
And run pod install on iOS:
cd ios && pod install
This repository includes a complete example app demonstrating all features of react-native-torch-nitro.
Location: The example app is located in the example/ directory within this repository.
# Clone the repository
git clone https://github.com/irekrog/react-native-torch-nitro.git
cd react-native-torch-nitro
# Install library dependencies
npm install
# Navigate to example app
cd example
npm install
# iOS
cd ios && pod install && cd ..
npm run ios
# Android
npm run android
The example app demonstrates:
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT
Made with NitroModules ⚡️
FAQs
react-native-torch-nitro
The npm package react-native-torch-nitro receives a total of 30 weekly downloads. As such, react-native-torch-nitro popularity was classified as not popular.
We found that react-native-torch-nitro demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.