Overview
Synto Mobile uses Expo and EAS (Expo Application Services) for building and deploying the app. The project supports development builds, preview builds, and production releases.
Prerequisites
Before building the app, ensure you have:
Node.js and package manager
Node.js 18 or later
pnpm 10.12.3 (specified in eas.json)
EAS CLI (for cloud builds)
Development tools
For local development:
Android: Android Studio with SDK
iOS: Xcode 14+ (macOS only)
Environment setup
Install dependencies
# Clone the repository
git clone < repository-ur l >
cd synto-mobile
# Install dependencies
pnpm install
Environment variables
Create a .env file in the project root:
# Backend configuration
EXPO_PUBLIC_BACKEND_URL = https://your-backend-url.com
EXPO_PUBLIC_BACKEND_KEY = your-api-key
# Solana RPC (optional, defaults to public RPC)
NEXT_PUBLIC_SOLANA_RPC = https://api.devnet.solana.com
Never commit .env files to version control. Add .env to your .gitignore file.
Development
Running the development server
Start the Expo development server:
Quick start
Platform-specific
This starts the Metro bundler and opens the Expo DevTools. # iOS (macOS only)
pnpm ios
# Android
pnpm android
# Web (for testing)
pnpm web
Development workflow
Scan QR code
iOS: Use Camera app to scan QR code
Android: Use Expo Go app to scan QR code
Enable hot reload
Changes to code will automatically reload the app.
For full native functionality (like Mobile Wallet Adapter), you need to create a development build instead of using Expo Go.
Code quality
The project includes several npm scripts for maintaining code quality:
Linting
Check for issues
Fix issues automatically
The project uses eslint-config-expo for linting rules.
Check formatting
Format code
Prettier formats these file types:
app/**/*.{js,jsx,ts,tsx}
constants/**/*.{js,jsx,ts,tsx}
hooks/**/*.{js,jsx,ts,tsx}
components/**/*.{js,jsx,ts,tsx}
Type checking
pnpm build
# This runs: tsc --noEmit && npm run android:build
TypeScript is configured with strict mode enabled:
{
"extends" : "expo/tsconfig.base" ,
"compilerOptions" : {
"strict" : true ,
"paths" : {
"@/*" : [ "./*" ]
}
}
}
CI pipeline
Run all checks before committing:
This runs:
Type checking (tsc --noEmit)
Linting (lint:check)
Format checking (fmt:check)
Android prebuild
Building the app
Build profiles
The app uses three build profiles defined in eas.json:
Development
Preview
Production
{
"development" : {
"developmentClient" : true ,
"distribution" : "internal"
}
}
Purpose: For testing with full native functionalityFeatures:
Includes development tools
Fast refresh enabled
Internal distribution (TestFlight/Internal Testing)
{
"preview" : {
"distribution" : "internal"
}
}
Purpose: Testing release builds internallyFeatures:
Production-like build
Internal distribution only
No development tools
{
"production" : {
"autoIncrement" : true
}
}
Purpose: App Store/Play Store releasesFeatures:
Fully optimized build
Auto-increments version numbers
Ready for public distribution
EAS Build (Cloud builds)
EAS Build is the recommended way to build Expo apps. It handles all the complexity of native builds in the cloud.
Configure project
This creates eas.json if it doesn’t exist.
Build for Android
# Development build
eas build --profile development --platform android
# Preview build
eas build --profile preview --platform android
# Production build
eas build --profile production --platform android
Build for iOS
# Development build
eas build --profile development --platform ios
# Preview build
eas build --profile preview --platform ios
# Production build
eas build --profile production --platform ios
iOS builds require an Apple Developer account ($99/year).
Local builds
You can also build locally if you have the required development tools installed.
# Prebuild (generates android directory)
pnpm android:build
# or
expo prebuild -p android
# Build APK
cd android
./gradlew assembleRelease
# Build AAB (for Play Store)
./gradlew bundleRelease
Output location:
APK: android/app/build/outputs/apk/release/app-release.apk
AAB: android/app/build/outputs/bundle/release/app-release.aab
# Prebuild (generates ios directory)
expo prebuild -p ios
# Build with Xcode
# 1. Open ios/syntomobile.xcworkspace in Xcode
# 2. Select your target device/simulator
# 3. Product > Archive
# 4. Distribute App
Configuration files
app.json
Main Expo configuration:
{
"expo" : {
"name" : "synto-mobile" ,
"slug" : "synto-mobile" ,
"version" : "1.0.0" ,
"orientation" : "portrait" ,
"icon" : "./assets/images/icon.png" ,
"scheme" : "templateexpobasic" ,
"userInterfaceStyle" : "automatic" ,
"newArchEnabled" : true ,
"android" : {
"package" : "com.juiceee.syntomobile" ,
"adaptiveIcon" : {
"foregroundImage" : "./assets/images/adaptive-icon.png" ,
"backgroundColor" : "#ffffff"
}
},
"plugins" : [
"expo-router" ,
[ "expo-splash-screen" , { /* ... */ }],
"expo-web-browser" ,
"expo-font"
]
}
}
Key configuration options
newArchEnabled: true - Enables React Native’s new architecture (Fabric + TurboModules)
scheme - Deep linking scheme for the app
userInterfaceStyle: "automatic" - Supports both light and dark mode
experiments.typedRoutes: true - Type-safe routing with Expo Router
Splash screen configuration
{
"backgroundColor" : "#FFFFFF" ,
"dark" : {
"backgroundColor" : "#000000" ,
"image" : "./assets/images/splash-icon.png"
},
"image" : "./assets/images/splash-icon.png" ,
"imageWidth" : 200 ,
"resizeMode" : "contain"
}
Separate configurations for light and dark mode.
package.json scripts
Available npm scripts:
{
"scripts" : {
"android" : "expo run:android" ,
"android:build" : "expo prebuild -p android" ,
"build" : "tsc --noEmit && npm run android:build" ,
"ci" : "tsc --noEmit && npm run lint:check && npm run fmt:check && npm run android:build" ,
"dev" : "expo start" ,
"fmt" : "prettier --write 'app/**/*.{js,jsx,ts,tsx}' ..." ,
"fmt:check" : "prettier --check 'app/**/*.{js,jsx,ts,tsx}' ..." ,
"ios" : "expo run:ios" ,
"lint" : "expo lint --fix" ,
"lint:check" : "expo lint" ,
"start" : "expo start" ,
"web" : "expo start --web"
}
}
Testing
Manual testing
Install development build
Build and install a development build on your device: eas build --profile development --platform android
# or
eas build --profile development --platform ios
Connect to dev server
After installing, launch the app and shake your device to open the developer menu. Select “Connect to dev server” and enter your computer’s IP address.
Test features
Wallet connection
Transaction signing
Chat functionality
Token transfers
Network switching
Testing on different networks
The app supports multiple Solana networks:
export class AppConfig {
static clusters : Cluster [] = [
{
id: "solana:devnet" ,
name: "Devnet" ,
endpoint: clusterApiUrl ( "devnet" ),
network: ClusterNetwork . Devnet ,
},
{
id: "solana:testnet" ,
name: "Testnet" ,
endpoint: clusterApiUrl ( "testnet" ),
network: ClusterNetwork . Testnet ,
},
];
}
Switch networks from the settings screen to test on different Solana clusters.
Deployment
Android deployment
Build production AAB
eas build --profile production --platform android
Download build artifact
After the build completes, download the .aab file from the Expo dashboard.
Upload to Google Play Console
Go to Google Play Console
Select your app or create a new app
Navigate to “Release” > “Production”
Upload the .aab file
Fill in release details
Submit for review
iOS deployment
Build production IPA
eas build --profile production --platform ios
Submit to App Store
eas submit --platform ios
Or manually upload via Xcode or App Store Connect.
Configure App Store listing
Go to App Store Connect
Fill in app metadata (description, screenshots, etc.)
Submit for review
Auto-incrementing versions
The production profile has autoIncrement: true, which automatically bumps the build number on each build.
To manually update the version:
{
"expo" : {
"version" : "1.0.1" , // User-facing version
"ios" : {
"buildNumber" : "2" // Internal build number
},
"android" : {
"versionCode" : 2 // Internal version code
}
}
}
Troubleshooting
Clear cache and restart: # Clear Metro cache
expo start --clear
# Clear all caches
rm -rf node_modules
pnpm install
expo start --clear
Rebuild native directories: # Remove native directories
rm -rf android ios
# Regenerate
expo prebuild --clean
Check the build logs in the Expo dashboard:
Go to expo.dev
Navigate to your project
Click on the failed build
Review the logs for errors
Common issues:
Missing credentials (iOS)
Invalid package name (Android)
Dependency conflicts
Wallet adapter not working
Mobile Wallet Adapter requires a development build or production build. It doesn’t work with Expo Go. # Build a development build
eas build --profile development --platform android
Best practices
Use EAS Build Cloud builds are more reliable and don’t require local setup
Test on real devices Test wallet adapter and native features on physical devices
Version control Commit eas.json and app.json to version control
Environment variables Never commit .env files; use EAS Secrets for sensitive values
Enable Hermes
Hermes is enabled by default in Expo. Verify in app.json: {
"expo" : {
"jsEngine" : "hermes"
}
}
Optimize images
Use optimized image formats and appropriate sizes: import { Image } from 'expo-image' ;
< Image
source = { { uri: 'https://...' } }
contentFit = "cover"
transition = { 200 }
/>
Bundle size analysis
Analyze your bundle size: npx react-native-bundle-visualizer
Next steps
App architecture Understand the app structure
Component structure Learn about components
Custom hooks Explore React hooks
Expo documentation Official Expo docs