React Native + Expo application that builds both PWA and Android APK from a single codebase
This repository contains the frontend for the AI Assistant application. The backend API is in a separate repository.
- Overview
- Features
- Architecture
- Prerequisites
- Getting Started
- Development
- Building
- Deployment
- Project Structure
- Configuration
- Troubleshooting
This is a React Native application built with Expo that can deploy to:
- Web (PWA): Progressive Web App for browsers
- Android: Native Android APK for mobile devices
Key Architecture Decision: ONE codebase builds BOTH targets, maximizing code reuse (90%+) while handling platform-specific differences via Platform.OS checks.
Technology Stack:
- Framework: React Native 0.81.5 + Expo 54.0.0
- Language: TypeScript 5
- Styling: NativeWind 4.x (Tailwind CSS for React Native)
- Navigation: React Navigation (Stack + Tabs)
- State Management: React Hooks + Context API
- Storage: MMKV (synchronous storage)
- ✅ Authentication: Google OAuth login with platform-specific flows
- ✅ AI Chat: Real-time streaming chat with Claude models (Sonnet 4.5, Opus 4.1, Haiku 3.5)
- ✅ Conversations: Save, load, and delete chat history
- ✅ MCP Integration: Connect to external tools (Gmail, Drive, Calendar, Tasks)
- OAuth-based server connections
- Tool discovery and execution
- Dynamic form generation
- ✅ 4-Tab Navigation: Chat, History, MCP, Settings
- ✅ Platform-specific Storage: localStorage (web) / SecureStore (Android)
- ✅ Responsive UI: NativeWind/Tailwind styling
- ✅ API Client: Fetch wrapper with JWT + CSRF token authentication
- ✅ PWA Support: Complete Progressive Web App implementation
- Web app manifest with install prompts
- Service worker with offline support
- Intelligent caching (cache-first for assets, network-first for API)
- Install button component
- iOS and Android PWA compatibility
- 🚧 Android APK: Local build via WSL + Gradle (see
LLM_BUILD_ANDROID_APK.md)
- 📋 Push Notifications: Web Push API and expo-notifications (optional)
- 📋 Advanced Features: File uploads, voice input, etc.
┌─────────────────────────────────────────┐
│ Frontend (This Repository) │
│ ├── PWA Build → npm run build:web │
│ │ └── Deploys to Firebase Hosting │
│ │ │
│ └── Android APK → npm run build:android│
│ └── Built via EAS Build │
└──────────────┬──────────────────────────┘
│
│ HTTPS REST API
│
┌──────────────▼──────────────────────────┐
│ Backend API (Separate Repository) │
│ https://ai-assistant-backend.run.app │
└─────────────────────────────────────────┘
- Node.js: 20+ (LTS recommended)
- npm: 10+
- Expo CLI: Installed globally or use
npx - Android Studio: For Android development (optional)
- Backend API: Running at
http://localhost:8080(development) or production URL
git clone https://github.com/sdhector/ai-agent-frontend.git
cd ai-agent-frontendnpm installEdit lib/constants.ts and update API_BASE_URL:
export const API_BASE_URL = Platform.select({
web: 'http://localhost:8080', // Local backend
default: 'http://localhost:8080',
// For Android emulator:
// android: 'http://10.0.2.2:8080',
});Or update app.json:
{
"expo": {
"extra": {
"apiUrl": "http://localhost:8080"
}
}
}# Start Expo dev server
npm start
# Run on web (PWA)
npm run web
# Run on Android emulator
npm run androidExpected output:
Metro waiting on exp://localhost:8081
› Press w │ open web
› Press a │ open Android
- Open app in browser or Android emulator
- Navigate to Chat tab
- Click "Test Backend Connection" button
- Should see "✅ Connected" status
ai-agent-frontend/
├── app/ # Main application code
│ ├── app.tsx # Root component
│ ├── navigators/
│ │ └── AppNavigator.tsx # React Navigation config
│ ├── screens/ # All app screens
│ │ ├── LoginScreen.tsx
│ │ ├── ChatScreen.tsx
│ │ ├── ConversationsScreen.tsx
│ │ ├── MCPScreen.tsx
│ │ └── SettingsScreen.tsx
│ ├── components/ # UI components
│ │ ├── ui/ # Reusable UI components
│ │ ├── chat/ # Chat-specific components
│ │ └── mcp/ # MCP-specific components
│ ├── services/ # Business logic
│ │ ├── api-client.ts # Fetch wrapper
│ │ ├── storage.ts # MMKV storage
│ │ ├── constants.ts # API URLs, config
│ │ └── csrf.ts # CSRF token handling
│ ├── contexts/ # React context providers
│ └── utils/hooks/ # Custom React hooks
├── index.js # Entry point
├── assets/ # Icons, images
├── public/ # PWA assets (manifest, service worker)
├── android/ # Native Android project (generated)
├── app.json # Expo configuration
├── eas.json # EAS Build config
├── package.json
├── tsconfig.json
└── tailwind.config.js # NativeWind config
- Make changes to code
- Hot reload automatically updates
- Test on web:
npm run web - Test on Android:
npm run android - Type check:
npm run type-check - Commit:
git commit -m "feat: your changes"
Using Expo Router (file-based routing):
# Create new screen
touch app/(tabs)/new-screen.tsx
# Screen automatically available at /new-screenimport { Platform } from 'react-native';
// Conditional code
if (Platform.OS === 'web') {
// Web-only code (PWA)
} else if (Platform.OS === 'android') {
// Android-only code
}
// Platform-specific values
const apiUrl = Platform.select({
web: 'http://localhost:8080',
android: 'http://10.0.2.2:8080',
});import { View, Text } from 'react-native';
export default function MyComponent() {
return (
<View className="p-4 bg-white rounded-lg">
<Text className="text-lg font-bold text-primary-500">
Hello World
</Text>
</View>
);
}# Build static web files
npm run build:web
# Output: dist/ folderTest locally:
npx serve dist
# Visit http://localhost:3000Prerequisites:
- Create Expo account at https://expo.dev
- Install EAS CLI:
npm install -g eas-cli - Login:
eas login
Build APK:
# Configure (first time only)
eas build:configure
# Build production APK
npm run build:android
# Or directly:
eas build --platform android --profile productionBuild process:
- EAS uploads your code to cloud
- Builds APK in ~10-15 minutes
- Provides download link
Download APK:
# Get build status
eas build:list
# Download APK
# Visit URL from build:list or check https://expo.dev/accounts/[username]/projects/ai-assistant/buildsEdit eas.json:
{
"build": {
"preview": {
"android": {
"buildType": "apk"
}
},
"production": {
"android": {
"buildType": "apk"
}
}
}
}Quick Start:
# 1. Configure environment
cp .env.example .env.production
# Edit .env.production with your backend URL
# 2. Configure Firebase project
# Edit .firebaserc with your Firebase project ID
# 3. Deploy (automated)
npm run deploy:webFull deployment guide: See DEPLOYMENT.md for:
- Complete setup instructions
- CI/CD with GitHub Actions
- Environment configuration
- Custom domain setup
- Lighthouse audit
- Troubleshooting
Result: PWA available at https://your-project.web.app
Option 1: Direct Download (Recommended for now)
- Build APK:
npm run build:android - Download from EAS Build dashboard
- Host on website (e.g., hectorsanchez.work/apps/ai-assistant.apk)
- Share download link
Option 2: Google Play Store (Future)
Can use same APK for Play Store with minor config changes.
Create .env (not tracked by git):
# Backend API URL
EXPO_PUBLIC_API_URL=https://ai-assistant-backend-xyz.run.app
# Feature flags
EXPO_PUBLIC_ENABLE_MCP=trueAccess in code:
import Constants from 'expo-constants';
const apiUrl = Constants.expoConfig?.extra?.apiUrl;Edit app.json:
{
"expo": {
"name": "AI Assistant",
"slug": "ai-assistant",
"version": "1.0.0",
"android": {
"package": "com.hectorsanchez.aiassistant"
},
"extra": {
"apiUrl": "http://localhost:8080"
}
}
}Edit tailwind.config.js:
module.exports = {
theme: {
extend: {
colors: {
primary: {
500: '#0284c7', // Brand color
},
},
},
},
};Error: "Backend Connection Failed" alert
Solution:
- Verify backend is running:
curl http://localhost:8080/health - Check
API_BASE_URLinlib/constants.ts - For Android emulator, use
10.0.2.2instead oflocalhost - Check CORS configuration in backend
Error: Peer dependency warnings during npm install
Solution:
npx expo install --fixError: Stale imports or old code running
Solution:
npx expo start -c
# Or: npm start -- --clearError: Tailwind classes not rendering
Solution:
- Verify
babel.config.jsincludes NativeWind preset - Restart Metro bundler:
npm start -- --clear - Check
tailwind.config.jscontent paths
Error: API Error 403: {"success":false,"error":"Invalid CSRF token"}
Solution: The app implements CSRF protection for state-changing requests (POST/PUT/DELETE). The CSRF token is automatically extracted from cookies set by the backend.
-
Verify backend sets CSRF cookie:
- Open DevTools → Application → Cookies
- Look for:
csrf_token,XSRF-TOKEN, or_csrf
-
Check cookie attributes:
- Must have
HttpOnly: false(so JavaScript can read it) - Must have correct
DomainandPath
- Must have
-
Verify CORS configuration:
- Backend must allow credentials:
Access-Control-Allow-Credentials: true - Frontend origin must be in
Access-Control-Allow-Origin
- Backend must allow credentials:
Implementation details: See lib/csrf.ts and lib/api-client.ts
Error: No install button appears in browser
Solution:
- Verify HTTPS (PWA requires secure context)
- Check manifest file is served:
/manifest.webmanifest - Check service worker registered: DevTools → Application → Service Workers
- Verify icons exist:
/icon-192.png,/icon-512.png - Try clearing cache and reload
Error: EAS build fails
Solution:
- Check build logs:
eas build:list - View detailed log: Click build ID on expo.dev
- Common issues:
- Invalid
app.jsonconfiguration - Missing Android package name
- Invalid version format
- Invalid
Error: "No Android devices found"
Solution:
- Start Android Studio
- Open AVD Manager
- Create/start an emulator
- Run
npm run androidagain
-
Configure environment:
# Update .env.production with your backend URL EXPO_PUBLIC_API_URL=https://your-backend.run.app -
Build the PWA:
npm run build:web:production
-
Deploy to Firebase:
firebase deploy --only hosting # Or use the deployment script: ./scripts/deploy-pwa.sh -
Verify PWA installation:
- Open deployed URL in Chrome/Edge
- Look for install icon in address bar
- Click to install as app
The repository includes .github/workflows/deploy-pwa.yml and cloudbuild.yaml for automated deployments on push to main branch.
{
"start": "expo start",
"web": "expo start --web",
"android": "expo start --android",
"build:web": "expo export:web",
"build:web:production": "expo export --platform web",
"build:android": "eas build --platform android --profile production",
"deploy:web": "./scripts/deploy-pwa.sh",
"type-check": "tsc --noEmit",
"lint": "eslint .",
"test": "jest"
}Web (PWA):
- Run
npm run web - Test in Chrome, Firefox, Safari
- Test responsive design (mobile view)
- Test offline mode (after PWA install)
Android:
- Run
npm run android - Test on emulator and real device
- Test different screen sizes
- Test Android-specific features
# Run tests (when implemented)
npm test- Fork the repository
- Create feature branch:
git checkout -b feature/your-feature - Make changes and test on both web and Android
- Commit changes:
git commit -m "feat: add your feature" - Push to branch:
git push origin feature/your-feature - Create Pull Request
This project is licensed under the ISC License.
- Backend: https://github.com/sdhector/ai-agent-backend (Express.js API)
For issues, questions, or contributions:
- GitHub Issues: https://github.com/sdhector/ai-agent-frontend/issues
- Migration Guide: See
/react-native-migration-guide/in original repository
Current Status: Ignite Migration Complete - PWA Working, Android Build Ready
Next Steps: Build Android APK using WSL environment (see LLM_BUILD_ANDROID_APK.md)
Last Updated: November 25, 2025