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

React Native(Expo)移动端应用如何显示音频波形?

React Native 音频波形可视化播放器实现方案

可用第三方库适配方案

  • react-native-audio-waveform:若原库因版本兼容问题无法运行,可尝试社区维护的fork版本,不少分支已适配React Native 0.70+,修复了原生模块编译错误。
  • react-native-wave-visual:原库失效时,可手动修改其原生代码:Android端更新JNI调用逻辑与ReactPackage实现,iOS端替换废弃的AudioToolkit API,适配当前RN版本的桥接规范。
  • Expo生态组合方案:用expo-av处理音频播放,通过其API获取音频PCM数据,再结合react-native-canvas或动态生成的View组件绘制波形。这种方式灵活性强,适配性优于老旧第三方库。

原生实现方案(自定义桥接)

Android端

  1. 用ExoPlayer或MediaPlayer处理音频播放,通过AudioRecord采集实时PCM数据;
  2. 将PCM数据转换为振幅值,通过React Native桥接将数据传递至JS层;
  3. JS层根据振幅数据,用FlatList或动态View组件绘制波形条。

简化的Android原生代码片段:

// PCM数据采集与振幅计算
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, 
    AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);
short[] buffer = new short[bufferSize];
audioRecord.startRecording();
while (isPlaying) {
    int readCount = audioRecord.read(buffer, 0, bufferSize);
    int amplitude = calculateAverageAmplitude(buffer, readCount);
    // 向JS发送波形数据
    sendEvent(getReactApplicationContext(), "audioWaveData", amplitude);
}

iOS端

  1. 用AVAudioPlayer播放音频,通过AVAudioEngine的inputNode获取PCM数据;
  2. 从AVAudioPCMBuffer中提取振幅信息,通过桥接传递至JS层;
  3. JS层动态渲染波形组件。

简化的iOS原生代码片段:

// 音频数据监听与振幅提取
let audioEngine = AVAudioEngine()
let inputNode = audioEngine.inputNode
let format = inputNode.inputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: format) { buffer, _ in
    let channelData = buffer.floatChannelData![0]
    let amplitude = self.calculateAmplitude(from: channelData, length: Int(buffer.frameLength))
    // 向JS发送波形数据
    self.sendEvent(withName: "audioWaveData", body: amplitude)
}
try? audioEngine.start()

JS层波形绘制示例

import React, { useState, useEffect } from 'react';
import { View, StyleSheet, NativeEventEmitter, NativeModules } from 'react-native';

const AudioWaveform = () => {
  const [amplitudes, setAmplitudes] = useState([]);
  const { AudioWaveModule } = NativeModules;
  const eventEmitter = new NativeEventEmitter(AudioWaveModule);

  useEffect(() => {
    const subscription = eventEmitter.addListener('audioWaveData', (amplitude) => {
      // 保留最近20个振幅值,避免组件过多
      setAmplitudes(prev => [...prev.slice(-20), amplitude]);
    });
    return () => subscription.remove();
  }, []);

  return (
    <View style={styles.waveContainer}>
      {amplitudes.map((amp, idx) => (
        <View
          key={idx}
          style={[
            styles.waveBar,
            { height: Math.max(8, amp * 1.5), backgroundColor: '#2563eb' }
          ]}
        />
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  waveContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    height: 120,
    gap: 3,
    paddingHorizontal: 10,
  },
  waveBar: {
    width: 5,
    borderRadius: 3,
  },
});

export default AudioWaveform;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:05:07