You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native录音功能实现及音频上传服务器需求咨询

React Native 录音功能实现方案

1. 安装依赖

使用react-native-audio-recorder-player处理录音逻辑,react-native-permissions处理权限申请,执行以下命令:

npm install react-native-audio-recorder-player react-native-permissions react-native-fs
# 或用 yarn
yarn add react-native-audio-recorder-player react-native-permissions react-native-fs

2. 配置权限

iOS

在Info.plist中添加麦克风权限申请描述:

<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风进行录音</string>

Android

在AndroidManifest.xml中添加录音和存储权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

3. 完整Train组件代码

替换原有代码,实现点击录音、自动静音停止、手动停止及文件上传功能:

import { StyleSheet, Text, View, Image, Pressable, Alert } from 'react-native'
import React, { useState, useRef } from 'react'
import { useAuth } from '../AuthContext'
import { COLORS } from '../assets/colors/colors';
import Train_word from '../assets/images/Train_word.svg'
import Train_word_2 from '../assets/images/Train_word_2.svg'
import AudioRecorderPlayer from 'react-native-audio-recorder-player';
import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions';
import RNFS from 'react-native-fs';

const audioRecorderPlayer = new AudioRecorderPlayer();

const Train = () => {
  const [user] = useAuth()
  const [isRecording, setIsRecording] = useState(false)
  const [audioPath, setAudioPath] = useState('')
  const silenceTimerRef = useRef(null)

  // 检查并申请麦克风权限
  const checkMicrophonePermission = async () => {
    const permission = Platform.OS === 'ios' ? PERMISSIONS.IOS.MICROPHONE : PERMISSIONS.ANDROID.RECORD_AUDIO;
    const result = await check(permission);
    if (result === RESULTS.DENIED) {
      const requestResult = await request(permission);
      return requestResult === RESULTS.GRANTED;
    }
    return result === RESULTS.GRANTED;
  }

  // 启动静音检测:5秒内音量低于阈值则自动停止录音
  const startSilenceDetection = () => {
    silenceTimerRef.current = setInterval(async () => {
      const volume = await audioRecorderPlayer.getVolume();
      // 音量阈值可按需调整,当前设为0.01
      if (parseFloat(volume) < 0.01) {
        stopRecording();
        Alert.alert('提示', '未检测到声音,已自动停止录音');
      }
    }, 5000);
  }

  // 开始录音
  const startRecording = async () => {
    const hasPermission = await checkMicrophonePermission();
    if (!hasPermission) {
      Alert.alert('权限不足', '请允许访问麦克风');
      return;
    }

    const path = `${RNFS.DocumentDirectoryPath}/recording_${Date.now()}.mp4`;
    const audioSet = {
      AudioEncoderAndroid: 'aac',
      AudioSourceAndroid: 'mic',
      OutputFormatAndroid: 'mpeg_4',
      AudioQualityIOS: 'low',
      AudioEncodingBitRateIOS: 32000,
      NumberOfChannelsIOS: 1,
    };

    await audioRecorderPlayer.startRecorder(path, audioSet);
    setIsRecording(true);
    setAudioPath(path);
    startSilenceDetection();

    audioRecorderPlayer.addRecordBackListener((e) => {
      console.log('录音进度:', e.current_position, '/', e.duration);
    });
  }

  // 停止录音
  const stopRecording = async () => {
    if (silenceTimerRef.current) {
      clearInterval(silenceTimerRef.current);
      silenceTimerRef.current = null;
    }
    await audioRecorderPlayer.stopRecorder();
    setIsRecording(false);
    audioRecorderPlayer.removeRecordBackListener();
    console.log('录音文件路径:', audioPath);
  }

  // 上传录音文件到服务器
  const uploadAudio = async () => {
    if (!audioPath) {
      Alert.alert('提示', '暂无录音文件可上传');
      return;
    }

    const formData = new FormData();
    formData.append('audio', {
      uri: Platform.OS === 'ios' ? audioPath.replace('file://', '') : audioPath,
      name: `recording_${Date.now()}.mp4`,
      type: 'audio/mp4',
    });

    try {
      const response = await fetch('你的服务器上传接口地址', {
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data',
          // 若需身份验证,添加token
          // 'Authorization': `Bearer ${user.token}`
        },
        body: formData,
      });

      const result = await response.json();
      response.ok ? Alert.alert('成功', '录音文件上传完成') : Alert.alert('失败', `上传错误:${result.message}`);
    } catch (error) {
      Alert.alert('错误', `上传失败:${error.message}`);
    }
  }

  return (
    <View style={styles.container}>
        <View style={styles.header}>
            <Image
                source={require('../assets/images/Logo_small.png')}
                style={styles.logo_s}
                resizeMode='contain'/>
        </View>
        <View style={styles.main_cont}>
            <Train_word marginBottom={34}/>
            <Train_word_2 marginBottom={55}/>
            <Pressable 
              marginBottom={180}
              onPress={() => isRecording ? stopRecording() : startRecording()}
            >
                <Image
                    source={isRecording ? require('../assets/images/Stop_img.png') : require('../assets/images/Start_img.png')}
                    style={styles.start_img}>
                </Image>
            </Pressable>
            <Pressable style={styles.result} onPress={uploadAudio}>
                <Text style={styles.text_result}>Получить результат</Text>
            </Pressable>
        </View>
        <Image
        source={require('../assets/images/bottom_menu.png')}
        style={styles.img_bg}/>
    </View>
  )
}

export default Train

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: "rgba(243, 239, 239, 1)",
        alignItems: 'center'
    },

    img_bg: {
        width: 412,
        height: 80,
    },
    
    logo_s: {
        width: 100,
        height: 100,
        left: 150,
        top: -130,
    },

    header: {
        backgroundColor: 'transparent',
        flexDirection: 'row',
        alignItems:'center',
        height: 100,
        paddingTop: 180,
        paddingRight: 35
    },

    main_cont: {
        alignItems: 'center',
        top: -90,
        flex: 1,
    },

    start_img: {
        width: 286,
        height: 286,
    },

    result: {
        backgroundColor: 'transparent',
        width: 178,
        height: 25,
        alignItems: "center",
        left: -63,
        
    },
  
    text_result: {
        fontFamily: 'OpenSans-Italic',
        color: COLORS.text,
        fontSize: 16,
        textDecorationLine: 'underline'
    }
})

功能说明

  • 录音切换:点击按钮切换状态,未录音时启动录音,录音中则手动停止。
  • 自动静音停止:录音启动后每5秒检测音量,低于阈值时自动停止并提示用户。
  • 文件上传:点击"Получить результат"按钮将录音文件以FormData格式上传到服务器,需替换为实际接口地址。
  • 权限处理:启动录音前自动检查并申请麦克风权限,避免无权限导致功能异常。

内容的提问来源于stack exchange,提问作者Proger228

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 20:55:10