Building a Production Audio Recorder with Expo and React Native

від

у

Створення продакшн-рекордера аудіо з Expo та React Native

Mobile audio recording is a core feature in many modern apps, powering everything from voice memos to podcast tools and user-generated content platforms. If you’re developing a mobile app with React Native, the Expo framework provides a robust set of APIs—especially the expo-av module—that simplifies cross-platform audio capture. But moving from a basic demo to a reliable, production-ready audio recorder means addressing a host of real-world challenges: managing permissions, supporting background recording, handling file storage, and reliably uploading recordings.

Let’s explore how to build a production-grade audio recorder using Expo and React Native, focusing on background recording, file management, and upload strategies. Along the way, you’ll find practical code examples and architectural tips for scalable, maintainable implementations.

Встановлення Expo AV для аудіозапису
Основа для будь-якого аудіоприложення на React Native — пакет expo-av. Ця бібліотека абстрагує платформенні деталі та надає уніфований API для відтворення та запису аудіо.

Спочатку переконайтесь, що у вас є потрібні залежності:
expo install expo-av

Вам також потрібно обробляти дозволи на доступ до мікрофона. Для iOS оновіть файл app.json відповідним описом використання:
“expo”: {
“ios”: {
“infoPlist”: {
“NSMicrophoneUsageDescription”: “We need access to your microphone to record audio.”
}
}
}

Для Android Expo автоматично управляє дозволами, але ви можете налаштувати повідомлення у AndroidManifest.xml, якщо викидаєте з проекту.

Запит дозволів
Перед початком запису завжди запитуйте дозвіл користувача:

import { Audio } from ‘expo-av’;

async function requestAudioPermission() {
const { status } = await Audio.requestPermissionsAsync();
if (status !== ‘granted’) {
throw new Error(‘Microphone permission not granted’);
}
}

Імплементування рекордера
API Audio.Recording — це ваша точка входу для захоплення аудіо. Ось базовий хуку для інкапсуляції логіки запису:

import { useRef, useState } from ‘react’;
import { Audio, AVPlaybackStatus } from ‘expo-av’;

export function useAudioRecorder() {
const [isRecording, setIsRecording] = useState(false);
const [recordingUri, setRecordingUri] = useState(null);
const recordingRef = useRef(null);

async function startRecording() {
await requestAudioPermission();

await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
playsInSilentModeIOS: true,
staysActiveInBackground: true, // критично для фонового запису
});

const recording = new Audio.Recording();
await recording.prepareToRecordAsync(
Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY
);
await recording.startAsync();
recordingRef.current = recording;
setIsRecording(true);
}

async function stopRecording() {
const recording = recordingRef.current;
if (!recording) return;

await recording.stopAndUnloadAsync();
const uri = recording.getURI();
setRecordingUri(uri);
setIsRecording(false);
recordingRef.current = null;
return uri;
}

return {
isRecording,
recordingUri,
startRecording,
stopRecording,
};
}

Інтеграція з UI
Проста UI-запис може виглядати так:

import React from ‘react’;
import { Button, View, Text } from ‘react-native’;
import { useAudioRecorder } from ‘./useAudioRecorder’;

export default function AudioRecorderScreen() {
const { isRecording, recordingUri, startRecording, stopRecording } = useAudioRecorder();

return (