Project works locally, builds fine, but crashes in TestFlight

Description of the project:

This project uses firebase for the the auth, services, and data storage. The first page after the splash is a simple login. This project also uses Redux and Redux thunk to manage a global state. The main view after the login screen is a react-native MapView, and I’m providing an iOS googleMapsApiKey to the iOS config so it uses google maps instead. This project prompts for location permission when the component with the MapView is rendered, and asks for Notification permission in the Register component.

Description of the problem:

  • The app works completely fine when using expo start and running the app via LAN or tunnel, on either a simulated iPhone or an actual iPhone.
  • The project also builds fine and I’m able to retrieve an .ipa file from Expo. I used Transporter to upload the build to the appstoreconnect. When the project is actually downloaded on a device it crashes immediately upon clicking the icon.
  • Used expo build:ios -t simulator to get the tar.gz and ran on an emulator, still crashes instantly
  • The call to add logs to firebase in app.js in the handleLoadingError() and handleFinishLoading() functions are never called

Expo diagnostics:

Expo CLI 3.11.7 environment info:
    System:
      OS: macOS 10.15.2
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 10.16.3 - /usr/local/bin/node
      npm: 6.13.4 - /usr/local/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild
    npmPackages:
      expo: ^35.0.0 => 35.0.1 
      react: 16.8.3 => 16.8.3 
      react-native: https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz => 0.59.8 
      react-navigation: ^3.12.0 => 3.13.0 
    npmGlobalPackages:
      expo-cli: 3.11.7

package.json:

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "test": "jest --watchAll"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/samples": "~3.0.3",
    "@expo/vector-icons": "^10.0.3",
    "@react-native-community/datetimepicker": "^2.1.0",
    "@react-navigation/web": "^1.0.0-alpha.9",
    "expo": "^35.0.0",
    "expo-asset": "^7.0.0",
    "expo-constants": "^7.0.0",
    "expo-font": "^7.0.0",
    "expo-web-browser": "^7.0.0",
    "firebase": "^7.3.0",
    "react": "16.8.3",
    "react-dom": "16.8.3",
    "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
    "react-native-appearance": "~0.1.0",
    "react-native-gesture-handler": "~1.3.0",
    "react-native-maps": "~0.25.0",
    "react-native-modal-datetime-picker": "^7.6.1",
    "react-native-web": "^0.11.7",
    "react-navigation": "^3.12.0",
    "react-redux": "^7.1.3",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0"
  },
  "devDependencies": {
    "babel-preset-expo": "^7.0.0",
    "jest-expo": "^35.0.0"
  },
  "private": true
}

app.json:

{
  "expo": {
    "name": "Swoop Me",
    "slug": "swoopme-native",
    "privacy": "unlisted",
    "sdkVersion": "35.0.0",
    "platforms": [
      "ios",
      "android"
    ],
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/images/swoopicon.png",
    "splash": {
      "image": "./assets/images/swoopsplash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "updates": {
      "fallbackToCacheTimeout": 0
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.swoopme.swoop",
      "config": {
        "googleMapsApiKey": "aaaaaaazzzzzzzyyyyyyyxxxxx"
      }
    },
    "description": "",
    "notification": {
      "icon": "./assets/images/swoopicon.png"
    }
  }
}

app.js:

import { AppLoading } from 'expo';
import * as Font from 'expo-font';
import React, { useState } from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { AppearanceProvider } from 'react-native-appearance';
import { Provider } from 'react-redux'

import configureStore from './redux/store'
import AppNavigator from './navigation/AppNavigator';
import NavigationService from './navigation/NavigationService'

import * as firebase from 'firebase'

let firebaseConfig = {
  apiKey: "~~~~~~~~~~~",
  authDomain: "~~~~~~~~~~~",
  databaseURL: "~~~~~~~~~~~",
  projectId: "~~~~~~~~~~~",
  storageBucket: "~~~~~~~~~~~",
  messagingSenderId: "~~~~~~~~~~~",
  appId: "~~~~~~~~~~~",
  measurementId: "~~~~~~~~~~~"
}

firebase.initializeApp(firebaseConfig)
// app.functions().useFunctionsEmulator('http://localhost:5000');


export default function App(props) {
  const [isLoadingComplete, setLoadingComplete] = useState(false);

  if (!isLoadingComplete && !props.skipLoadingScreen) {
    return (
      <AppLoading
        startAsync={loadResourcesAsync}
        onError={handleLoadingError}
        onFinish={() => handleFinishLoading(setLoadingComplete)}
      />
    );
  } else {
    return (
      <Provider store={configureStore()}>
        <AppearanceProvider>
          <View style={styles.container}>
            {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
            <AppNavigator ref={navigatorRef => {NavigationService.setTopLevelNavigator(navigatorRef)}}/>
          </View>
        </AppearanceProvider>
      </Provider>
    );
  }
}

async function loadResourcesAsync() {
  await Promise.all([
    Font.loadAsync({
      // This is the font that we are using for our tab bar
      ...Ionicons.font,
      // We include SpaceMono because we use it in HomeScreen.js. Feel free to
      // remove this if you are not using it in your app
      'space-mono': require('./assets/fonts/SpaceMono-Regular.ttf'),
    }),
  ]);
}

function handleLoadingError(error) {
  // In this case, you might want to report the error to your error reporting
  // service, for example Sentry
  firebase.firestore().collection('errorLog').add(JSON.stringify(error))
}

function handleFinishLoading(setLoadingComplete) {
  console.log("loading complete...")
  firebase.firestore().collection('logs').add({ status: "finished"})
  setLoadingComplete(true);
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
});

iOS Crash Report Data:

feedback.json:

{
  "id" : "~~~~~~~~~~~",
  "timestamp" : "2020-01-17T14:28:08.883Z[UTC]",
  "appAdamId" : 1495252462,
  "cfBundleShortVersion" : "1.0.1",
  "cfBundleVersion" : "1",
  "deviceModel" : "iPhone9,2",
  "osVersion" : "13.3",
  "locale" : "en-US",
  "carrier" : "T-Mobile",
  "timezone" : "America/New_York",
  "architecture" : "arm64",
  "connectionStatus" : "MOBILE_DATA",
  "pairedAppleWatch" : "",
  "appUptimeMillis" : null,
  "availableDiskBytes" : 67002064896,
  "totalDiskBytes" : 127989469184,
  "networkType" : "LTE",
  "batteryPercentage" : 99,
  "screenWidth" : 414,
  "screenHeight" : 736,
  "emailAddress" : "~~~~~~~~",
  "comment" : null
}

I figured out my issue, it was due to botched environment variable setup. I wasnt able to identify what the error was until I ran the project with the following arguments: expo start --no-dev --minify

This is what my environment.js looked like:

import Constants from "expo-constants";
const { manifest } = Constants;

const ENV = {
 dev: {
   apiUrl: localhost,
 },
 staging: {
   apiUrl: "https://test-url.net"
 },
 prod: {
   apiUrl: "https://prod-url.net"
 }
};

const getEnvVars = (env = Constants.manifest.releaseChannel) => {
 // What is __DEV__ ?
 // This variable is set to true when react-native is running in Dev mode.
 // __DEV__ is true when run locally, but false when published.
 if (__DEV__) {
   return ENV.dev;
 } else if (env === 'staging') {
   return ENV.staging;
 } else if (env === 'prod') {
   return ENV.prod;
 }
};

export default getEnvVars;

I’m not entirely sure what I messed up in it’s implementation but that was the cause. After removing it completely and hardcoding URLs the build worked with an expo build:ios -t simulator build and running on a simulator. It is worth noting that doing what expo docs say to run the tar.gz build does not work in Catalina currently.

1 Like

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.