Expo Camera takePictureAsync() аварийно завершает работу в сборке выпуска с ошибкой «Невозможно привести к PictureOptionJavascript

Форум по Javascript
Ответить
Anonymous
 Expo Camera takePictureAsync() аварийно завершает работу в сборке выпуска с ошибкой «Невозможно привести к PictureOption

Сообщение Anonymous »

Я разрабатываю приложение React Native/Expo (Expo SDK 52.0.38), в котором пользователи фотографируют свою одежду. Я боролся с периодическим сбоем в релизном APK, и мне нужна помощь, чтобы понять, почему это происходит и как это исправить.

У меня не очень большой опыт разработки — я скорее «вайбер-программист» — и это обязательный проект, который мне нужно выполнить. Возможно, мне не хватает чего-то простого. Я попробовал несколько подходов и даже обратился к нескольким LLM (GPT, Sonnet и т. д.), но ни один из них не смог решить эту проблему.


Среда
  • React Native: 0.72.x
  • Expo SDK: 52.0.38
  • Рабочий процесс: Перенесено с Expo Managed Workflow → Bare Workflow
  • Пакеты:

    expo-camera (CameraView + useCameraPermissions)
  • expo-router
[*]Протестированные платформы: Android (выпуск APK)

[*]Цель: пользователи делают снимки → подтверждают/переснимают → передают URI изображения в глобальное состояние.



Что Я хочу сделать
  • Запросить разрешение камеры, если оно не предоставлено.
  • Показать камеру с помощью CameraView.
  • Разрешить пользователям:
    • Переключаться между передней и задней камерой.
    • Сделать снимок (takePictureAsync).
    • Подтвердите или сделайте снимок повторно.
  • Передайте URI захваченной фотографии в глобальное состояние и перейдите к следующему экрану.
Текущее поведение
  • В разработке сборка: ✅ Работает нормально — камера показывает, изображение снято, URI возвращен.
  • Выпустить APK: ❌ Не работает при съемке изображения.

    Запрос разрешения работает нормально.
  • Камера открывается.
  • При съемке изображения просто не работает работаю.

TypeError: Cannot read property 'Type' of undefined
in TakePicture

Еще один вариант со старыми опциями:
The 2nd argument cannot be cast to type expo.modules.camera.PictureOptions
(received class com.facebook.react.bridge.ReadableNativeMap)


Что я пробовал
  • Проверено разрешение камеры → работает нормально.
  • Проверено cameraRef.current и cameraReady → верно при съемке.
  • Проверил разные параметры takePictureAsync:
    • { quality: 1, skipProcessing: true }
    • { quality: 1, skipProcessing: true, base64: false }
    • { quality: 1, skipProcessing: true, exif: false }
      ❌ Та же ошибка.
  • Проверено использование CameraType и Camera.Type → обновлен импорт.
  • Добавлены журналы консоли → разрешение предоставлено, камера готова, ссылка существует.
  • Работает в разработке, сбой только в выпуске APK.
  • Пересобран APK, очищены кеши → все равно вылетает.
  • Проверил документы Expo + проблемы с GitHub → некоторые упоминают минификацию / Hermes, вызывающие проблемы с ReadableNativeMap.
  • Попробовал подходы CameraView и Camera → проблема сохраняется.
Вопросы
  • Почему takePictureAsync() работает в разработке, но происходит сбой в APK-версии релиза после перехода на пустой рабочий процесс?
  • Известна ли проблема с CameraView / takePictureAsync в Expo SDK 52 Android?
  • Нужно ли передавать разные параметры для выпускных сборок?
  • Есть ли какие-либо обходные пути, чтобы сделать снимок без сбоев в выпуске?
  • Следует ли мне полностью переключиться обратно на «Камеру» вместо «CameraView»?
Чего я ожидаю
  • Камера открывается → пользователь может сделать снимок → получить URI фотографии → продолжить без сбоев.
Дополнительные примечания
  • Я «вибрационный программист» — возможно, мне не хватает чего-то простого.
  • LLM, такие как GPT и Sonnet, не могут помогите.
  • Разработка сборки работает нормально — только выпуск APK дает сбой.
  • Переход от Expo Managed → Bare workflow может быть уместен.
Полный компонент TakePicture (со стилями)
import { View, Text, TouchableOpacity, Image, StyleSheet, Alert } from "react-native";
import { useRouter } from "expo-router";
import { CameraView, useCameraPermissions } from "expo-camera";
import { useState, useRef, useEffect } from "react";
import { useGlobalState } from "../../context/GlobalState";
import { useTheme } from "../../context/ThemeContext";
import Svg, { Path, G, ClipPath, Defs, Rect } from "react-native-svg";

const TakePicture = () => {
const router = useRouter();
const { setSelectedImage } = useGlobalState();
const { theme } = useTheme();
const styles = themedStyles(theme);

const [permission, requestPermission] = useCameraPermissions();
const [cameraReady, setCameraReady] = useState(false);
const [facing, setFacing] = useState("back");
const [capturedPhoto, setCapturedPhoto] = useState(null);
const [showCamera, setShowCamera] = useState(false);
const cameraRef = useRef(null);

useEffect(() => {
return () => {
// Cleanup if needed
cameraRef.current = null;
};
}, []);

// Ask permission & show camera
const handleTakePicture = async () => {
try {
if (!permission?.granted) {
const result = await requestPermission();
if (!result.granted) {
Alert.alert("Permission Required", "Camera access is needed to take photos.");
return;
}
}
setShowCamera(true);
} catch (error) {
Alert.alert("Error", "Failed to access camera. Please try again.");
}
};

// Capture photo
const takePicture = async () => {
if (!cameraReady || !cameraRef.current) return;
try {
const options = { quality: 1, skipProcessing: true, base64: false, exif: false };
const photo = await cameraRef.current.takePictureAsync(options);
if (photo?.uri) setCapturedPhoto(photo.uri);
} catch (error) {
Alert.alert("Error", "Unable to take picture.");
}
};

const confirmPicture = () => {
if (capturedPhoto) {
setSelectedImage(capturedPhoto);
router.push("../uploadItems/uploadLoading");
}
};

const retakePicture = () => setCapturedPhoto(null);

const goBack = () => {
if (showCamera && !capturedPhoto) setShowCamera(false);
else router.replace("../uploadItems/uploadAnItem");
};

// Camera screen
if (showCamera && permission?.granted) {
return (

{capturedPhoto ? (




❌


✅



) : (




setCameraReady(true)}
>


📸

setFacing(facing === "back" ? "front" : "back")}
>
🔄




)}

);
}

// Main screen
return (


router.replace("../uploadItems/uploadAnItem")}>











Camera



Take a Picture
You can take outfit photos using your camera




Take Picture




);
};

// Styles
const themedStyles = (theme) =>
StyleSheet.create({
container: { flex: 1, backgroundColor: theme.background },
header: { flexDirection: "row", alignItems: "center", gap: 90, marginTop: 52, marginBottom: 55, paddingHorizontal: 23 },
headerText: { fontSize: 23, fontWeight: "bold", color: theme.primary },
headingContainer: { marginBottom: 20, paddingHorizontal: 23, gap: 4 },
heading: { fontSize: 33, fontWeight: "bold", color: theme.primary },
subheading: { fontSize: 15, fontWeight: "500", color: theme.subTextGrey },
buttons: { flex: 1, flexDirection: "column", gap: 15, marginHorizontal: 23, marginTop: 12 },
takePictureButton: { width: 328, height: 64, borderRadius: 5, alignItems: "center", justifyContent: "center", backgroundColor: theme.orangish, flexDirection: "row", gap: 10 },
takePictureButtonText: { fontSize: 19, fontWeight: "700", color: "white" },
fullScreen: { flex: 1, width: "100%", height: "100%" },
overlay: { position: "absolute", bottom: 40, width: "100%", flexDirection: "row", justifyContent: "center", alignItems: "center" },
captureBtn: { width: 80, height: 80, borderRadius: 40, backgroundColor: theme.orangish, justifyContent: "center", alignItems: "center" },
capture


Подробнее здесь: https://stackoverflow.com/questions/798 ... ast-to-pic
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»