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

expo-camera的recordAsync无返回结果,视频录制功能异常

Expo-Camera 视频录制无反应问题修复

我正在用expo-camera开发视频录制功能,界面包含CameraView视图和操作按钮,预期点击按钮启动录制,再次点击停止录制。权限已成功授予,但调用recordAsync后无任何反应,相关代码如下:

import { Divider, ThemedButton, ThemedText, ThemedView } from "@/components";
import ScreenNameWithBack from "@/components/atoms/ScreenNameWithBack";
import { Colors } from "@/constants/Colors";
import { CameraView, useCameraPermissions } from "expo-camera";
import { useRef, useState } from "react";
import { Button, StyleSheet, Text, View } from "react-native";

export default function VerificationStep() {
  const [isRecording, setIsRecording] = useState(false);
  const [permission, requestPermission] = useCameraPermissions();

  const [video, setVideo] = useState<any>();
  const cameraRef = useRef<any>(null);

  if (!permission) {
    // Camera permissions are still loading.
    return <View />;
  }

  if (!permission.granted) {
    // Camera permissions are not granted yet.
    return (
      <View style={styles.container}>
        <Text style={styles.message}>
          We need your permission to show the camera
        </Text>
        <Button onPress={requestPermission} title="grant permission" />
      </View>
    );
  }


  const recordVideo = async () => {
    console.log("mmmm");
    setIsRecording(true);
    let options = {
      quality: "480p",
      maxDuration: 120,
      mute: false,
    };
    console.log("nnn");
    try {
      cameraRef?.current?.recordAsync(options)?.then((ss: any) => {
        setVideo(ss);
      });
    } catch (error) {
      console.log({ error });
    }
  };

  const stopRecording = () => {
    console.log("---");
    setIsRecording(false);
    cameraRef.current.stopRecording();
    console.log("+++");
  };
  console.log({ video });
  return (
    <View style={styles.container}>
      <CameraView
        style={styles.camera}
        mode="video"
        ref={cameraRef}
        onCameraReady={() => console.log("ready")}
      />
      <ThemedButton
        title={isRecording ? "Stop Recording" : "Record Video"}
        onPress={isRecording ? stopRecording : recordVideo}
      />
    </View>
  );
}

问题分析

代码存在几个核心问题导致录制无响应:

  • recordAsync是异步Promise方法,当前用then链式调用但未正确等待结果,且外层try/catch无法捕获then中的错误
  • 启动/停止录制的逻辑拆分导致状态不同步,stopRecording调用后未关联recordAsync的结果捕获
  • 未处理录制过程中可能的异常状态重置

修复后的代码

import { Divider, ThemedButton, ThemedText, ThemedView } from "@/components";
import ScreenNameWithBack from "@/components/atoms/ScreenNameWithBack";
import { Colors } from "@/constants/Colors";
import { CameraView, useCameraPermissions } from "expo-camera";
import { useRef, useState } from "react";
import { Button, StyleSheet, Text, View } from "react-native";

export default function VerificationStep() {
  const [isRecording, setIsRecording] = useState(false);
  const [permission, requestPermission] = useCameraPermissions();
  const [video, setVideo] = useState(null);
  const cameraRef = useRef(null);

  if (!permission) {
    return <View />;
  }

  if (!permission.granted) {
    return (
      <View style={styles.container}>
        <Text style={styles.message}>
          需要获取相机权限才能使用
        </Text>
        <Button onPress={requestPermission} title="授予权限" />
      </View>
    );
  }

  const toggleRecording = async () => {
    if (isRecording) {
      cameraRef.current?.stopRecording();
      setIsRecording(false);
    } else {
      setIsRecording(true);
      const options = {
        quality: "480p",
        maxDuration: 120,
        mute: false,
      };
      try {
        // recordAsync会在停止录制时自动返回视频数据
        const videoData = await cameraRef.current?.recordAsync(options);
        setVideo(videoData);
        setIsRecording(false);
      } catch (error) {
        console.error("录制出错:", error);
        setIsRecording(false);
      }
    }
  };

  console.log({ video });
  return (
    <View style={styles.container}>
      <CameraView
        style={styles.camera}
        mode="video"
        ref={cameraRef}
        onCameraReady={() => console.log("相机已准备好")}
      />
      <ThemedButton
        title={isRecording ? "停止录制" : "开始录制"}
        onPress={toggleRecording}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
  camera: {
    flex: 1,
    width: "100%",
  },
  message: {
    fontSize: 16,
    marginBottom: 20,
  },
});

关键修复点

  • 将启动/停止录制合并为单个toggleRecording函数,避免状态不同步
  • 使用await正确处理recordAsync的Promise,确保捕获录制完成后的视频数据
  • 统一错误处理逻辑,录制失败时自动重置状态
  • 简化代码结构,移除不必要的可选链嵌套

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 10:43:14