This describes how the HybridApp architecture works and the conventions that MUST be followed when working with it.
- HybridApp - The production app containing both "Expensify Classic" and "New Expensify"
- NewDot - The new Expensify application (this repository)
- Mobile-Expensify - Git submodule containing Expensify Classic code
- Standalone - NewDot running independently without Classic integration
Currently, the production Expensify app contains both "Expensify Classic" and "New Expensify". The file structure is as follows:
- 📂 App
- 📂 android: New Expensify Android specific code (not a part of HybridApp native code)
- 📂 ios: New Expensify iOS specific code (not a part of HybridApp native code)
- 📂 src: New Expensify TypeScript logic
- 📂 Mobile-Expensify:
gitsubmodule that is pointed to Mobile-Expensify
You can only build HybridApp if you have been granted access to Mobile-Expensify. For most contributors, you will be working on the standalone NewDot application.
For most contributors, you SHOULD work on the standalone NewDot application instead.
When working with HybridApp:
- Initialize the submodule:
git submodule init - Update the submodule:
git submodule update - Configure automatic updates:
git config --global submodule.recurse true
The native code for HybridApp is located in:
./Mobile-Expensify/Android(not./android)./Mobile-Expensify/iOS(not./ios)
Changes to ./android and ./ios folders at the root will NOT affect HybridApp builds.
To open HybridApp projects:
- Android Studio:
./Mobile-Expensify/Android - Xcode:
./Mobile-Expensify/iOS/Expensify.xcworkspace
Default npm scripts target HybridApp when the submodule exists:
| Command | Description |
|---|---|
npm run android |
Build HybridApp for Android |
npm run ios |
Build HybridApp for iOS |
npm run ipad |
Build HybridApp for iPad |
npm run ipad-sm |
Build HybridApp for small iPad |
npm run pod-install |
Install pods for HybridApp |
npm run clean |
Clean native code of HybridApp |
Append -standalone to target standalone NewDot:
| Command | Description |
|---|---|
npm run install-standalone |
Install standalone NewDot node modules (npm install) |
npm run clean-standalone |
Clean native code for standalone NewDot |
npm run android-standalone |
Build NewDot for Android in standalone mode |
npm run ios-standalone |
Build NewDot for iOS in standalone mode |
npm run pod-install-standalone |
Install pods for standalone NewDot |
npm run ipad-standalone |
Build NewDot for iPad in standalone mode |
npm run ipad-sm-standalone |
Build NewDot for small iPad in standalone mode |
- Follow NewDot setup instructions first
- Initialize submodule:
git submodule init - Update submodule:
git submodule update- For faster setup:
git submodule update --init --progress --depth 100
- For faster setup:
- Configure Git for automatic submodule updates:
git config --global submodule.recurse true
If you have access to Mobile-Expensify and commands fail, add to ~/.gitconfig:
[url "https://github.com/"]
insteadOf = ssh://git@github.com/
To prevent submodule changes from appearing in git status, add to .git/config:
[submodule "Mobile-Expensify"]
ignore = all
If you need to modify Mobile-Expensify source code:
- Create your own fork of Mobile-Expensify
- Swap the origin:
cd Mobile-Expensify && git remote set-url origin <YOUR_FORK_URL>
The Mobile-Expensify directory points to a specific commit. To update:
- Download latest changes:
git submodule update --remote - Manual update: Switch branches and pull within the
Mobile-Expensifydirectory
When switching branches, run git submodule update to ensure compatibility.
- Patches are applied automatically during
npm install - Add HybridApp-specific patches:
npx patch-package <PACKAGE_NAME> --patch-dir Mobile-Expensify/patches
For extended documentation, troubleshooting, and pro tips, refer to the platform specific guides:
- 📱 iOS Development: iOS Setup Instructions
- 🤖 Android Development: Android Setup Instructions