You built a voice memo app with Rork, tapped the record button, and nothing happened. No error, no crash — just silence.
Microphone bugs are uniquely frustrating because they often fail silently. Unlike a network request that throws a 404 or a UI crash that prints a stack trace, a microphone that doesn't start gives you almost no feedback. If you're also dealing with camera or location permission issues, the Rork Permissions Troubleshooting Guide covers those patterns in detail. This guide breaks down the most common failure patterns in Rork-generated audio recording code, with practical fixes for each.
First Check: The Simulator Won't Record Audio
Before diving into code, it's worth ruling out the most common false alarm.
The iOS Simulator does not support the microphone. If you're testing recording functionality in Expo Go or the simulator, it will silently fail every time — regardless of how correct your code is.
// This might look like it's working, but on a simulator
// the permission status may stay 'undetermined' indefinitely
const { status } = await Audio.requestPermissionsAsync();
console.log('Permission status:', status);Always test microphone functionality on a real device using the Rork Companion app, a TestFlight build, or an EAS Development Build. If recording works on device but not simulator, your code is fine — you just need a real device for this feature.
Pattern 1: Recording Crashes Immediately or Produces No Audio
If the app crashes on record, or recording appears to start but captures nothing, the most likely cause is missing native permission declarations.
iOS — Info.plist Entry
Without NSMicrophoneUsageDescription in your app's Info.plist, iOS denies microphone access at the OS level. The app may crash without a clear error message.
// app.json (or app.config.js) — add this under expo.ios
{
"expo": {
"ios": {
"infoPlist": {
"NSMicrophoneUsageDescription": "Used to record voice memos within the app."
}
}
}
}Rork's AI often generates the recording component correctly but omits this app.json entry. After adding it, you'll need to create a new EAS Build — an OTA update (eas update) won't pick up native configuration changes.
Android — RECORD_AUDIO Permission
On Android, RECORD_AUDIO must be declared in AndroidManifest.xml. When using expo-audio, the Expo plugin usually handles this automatically, but it's worth verifying.
// app.json — android section
{
"expo": {
"android": {
"permissions": ["RECORD_AUDIO"]
}
}
}After changing this, rebuild with EAS. Runtime permission requests also need to be handled in code — the manifest entry alone isn't enough.
Pattern 2: Permission Dialog Appears, User Approves, Still No Recording
If the user grants microphone permission but recording still doesn't work, the issue is almost always missing Audio Mode configuration.
With expo-audio (the current recommended library as of Expo SDK 51+), you need to set the audio mode before starting a recording. Without this, iOS in particular will silently fail because the audio session isn't configured for recording.
import { useAudioRecorder, AudioModule, RecordingPresets } from 'expo-audio';
async function startRecording() {
// Request permission first
const { status } = await AudioModule.requestRecordingPermissionsAsync();
if (status !== 'granted') {
// Guide user to Settings — iOS won't show the dialog again after denial
Alert.alert(
'Microphone Permission Required',
'Please enable microphone access in Settings to use this feature.',
[{ text: 'Open Settings', onPress: () => Linking.openSettings() }]
);
return;
}
// ★ This step is frequently missing from Rork-generated code
await AudioModule.setAudioModeAsync({
allowsRecordingIOS: true, // Required for recording on iOS
playsInSilentModeIOS: true, // Record even when device is on silent
interruptionModeIOS: 'doNotMix', // Don't mix with other audio sessions
});
const recorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY);
await recorder.record();
}The key line is allowsRecordingIOS: true. Without it, iOS keeps the audio session in playback mode, and recording simply doesn't start — no error thrown, just no audio captured.
Pattern 3: Works in Expo Go, Fails in TestFlight Build
Expo Go ships with broad permissions pre-granted for development purposes. This means a feature that works in Expo Go may fail in a production build that doesn't have the correct app.json configuration.
Additionally, if Rork generated code using the older expo-av recording API, you may be hitting deprecation-related instability. As of Expo SDK 51, expo-av's audio recording functionality is deprecated in favor of expo-audio.
# Install the current recommended audio package
npx expo install expo-audio
# If you're migrating from expo-av, check for this import
# OLD: import { Audio } from 'expo-av';
# NEW: import { useAudioRecorder, AudioModule } from 'expo-audio';After switching packages, you need a fresh EAS Build — not just an OTA update.
Pattern 4: Recording Starts but File Is Corrupted or Empty
If recording starts but the saved file won't play back (or is 0 bytes), the issue is almost certainly async handling. Rork's AI sometimes generates recording stop logic without properly awaiting the async operations.
// ❌ Common pattern in Rork-generated code — doesn't await stop()
const handleStop = () => {
recorder.stop(); // Returns a Promise, but we're not awaiting it
const uri = recorder.getUri(); // Called before recording has actually stopped
saveFile(uri); // May save an incomplete or empty file
};
// ✅ Correct async pattern
const handleStop = async () => {
await recorder.stop(); // Wait for recording to fully complete
const uri = recorder.getUri(); // URI is now valid
if (uri) {
await saveToStorage(uri); // File is complete, safe to save
}
};The stop() method is asynchronous — the audio file isn't fully written until the Promise resolves. Accessing the URI before that point often results in an empty or corrupted file.
iOS vs Android Behavioral Differences
Microphone behavior has meaningful differences between platforms that are useful to know when debugging.
iOS:
- Silent mode blocks recording unless
playsInSilentModeIOS: trueis set - After a user taps "Don't Allow," iOS won't show the permission dialog again — you must redirect to Settings
- Background recording requires Background Modes capability (
audiomode inapp.json)
Android:
- Runtime permission request is required even if declared in the manifest
- Background recording needs a Foreground Service
- Some manufacturers (particularly Huawei and Xiaomi) have custom battery optimization that can interrupt background recording
If something works on iOS but not Android, start by verifying that the runtime RECORD_AUDIO permission request is actually being triggered in code (not just declared in the manifest).
Getting Rork AI to Generate Better Recording Code
Vague prompts often produce incomplete recording implementations. Being specific about what you need gets significantly better results.
# Effective prompt for recording functionality
"Create a voice recording component using expo-audio that works on both
iOS and Android. Include AudioModule.setAudioModeAsync with
allowsRecordingIOS: true before recording starts. Handle the case where
the user denies permission with an alert that links to Settings. Use
proper async/await throughout the start and stop recording flow."
A prompt like "add a record button" tends to produce code missing the Audio Mode setup and permission denial handling. The more you specify what you know is needed, the more complete the output.
If you already have generated code that's not working, pasting the actual error output (or noting "recording starts but the file is empty") alongside the code gives Rork's AI the context it needs to produce a targeted fix.
Testing on a Real Device Without a Full EAS Build
If you want to verify microphone behavior without going through a full EAS Build cycle, Rork's Development Build workflow (via expo-dev-client) is the fastest option. It behaves like a real native build while allowing you to update JavaScript code on the fly.
# Create a development build once
eas build --profile development --platform ios
# After installation, use expo start to push JS changes instantly
npx expo start --dev-clientThis approach means you only need to rebuild when native configuration changes (like adding NSMicrophoneUsageDescription). For the async and audio mode fixes described above, you can test changes immediately without waiting for a full build.
The Rork Companion app also supports testing many native features, including microphone access — which makes it useful for quick iteration before committing to a formal build.
Where to Start
If recording isn't working and you're not sure why, work through this checklist in order:
- Are you testing on a real device? (The simulator won't work)
- Is
NSMicrophoneUsageDescriptionin yourapp.json? - Is
AudioModule.setAudioModeAsync({ allowsRecordingIOS: true })called beforerecord()? - Is
stop()properly awaited before accessing the file URI?
These four checks resolve the majority of Rork recording issues. Audio apps — voice diaries, transcription tools, AI voice assistants — are well within Rork's capabilities once the native wiring is in place. For a complete implementation example, the AI Voice Diary App Guide shows how these pieces fit together in a production app.