Expo 相机与媒体库实战:扫码、拍照与本地保存

Created on

前言

相机和相册是最常见的原生能力之一,从扫码登录到拍照上传几乎每个 App 都会用到。Expo 提供了 expo-cameraexpo-media-library,可以在不写原生代码的情况下完成大部分需求。

本文以“扫码 + 拍照 + 保存到相册”为例,演示完整接入流程。

安装依赖

expo install expo-camera expo-media-library

权限申请

相机和媒体库都需要权限,建议在页面初始化时统一处理:

import { useEffect, useState } from "react";
import { Camera } from "expo-camera";
import * as MediaLibrary from "expo-media-library";

export function useCameraPermissions() {
  const [cameraGranted, setCameraGranted] = useState(false);
  const [mediaGranted, setMediaGranted] = useState(false);

  useEffect(() => {
    (async () => {
      const camera = await Camera.requestCameraPermissionsAsync();
      const media = await MediaLibrary.requestPermissionsAsync();
      setCameraGranted(camera.status === "granted");
      setMediaGranted(media.status === "granted");
    })();
  }, []);

  return { cameraGranted, mediaGranted };
}

扫码功能(BARCODE)

Expo Camera 内置条码扫描能力,常用场景是二维码登录或支付确认:

import { useRef, useState } from "react";
import { CameraView } from "expo-camera";

export function QrScanner() {
  const [scanned, setScanned] = useState(false);
  const onBarcodeScanned = ({ data }: { data: string }) => {
    if (scanned) return;
    setScanned(true);
    console.log("扫码结果:", data);
  };

  return (
    <CameraView
      style={{ flex: 1 }}
      barcodeScannerSettings={{ barcodeTypes: ["qr"] }}
      onBarcodeScanned={onBarcodeScanned}
    />
  );
}

建议加入“重新扫描”的交互按钮,避免连续触发。

拍照与保存到相册

import { useRef } from "react";
import { CameraView } from "expo-camera";
import * as MediaLibrary from "expo-media-library";

export function CameraCapture() {
  const cameraRef = useRef<CameraView | null>(null);

  const takePhoto = async () => {
    const photo = await cameraRef.current?.takePictureAsync({
      quality: 0.8,
      skipProcessing: true,
    });

    if (!photo?.uri) return;
    const asset = await MediaLibrary.createAssetAsync(photo.uri);
    await MediaLibrary.createAlbumAsync("MyApp", asset, false);
  };

  return <CameraView ref={cameraRef} style={{ flex: 1 }} />;
}

这里用 createAlbumAsync 统一管理相册,也可以只保存到系统默认相册。

常见问题与建议

小结

Expo 已经覆盖了绝大多数相机与媒体库需求。对于常见扫码、拍照、保存的场景,无需写原生代码就能落地。若后续需要更深度的相机控制(如 RAW 或专业级参数),再考虑引入自定义 native module。