React Native Expo - atabegruslan/Notes GitHub Wiki
Tutorials
- https://www.youtube.com/playlist?list=PL4cUxeGkcC9ixPU-QkScoRBVxtPPzVjrQ
- https://www.youtube.com/playlist?list=PLC3y8-rFHvwhiQJD1di4eRVN30WWCXkg1
Simple start
1/ Install node
2/ Create new project
Either npx create-expo-app
or npx create-react-native-app
Local Expo CLI has became preferred over the Global one: https://blog.expo.dev/the-new-expo-cli-f4250d8e3421
So npx create-expo-app xxx
became preferred over expo init xxx
Eg: You can start a project like this:
npx create-expo-app@latest projectName --template blank
References
- https://docs.expo.dev/get-started/create-a-project/
- https://docs.expo.dev/more/create-expo/#--template
- A common problem and solution: https://stackoverflow.com/questions/58675179/error-emfile-too-many-open-files-react-native-cli/62437140#62437140
3/ Run
npx create-expo-app
by default creates these scripts in package.json
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
You can run using the Expo Go
app from your phone, or with development build
. The Expo Go
option is simpler. So,
download Expo Go
to your phone,
run npm run start
or yarn start
(A.K.A.: npx expo start
)
scan the QR code from within the Expo Go app.
npx expo start
vs npx expo run
start
defaults to Expo Go.
If you press a
or i
after that, it will run in any attached simulators or devices.
run
automatically runs prebuild under the hood.
It does everything in one command, eg: npx expo run:android
Though it also depends on whats in app.json
and eas.json
.
References
- Earlier version of
Expo Go
(v50): https://expo.dev/go?sdkVersion=50&platform=android&device=true - Use Yarn over NPM because it's faster: https://waverleysoftware.com/blog/yarn-vs-npm
Expo Go
is easy, but limited. Check what is compatible withExpo Go
here: https://reactnative.directory
Development build
- Very good article: https://expo.dev/blog/expo-go-vs-development-builds
- https://docs.expo.dev/guides/local-app-development/#local-app-compilation
Various commands
- https://docs.expo.dev/more/expo-cli/#launch-target
npm install expo-dev-client
thennpx expo start
will run a development buildnpx expo start --dev-client
will run a development build too.npx expo start
will run with Expo Go.npx expo start --clear
will run with Expo Go, without cache.
expo start
vsexpo run
ios
&android
foldersnpx expo prebuild
generatesios
&android
folders.npx expo eject
used to do this, but is now obsolete.
References
- USB debug, a common problem and solution: https://github.com/expo/fyi/blob/main/authorize-android-device.md
- https://niteco.com/articles/from-expo-to-react-native
- https://stackoverflow.com/questions/69060280/react-native-convert-an-expo-bare-project-to-a-pure-react-native-app
Bare vs Expo
Bare means without using Expo nor Metro bundler (nor any other frameworks) to manage it for you. You create the native app and configure everything yourself.
Back in the days, Expo wasn't fully stable and had some drawbacks in terms of using native Code and modules but today most projects can be run in Expo really well.
https://docs.expo.dev/workflow/prebuild is used to adapt from Expo to bare. But not fully bare.
You can create and run an Expo app on Expo Go on your phone and emulator. But when you start working with native stuff you'll need a dev build
Local app compilation
To build your project locally you can use compile commands from Expo CLI which generates the android and ios directories:
npx expo run:android
npx expo run:ios
The above commands compile your project, using your locally installed Android SDK or Xcode, into a debug build of your app.
These compilation commands initially run npx expo prebuild to generate native directories (android and ios) before building, if they do not exist yet. If they already exist, this will be skipped.
You can also add the --device
flag to select a device to run the app on — you can select a physically connected device or emulator/simulator.
You can pass in --variant release
(Android) or --configuration Release
(iOS) to build a production build of your app. Note that these builds are not signed and you cannot submit them to app stores. To sign your production build, see Local app production.
expo-dev-client
Local builds with If you install expo-dev-client to your project, then a debug build of your project will include the expo-dev-client UI and tooling, and we call these development builds.
npx expo install expo-dev-client
To create a development build, you can use local app compilation commands (npx expo run:[android|ios]
) which will create a debug build and start the development server.
Android Studio and xCode
It's advantageous to install xCode
and Android Studio
too.
Typical system requirements:
xCode
needs ~50GB disk space, Android Studio
needs ~20GB disk space. Overall, a Mac of ~200GB disk space.
Android Emulator typically needs 16GB RAM & 16GB disk space. Though 8GB of RAM can still cope.
References
- Common iOS emulator problem: https://github.com/expo/expo/issues/21727#issuecomment-1471621054
- If you have an older version of Mac, then you'll probably need an older version of
xCode
: https://developer.apple.com/download/all/ . Also see this for reference: https://developer.apple.com/support/xcode As of 2024, xCode 16 is buggy: https://www.reddit.com/r/iOSProgramming/comments/1flfm36/xcode_16_is_buggy_a_tragic_tale_of_regret_and/?rdt=39591
Common things
Query
- Use Tanstack React-Query from now on: https://www.npmjs.com/package/react-query -> https://tanstack.com/query/latest/docs/framework/react/quick-start
- Common good-to-knows:
Push notification
Awesome tutorial:
PS: If you changed Private Key and you need to set a new private key. You can delete the old key and then add a new one.
To delete existing key: eas credentials
. Navigate thru the prompts, select Google Service Account
. Keep navigating and find Delete a Google Service Account Key
For backend:
Icon:
The notification icon is tricky, and various solutions are all over the internet. But just do this (2025 solution):
"notification": {
"icon": "./assets/images/icon-notif.png",
"color": "#000000"
},
- Have the above in
app.json
, same level/nest as "android" and "ios". - 96x96 png, white content and transparent background.
Tools:
Others:
- https://docs.expo.dev/push-notifications/sending-notifications-custom
- https://docs.expo.dev/push-notifications/sending-notifications
- https://docs.expo.dev/push-notifications/receiving-notifications
- https://developer.apple.com/documentation/usernotifications
- https://firebase.google.com/docs/cloud-messaging/android/client
- https://firebase.google.com/docs/cloud-messaging/ios/client
- https://www.npmjs.com/package/react-native-push-notification
- https://www.youtube.com/watch?v=MjdF5HM05ls
- https://firebase.google.com/docs/cloud-messaging/ios/client
Data management
- https://rnfirebase.io/reference/auth/authprovider
- https://dev.to/alvessteve/the-complete-guide-to-env-variable-in-react-native-5999
- https://dev.to/bhatvikrant/how-to-add-environment-variables-in-a-react-native-project-with-ts-2ne5
- https://www.freecodecamp.org/news/how-to-store-data-locally-in-react-native-expo
- https://docs.expo.dev/develop/user-interface/store-data/#expo-filesystem (Works with Expo Go, but slow)
- MMKV https://github.com/mrousavy/react-native-mmkv (Doesn't work with Expo Go, but fast)
- Jotai https://www.youtube.com/watch?v=-AR2PN38ovo
- Zustand
- https://www.npmjs.com/package/@clerk/clerk-expo (Maybe not for RN)
- https://blog.codemagic.io/redux-vs-recoil-for-react-native
Social media integration
Toast messages
- https://www.youtube.com/watch?v=SgoI-fRiFTM
- Further customization: https://stackoverflow.com/a/70797747/21917494
Audio
- https://docs.expo.dev/versions/latest/sdk/audio
- https://docs.expo.dev/versions/latest/sdk/audio-av/
- https://github.com/expo/expo/discussions/18869#discussioncomment-8404583
At its most bare-basic
import { Audio } from 'expo-av';
async function playSound() {
const { sound } = await Audio.Sound.createAsync( require('../assets/audio/xxx.wav') );
await sound.playAsync();
}
<Button title="Play Sound" onPress={playSound} />
Camera
Forms
Keyboard Avoidance
- https://www.youtube.com/watch?v=jhyuk68YdWA
- https://www.npmjs.com/package/react-native-keyboard-aware-scroll-view
OS specific frontend styling
Paypal integration
This tutorial is for RN Cli: https://www.npmjs.com/package/react-native-paypal - react-native link react-native-paypal
generates android
& ios
folders
This tutorial is for Expo: https://chatgpt.com/share/d1c838b8-2e6e-4f89-92b6-d603d2a3f176 - expo eject
generates android
& ios
folders
Routers and navigators
- Expo-router vs React Navigation: https://www.reddit.com/r/reactnative/comments/14apzyj/comment/jocmfmy
- https://docs.expo.dev/router/navigating-pages/
- https://expo.github.io/router/docs/migration/react-navigation/params
- https://www.youtube.com/watch?v=Z20nUdAUGmM
- https://www.youtube.com/watch?v=AP08wUBhpKM
- https://docs.expo.dev/router/advanced/drawer
How to solve this problem ("RNCSafeAreaProvider
was not found in the UIManager
Error") when using Expo Drawer Nav ( https://docs.expo.dev/router/advanced/drawer )
- https://stackoverflow.com/a/70891254
- https://github.com/software-mansion/react-native-reanimated/issues/4736#issuecomment-1639967526
package.json
{
"name": "drawers",
"version": "1.0.0",
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"@react-native-community/masked-view": "^0.1.11",
"@react-navigation/drawer": "^6.7.2",
"expo": "~51.0.28",
"expo-router": "^3.5.23",
"expo-status-bar": "~1.12.1",
"react": "18.2.0",
"react-native": "0.74.5",
"react-native-gesture-handler": "^2.18.1",
"react-native-reanimated": "3.10.1",
"react-native-safe-area-context": "^4.10.9",
"react-native-screens": "^3.34.0"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}
- https://reactnavigation.org/docs/drawer-based-navigation
- https://docs.expo.dev/router/advanced/nesting-navigators
- https://reactnavigation.org/docs/configuring-links/
- Navigate and clear history
- Back: https://reactnative.dev/docs/backhandler
- Or simpler:
import { useRouter } from 'expo-router';
const router = useRouter();
router.back();
Deep Linking
- Example: https://github.com/Ruslan-Aliyev/DeepLinking_ReactNative
- https://reactnavigation.org/docs/deep-linking
- https://docs.expo.dev/linking/into-your-app/
- https://www.youtube.com/watch?v=odenjd0kGGg
- https://reactnative.dev/docs/linking#enabling-deep-links
- https://docs.expo.dev/linking/overview/
Tabs
https://gist.github.com/atabegruslan/07fc9e556141b7a5e27c7ed7bf8a96c0
Render HTML
FlatList Infinite Scroll
Flash List
- https://github.com/Shopify/flash-list
- https://gist.github.com/atabegruslan/e1b124673144da40ce32d777478bed6d
- https://shopify.github.io/flash-list/docs/known-issues
Payments
https://github.com/atabegruslan/Notes/wiki/React-Native-Payments
Open Phone's Email App
https://gist.github.com/atabegruslan/0aa755192f7db9c940feee12187255ee
Background Tasks
- https://expo.dev/blog/goodbye-background-fetch-hello-expo-background-task
- https://docs.expo.dev/versions/latest/sdk/background-task
Publish
EAS
- https://docs.expo.dev/eas-update/getting-started/
npm install --global eas-cli
Pre-publish
npx expo-doctor@latest
Advice: Use 'npx expo install --check' to review and upgrade your dependencies.
- Credential related: https://docs.expo.dev/app-signing/app-credentials
- Keystore: https://www.youtube.com/watch?v=3lDtAf8Jk_c
1/ https://docs.expo.dev/workflow/prebuild 1a/ https://www.youtube.com/watch?v=2yHI0e4MzUE
-
iOS
Distribution certificate: https://www.youtube.com/watch?v=DLvdZtTAJrE&t=600s -
https://www.sphinx-solution.com/blog/cost-to-put-an-app-on-the-app-store
If you are just using HTTPS REST API, Websockets and/or WebRTC, then just tick the standard option.
Publishing - Android
Google Play Console don't accept .apk
anymore
Publishing - iOS
Different ways: https://developer.apple.com/help/app-store-connect/manage-builds/upload-builds
eas build --platform ios [--profile preview2]
andeas submit -p ios --latest
with EAS (expo.dev): https://www.notjust.dev/blog/2022-03-29-how-to-publish-expo-react-native-app-to-apple-app-store- Archive, and then upload with xCode:
- In CLI, build
.xacrhive
files (eas build -p ios [--profile preview2] [--local]
), and then upload with xCode (xCode > organizer window > click upload to testflight): https://developer.apple.com/documentation/xcode/distributing-your-app-for-beta-testing-and-releases xcrun altool
: https://help.apple.com/asc/appsaltool- Transporter app: Need to get it from Apple App Store
- Even though it's free, you still need an Apple ID associated with an payment method.
- If you don't have an Apple ID associated with an payment method; Then ask someone with an Apple ID associated with an payment method, ask them to download it and send it to you as
.zip
, then you unzip it and drag it into theApplications
folder. Then you'll be prompted to login with your Apple ID, here you can login with your own Apple ID.
- If you don't have an Apple ID associated with an payment method; Then ask someone with an Apple ID associated with an payment method, ask them to download it and send it to you as
- Even though it's free, you still need an Apple ID associated with an payment method.
If you encounter this issue below, you need to agree to Apple's latest contract (2024).
https://stackoverflow.com/questions/78680844/ios-you-do-not-have-required-contracts-to-perform-an-operation
https://forums.developer.apple.com/forums/thread/710906
Before agreeing
After agreeing
Filling questionaire for review > Giving Screenshots
What screenshot dimensions App Store Connect needs for review
So:
References:
- https://cic.ubc.ca/2023/08/28/how-to-publish-an-ios-app-to-testflight
- https://developer.apple.com/help/app-store-connect/test-a-beta-version/testflight-overview
- https://developer.apple.com/testflight
- https://www.youtube.com/watch?v=cdUVbpT-Vks&t=487s
- https://www.youtube.com/watch?v=DLvdZtTAJrE&t=994s
- https://stackoverflow.com/a/52661591
- https://www.kodeco.com/10868372-testflight-tutorial-ios-beta-testing
Testing
Alpha testing = internal testing.
Beta testing = external testing.
https://github.com/atabegruslan/Notes/wiki/Testing
In both iOS and Android. Beta testing isn't required. If you are confident enough, you can just go straight to releasing it.
Update
app.json
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.yyy.xxx",
"buildNumber": "1",
"config": {
"usesNonExemptEncryption": false
}
},
"android": {
"package": "com.yyy.xxx",
"versionCode": 1,
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
Update - Android
Increment versionCode
!
When testing: Testing
> Internal Testing
> Create new release
& add testers
When creating anew: (Todo)
This step isn't necessary
- https://www.notjust.dev/blog/2022-04-11-how-to-publish-expo-react-native-app-to-google-play-store#creating-google-service-account
- https://www.notjust.dev/blog/2022-04-11-how-to-publish-expo-react-native-app-to-google-play-store#updating-application
If you do it (Linking service account and downloading the key), you can then publish new releases automatically by: eas build --platform android
then eas submit -p android --latest
, with eas.json
:
{
...
"submit": {
"production": {
"android": {
"serviceAccountKeyPath": "path to that downloaded key"
}
}
}
}
If not, then just eas build --platform android
, manually download build from expo.dev and upload to Google Play Console.
Update - iOS
- Increment
buildNumber
! Version number can stay the same - esp for small changes,eas build --platform=ios
theneas submit -p ios --latest
- https://www.youtube.com/watch?v=LE4Mgkrf7Sk&t=1654s
- https://www.youtube.com/watch?v=cdUVbpT-Vks&t=710s
Versions
Don't forget to update remote version too https://docs.expo.dev/build-reference/app-versions/#remote-version-source
So:
eas build:version:set
to set Android versionCode
and iOS buildNumber
, and chose remote. eas.json
will be updated.
eas build:version:sync
And don't forget to update:
android/app/build.gradle
'sversionCode
andversionName
versionCode
corresponds toapp.json
's AndroidversionCode
versionName
corresponds toapp.json
'sversion
ios/{appname}/Info.plist
'sCFBundleVersion
andCFBundleShortVersionString
:CFBundleVersion
corresponds toapp.json
's iOSbuildNumber
CFBundleShortVersionString
corresponds toapp.json
'sversion
The app version number is shown in the App Store after an app is released, but the build version number is not; it is only visible to TestFlight Beta testers who are invited to test your app and in App Store Connect.
AppStoreConnect's other version number
The version number 0.01 was set by the development team during the app creation process (xCode > General > Identity > Version). It is not a number that Apple assigned.
To change it:
- Either release the app ( click on your iOS submission. Once you do this, if you scroll down, there will be a version section where you can update the number ) on the App Store
- Or select the “cancel this release” link found in the blue highlighted text directly under “iOS App Version 0.01.”
After cancelling the release, you'll see:
Also, after your app is already in store, and then you want to update it with a new build, you'll have to create a new version, and this is another time when that version has to increment. https://developer.apple.com/help/app-store-connect/update-your-app/create-a-new-version
After that, you will have to fill the form, include your latest build, submit to review, just like before.
Soon you will get an email from Apple notifying you that your update went thru. And you will see in your Apple Store:
Others
Support
Google Play Developer support
- https://support.google.com/googleplay/android-developer/gethelp
[email protected]
- https://developer.android.com/support.html
Apple
- https://developer.apple.com
- https://appstoreconnect.apple.com
- Login at: https://idmsa.apple.com/appleauth/auth/signin
- Apple support:
[email protected]
[email protected]
[email protected]
- https://feedbackassistant.apple.com https://developer.apple.com/support/technical
- https://developer.apple.com/forums
Expo:
Theory
Metro; The JavaScript bundler for React Native:
- https://github.com/facebook/metro
- https://developers.facebook.com/blog/post/2021/11/01/eli5-metro-javascript-bundler-react-native
Platform Specific
Audio
Android emulator control output volume
Android emulator control input microphone - Method 1
Android emulator control input microphone - Method 2
iOS simulator control output volume
iOS simulator control input microphone
https://stackoverflow.com/questions/3195739/turn-off-sound-in-iphone-simulator
Mac control input microphone
Start afresh
Android
Clear the emulator.
Open the android
folder in Android Studio. Go to File
> Invalidate Caches
.
Or just delete app in emulator.
iOS
Delete app in simulator.
Reinstall all CocoaPods afresh: rm -rf node_modules; rm -rf ios/build; rm -rf ios/Pods; rm -rf ios/Podfile.lock; yarn; yarn podinstall
.
Update Pods cd ios
, then pod repo update
, then pod install
.
Or simple delete these folders: ios/build
and ios/Pods
.
PS: A Pod is a third-party library or framework that is integrated into a project using CocoaPods (CocoaPods is a dependency manager)
Android
Dealing with multiple gradles
When you run npx expo run:android
, you can also see:
yarn run v1.22.22
$ expo run:android --variant debug
› Building app...
Downloading https://services.gradle.org/distributions/gradle-8.8-all.zip
- https://stackoverflow.com/a/26254725
- https://stackoverflow.com/a/34532235
- https://stackoverflow.com/a/48155800
- https://github.com/NativeScript/android/issues/553#issuecomment-295862685
- https://www.simplilearn.com/tutorials/gradle-tutorial/gradle-installation
- Common issues:
- https://github.com/facebook/react-native/issues/32858
- Solution: Downgrade to Java v17 https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=32227 , remove
node_modules
and runyarn
again.
- Solution: Downgrade to Java v17 https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=32227 , remove
- https://github.com/facebook/react-native/issues/32858
iOS
iOS simulator use simulator's keyboard instead of Mac's keyboard
Screenshot
Run many Simulators
Firebase
Sometimes its faster to distribute builds among other developers during development phase
- https://30dayscoding.com/blog/adding-firebase-hosting-to-react-native-apps
- https://medium.com/one-thing-i-learned-today/perfect-guide-for-releasing-your-react-native-ios-and-android-app-using-firebase-app-distribution-7107f98ca122
Upload
Drag & Drop the build file (eg: .apk
) into Firebase, like any online dropbox.
Invite others
https://www.youtube.com/watch?v=V3z97mWuvmA&t=180s