EAS build crashes on TestFlight when Camera is opened.

eas-cli version
eas-cli/2.6.0 darwin-x64 node-v18.12.0

Hello everyone,

I am having problems with trying to release my application to the app store. After building using EAS build, when put onto TestFlight (iOS), the application will crash when a window with the camera is opened. It works fine with expo-cli build, though.

The component that opens the camera:

import React, { useState } from 'react';
import { Text, View, StyleSheet, Image, TouchableOpacity, Appearance, Alert, Platform } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useIsFocused } from '@react-navigation/core';
import { LinearGradient } from 'expo-linear-gradient';
import { Camera, CameraType } from 'expo-camera';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { Theme } from '../../models/Theme';
 

const DESIRED_RATIO = "16:9";

export default function MFPocketBarcodeScanner(props) {
 
    const [scanned, setScanned] = useState(false);
    const [camera, setCamera] = useState(null);
    const [ratio, setRatio] = useState(null);

    const [permission, requestPermission] = Camera.useCameraPermissions();

    let colorScheme =  Appearance.getColorScheme();
    const colors =  Theme.getColorPalette(colorScheme);
  
    let backgroundStyle = colors.background;
    let textStyle = colors.content;
    let scannerColor = colors.secondaryHighlight;

    // Barcode scanner shall only be rendered if screen is focused
    // Without detecting focus/blur, the barcode scanner will always be running at the background
    const isFocused = useIsFocused();

    const prepareRatio = async () => {
        if (Platform.OS === 'android' && camera) {
             const ratios = await camera.getSupportedRatiosAsync();
             // See if the current device has your desired ratio, otherwise get the maximum supported one
             // Usually the last element of "ratios" is the maximum supported ratio
             const finalRatio = ratios.find((ratio) => ratio === DESIRED_RATIO) || ratios[ratios.length - 1];
             
             setRatio(finalRatio);
        }
    }

    const handleBarCodeScanned = ({ type, data }) => {
        setScanned(true);

        if (type === BarCodeScanner.Constants.BarCodeType.qr) {
            try {
                if (data.includes("&info=")) {
                    props.navigation.navigate("Logon", { info: data.split("&info=")[1], type: "auth" });
                    setScanned(false);
                } else {
                    throw "error";
                }

            } catch (e) {
                // alert the data format is not correct
                Alert.alert(
                    'Incorrect data format detected.',
                    `You have scanned an QR code with incorrect data format. Please try again.`,
                    [
                        {
                            text: "OK", style: "destructive", onPress: () => {
                                setScanned(false);
                            }
                        },
                    ],
                    { cancelable: false }
                );
            }

        } else {
            Alert.alert(
                'Incorrect QR code type.',
                `You have scanned an incorrect QR code. Please try again.`,
                [
                    {
                        text: "OK", style: "destructive", onPress: () => {
                            setScanned(false);
                        }
                    },
                ],
                { cancelable: false }
            );
        }
    };


    if (permission != null && permission.status === "denied") {
        return <View
            style={{
                flex: 1,
                flexDirection: 'column',
                justifyContent: 'center',
                backgroundColor: `${backgroundStyle}`,
                position: 'relative',
            }}>

            <View style={{
                position: "absolute",
                width: '100%',
                height: '100%',
            }}>
                <LinearGradient
                    // Background Linear Gradient
 
                    colors={backgroundStyle}
                    start={[0, 0.5]}
                    end={[1, 0.5]}
                    style={{
                        width: '100%',
                        height: '100%',
                    }}
                />
            </View>

            <View style={{
                position: "absolute",
                width: '100%',
                height: '100%',
                zIndex: 1,
            }}>
                <Image
                    style={{
                        width: '100%',
                        height: '100%',
                    }}
                    source={require('../../assets/Grid.png')}
                    resizeMode="cover"
                />
            </View>

            <Text style={{ color: textStyle, textAlign: 'center' }}>No access to camera. </Text>
            <Text style={{ color: textStyle, textAlign: 'center'}}> Please manually modify the setting from your phone. </Text>
        </View>
    }

    return (
        <View
            style={{
                flex: 1,
                flexDirection: 'column',
                backgroundColor: `${backgroundStyle}`,
                position: 'relative',
            }}>

            <View style={{
                position: "absolute",
                width: '100%',
                height: '100%',
            }}>
                <LinearGradient
                    // Background Linear Gradient
                    colors={backgroundStyle}
                    start={[0, 0.5]}
                    end={[1, 0.5]}
                    style={{
                        width: '100%',
                        height: '100%',
                    }}
                />
            </View>

            <View style={{
                position: "absolute",
                width: '100%',
                height: '100%',
                zIndex: 1,
            }}>
                <Image
                    style={{
                        width: '100%',
                        height: '100%',
                    }}
                    source={require('../../assets/Grid.png')}
                    resizeMode="cover"
                />
            </View>

            <View style={{ flex: 1, justifyContent: "flex-start", alignItems: "center", marginTop: 50, zIndex: 2 }}>
                <Text style={{ color: `${textStyle}`, fontFamily: "Lato" }}>
                    Scan the QR code to get started.
                </Text>
            </View>

            {isFocused &&
                <Camera
                    onCameraReady={prepareRatio}
                    ratio={ratio}
                    type={CameraType.back}
                    ref={camera => setCamera(camera)}
                    onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
                    style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, margin: "auto" }}
                />
            }

            <View style={{ position: 'absolute', top: 0, left: 15, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center' }}>
                <Ionicons name="scan-outline" size={300} color={scannerColor} />
            </View>

            <View style={{ flex: 1, justifyContent: "flex-end", alignItems: "center", marginBottom: 50, zIndex: 2 }}>
                <TouchableOpacity
                    onPress={() => props.navigation.navigate("ManualRegistration")}
                >
                    <Text style={{ color: textStyle, fontSize: 16, fontFamily: "Roboto-Black", textDecorationLine: 'underline' }}>Can't scan the QR code?</Text>
                </TouchableOpacity>
            </View>
        </View>
    );




}

const styles = StyleSheet.create({
    scanner: {
        height: 500,
        width: 500
    },
    scanArea: {
        ...StyleSheet.absoluteFillObject,
        top: 50,
        left: 50,
        right: 50,
        bottom: 50,
    },
    text: {
        marginTop: 500,
    }
})

So when a user opens this component, the app would crash on TestFlight.

Any input appreciated :smiley:

Same problem happened to me when I upgrade from SKD 45 to 46.

Classic build works seamlessly on both TestFlight and Production, but EAS build doesn’t work on TestFlight when it tries to open Camera and a BarCodeScanner.

I reckon EAS is ignoring something as part of the building process. Try delete your .gitignore maybe.