Last active
December 9, 2024 14:15
-
-
Save GollyJer/9668ac1125eaad3e6d8cc3309867cf9d to your computer and use it in GitHub Desktop.
app.config.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ConfigContext } from '@expo/config'; | |
// eslint-disable-next-line no-console | |
// console.log('ENV', process.env); | |
// expands type in the vscode tooltip. | |
type ExpandTooltip<T> = T extends infer O ? { [K in keyof O]: O[K] } : never; | |
const EXPO_SDK = '51'; | |
const BINARY_ITERATION_FOR_SDK = '1'; // start with 1. CAN NOT BE 0. | |
const OTA_ITERATION_FOR_BINARY = '1'; // start with 1. CAN NOT BE 0. | |
const appName = ''; | |
const owner = ''; | |
const scheme = ''; // supptrack:// URLs will open the app when tapped. | |
const appStoreUniqueId = `${owner}.${scheme}.app`; | |
const expoProjectSlug = `${scheme}-app`; | |
const expoProjectId = ''; | |
const updateUrl = `https://u.expo.dev/${expoProjectId}`; | |
const icons = { | |
android: { | |
icon: './assets/images/supptrack-icon-android.png', | |
adaptiveIcon: { | |
foregroundImage: './assets/images/supptrack-adaptive-icon-android.png', | |
backgroundColor: '#000000', | |
monochromeImage: './assets/images/supptrack-adaptive-icon-monochrome-android.png', | |
}, | |
dev: { | |
icon: './assets/images/supptrack-icon-dev-android.png', | |
adaptiveIcon: { | |
foregroundImage: './assets/images/supptrack-adaptive-icon-android-dev.png', | |
backgroundColor: '#023F05', | |
monochromeImage: './assets/images/supptrack-adaptive-icon-monochrome-android-dev.png', | |
}, | |
}, | |
staging: { | |
icon: './assets/images/supptrack-icon-staging-android.png', | |
adaptiveIcon: { | |
foregroundImage: './assets/images/supptrack-adaptive-icon-android-staging.png', | |
backgroundColor: '#C27025', | |
monochromeImage: './assets/images/supptrack-adaptive-icon-monochrome-android-staging.png', | |
}, | |
}, | |
}, | |
ios: { | |
icon: './assets/images/supptrack-icon-ios.png', | |
dev: { | |
icon: './assets/images/supptrack-icon-dev-android.png', | |
}, | |
staging: { | |
icon: './assets/images/supptrack-icon-staging-android.png', | |
}, | |
}, | |
}; | |
const splashScreens = { | |
mobile: './assets/images/supptrack-splash.png', | |
tablet: './assets/images/supptrack-splash-tablet.png', | |
}; | |
const backgroundColor = '#000000'; | |
// A binary release is required when any non-javascript code is added to the build. This happens | |
// with every Expo SDK release and in between SDK releases when npm packages that require native | |
// code are added to the build. | |
// | |
// The first build for an Expo SDK will be <sdk_number>.1.1 | |
// We iterate the second number for every binary build on the same SDK. | |
// We identify this binary via the `runtimeVersion` key and when the code is built we | |
// create an Expo `--release-branch` with the same identifier (via `eas.json`). | |
// | |
// This allows us to push OTA, javascript only, updates to specific binaries. | |
const runtimeVersion = `${EXPO_SDK}.${BINARY_ITERATION_FOR_SDK}`; | |
// Every binary released is identified by the runtimeVersion. | |
// appVersion represents the full set of code, native + javascript, a user has on their device. | |
// We iterate appVersion for every OTA javascript push to a binary and show this value inside the | |
// app via the `extra"`key to trigger and display the WhatsNew modal. | |
const appVersion = `${EXPO_SDK}.${BINARY_ITERATION_FOR_SDK}.${OTA_ITERATION_FOR_BINARY}`; | |
// === For iOS binaries built with EAS CLI === | |
// Version is our runtimeVersion/release-channel. | |
// Build is our appVersion. | |
// =========================================== | |
// For each iOS release TestFlight has a "version" and groups "builds" underneath "version". | |
// iOS buildNumber is a binary identifier that must change with every binary build. | |
// https://diigo.com/0mo110 | |
// Expo sets the "version" to the top level version field in this config and we use our appversion | |
// as an iterator for the build number. | |
const iosBuildNumber = appVersion; | |
// === For Android binaries built with EAS CLI === | |
// Version is our runtimeVersoin/ReleaseChannel. | |
// versionCode is our androidVersionCode. | |
// =========================================== | |
// Android versionCode is a binary identifier that must increase with every binary build. | |
// The greatest value Google Play allows for versionCode is 2100000000. | |
// https://diigo.com/0mo0s4 | |
// The following generates an incremented number every 10 seconds starting on app release date and | |
// works for 500 years. | |
const appInitUnixTime = Math.floor(new Date(2023, 2, 10).getTime() / 1000); // March is 2 because months are 0-indexed | |
const currentUnixTime = Math.floor(Date.now() / 1000); | |
const androidVersionCode = Math.round((currentUnixTime - appInitUnixTime) / 10); | |
const android: ExpandTooltip<ConfigContext['config']['android']> = { | |
package: appStoreUniqueId, | |
versionCode: androidVersionCode, | |
icon: icons.android.icon, | |
adaptiveIcon: { | |
foregroundImage: icons.android.adaptiveIcon.foregroundImage, | |
backgroundColor: icons.android.adaptiveIcon.backgroundColor, | |
}, | |
googleServicesFile: process.env.PROD_FIREBASE_ANDROID_CONFIG, | |
splash: { | |
backgroundColor, | |
image: splashScreens.mobile, | |
}, | |
permissions: ['com.android.vending.BILLING'], | |
}; | |
const ios: ExpandTooltip<ConfigContext['config']['ios']> = { | |
buildNumber: iosBuildNumber, | |
bundleIdentifier: appStoreUniqueId, | |
icon: icons.ios.icon, | |
splash: { | |
backgroundColor, | |
image: splashScreens.mobile, | |
tabletImage: splashScreens.tablet, | |
}, | |
googleServicesFile: process.env.PROD_FIREBASE_IOS_CONFIG, | |
supportsTablet: true, | |
config: { | |
usesNonExemptEncryption: false, | |
}, | |
infoPlist: { | |
UIBackgroundModes: ['remote-notification'], | |
}, | |
entitlements: { | |
'aps-environment': 'production', | |
}, | |
}; | |
const initialConfig: ExpandTooltip<ConfigContext['config']> = { | |
experiments: { | |
tsconfigPaths: true, | |
}, | |
name: appName, | |
notification: { | |
icon: './assets/images/notification-icon-android.png', | |
}, | |
plugins: [ | |
'expo-font', | |
'expo-asset', | |
'./plugins/withFirebaseBuildErrorFix_iOS.cjs', | |
'./plugins/withShakeIntegration_iOS.cjs', | |
'./plugins/withChatNotificationMetaData_Android.cjs', | |
'react-native-edge-to-edge', | |
'@react-native-firebase/app', | |
'@react-native-firebase/app-check', | |
'@react-native-firebase/auth', | |
[ | |
'expo-build-properties', | |
{ | |
ios: { | |
useFrameworks: 'static', | |
}, | |
android: { | |
minSdkVersion: 24, | |
}, | |
}, | |
], | |
[ | |
'react-native-vision-camera', | |
{ | |
cameraPermissionText: 'This will allow you to scan product bar codes.', | |
enableCodeScanner: true, | |
enableLocation: false, | |
}, | |
], | |
[ | |
'react-native-permissions', | |
{ | |
iosPermissions: [ | |
// 'AppTrackingTransparency', | |
// 'Bluetooth', | |
// 'Calendars', | |
// 'CalendarsWriteOnly', | |
// 'Camera', // NOTE: react-native-vision-camera is handling this. | |
// 'Contacts', | |
// 'FaceID', | |
// 'LocationAccuracy', | |
// 'LocationAlways', | |
// 'LocationWhenInUse', | |
// 'MediaLibrary', | |
// 'Microphone', | |
// 'Motion', | |
'Notifications', | |
// 'PhotoLibrary', | |
// 'PhotoLibraryAddOnly', | |
// 'Reminders', | |
// 'Siri', | |
// 'SpeechRecognition', | |
// 'StoreKit', | |
], | |
}, | |
], | |
], | |
slug: expoProjectSlug, | |
scheme, | |
android, | |
ios, | |
extra: { | |
appVersion, | |
eas: { projectId: expoProjectId }, | |
}, | |
assetBundlePatterns: ['assets/images/*'], | |
backgroundColor, | |
primaryColor: backgroundColor, | |
icon: icons.android.icon, | |
jsEngine: 'hermes', | |
orientation: 'portrait', | |
owner, | |
platforms: ['ios', 'android'], | |
privacy: 'unlisted', | |
splash: { resizeMode: 'cover' }, | |
updates: { | |
enabled: true, | |
fallbackToCacheTimeout: 10_000, | |
checkAutomatically: 'ON_LOAD', | |
url: updateUrl, | |
requestHeaders: { | |
'expo-channel-name': runtimeVersion, | |
}, | |
}, | |
userInterfaceStyle: 'automatic', | |
runtimeVersion: { policy: 'appVersion' }, | |
version: runtimeVersion, // This is the "Version" number in both app stores. | |
}; | |
const config = () => { | |
let finalConfig = initialConfig; | |
if (process.env.APP_ENV === 'dev') { | |
finalConfig = { | |
...initialConfig, | |
plugins: [...(initialConfig.plugins ?? [])], | |
android: { | |
...initialConfig.android, | |
package: `dev.${initialConfig.android?.package}`, | |
icon: icons.android.dev.icon, | |
adaptiveIcon: { | |
...initialConfig.android?.adaptiveIcon, | |
foregroundImage: icons.android.dev.adaptiveIcon.foregroundImage, | |
backgroundColor: icons.android.dev.adaptiveIcon.backgroundColor, | |
monochromeImage: icons.android.dev.adaptiveIcon.monochromeImage, | |
}, | |
googleServicesFile: process.env.DEV_FIREBASE_ANDROID_CONFIG, | |
}, | |
ios: { | |
...initialConfig.ios, | |
bundleIdentifier: `dev.${initialConfig.ios?.bundleIdentifier}`, | |
icon: icons.ios.dev.icon, | |
googleServicesFile: process.env.DEV_FIREBASE_IOS_CONFIG, | |
entitlements: { | |
'aps-environment': 'development', | |
}, | |
}, | |
}; | |
} | |
if (process.env.APP_ENV === 'staging') { | |
finalConfig = { | |
...initialConfig, | |
plugins: [...(initialConfig.plugins ?? [])], | |
android: { | |
...initialConfig.android, | |
package: `staging.${initialConfig.android?.package}`, | |
icon: icons.android.staging.icon, | |
adaptiveIcon: { | |
...initialConfig.android?.adaptiveIcon, | |
foregroundImage: icons.android.staging.adaptiveIcon.foregroundImage, | |
backgroundColor: icons.android.staging.adaptiveIcon.backgroundColor, | |
monochromeImage: icons.android.staging.adaptiveIcon.monochromeImage, | |
}, | |
googleServicesFile: process.env.STAGING_FIREBASE_ANDROID_CONFIG, | |
}, | |
ios: { | |
...initialConfig.ios, | |
bundleIdentifier: `staging.${initialConfig.ios?.bundleIdentifier}`, | |
icon: icons.ios.staging.icon, | |
googleServicesFile: process.env.STAGING_FIREBASE_IOS_CONFIG, | |
entitlements: { | |
'aps-environment': 'development', | |
}, | |
}, | |
}; | |
} | |
return { | |
expo: { | |
...finalConfig, | |
}, | |
}; | |
}; | |
// Expo requires default export of app.config.ts | |
// eslint-disable-next-line import/no-default-export | |
export default config; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment