Mobile Client
Mobile Client
Section titled “Mobile Client”The Bifrost Mobile Client is a cross-platform application built with React Native and Expo, providing VPN management on iOS and Android devices.
Features
Section titled “Features”- Home Screen: VPN connection status and quick toggle
- Servers Screen: Server selection with latency indicators
- Stats Screen: Real-time traffic statistics and connection details
- Settings Screen: Configuration management and preferences
Installation
Section titled “Installation”App Stores
Section titled “App Stores”- iOS: App Store (coming soon)
- Android: Google Play (coming soon)
Building from Source
Section titled “Building from Source”Prerequisites
Section titled “Prerequisites”- Node.js 18+
- npm or yarn
- Expo CLI
- For iOS: Xcode 14+ (macOS only)
- For Android: Android Studio with SDK
# Clone repositorygit clone https://github.com/rennerdo30/bifrost-proxy.gitcd bifrost-proxy/mobile
# Install dependenciesnpm install
# Start development servernpx expo startRunning on Device/Simulator
Section titled “Running on Device/Simulator”# iOS Simulator (macOS only)npx expo run:ios
# Android Emulatornpx expo run:android
# On physical devicenpx expo start --tunnel# Then scan QR code with Expo Go appBuilding for Production
Section titled “Building for Production”Using EAS Build (recommended):
# Install EAS CLInpm install -g eas-cli
# Login to Expo accounteas login
# Build for iOSeas build --platform ios
# Build for Androideas build --platform android
# Build for botheas build --platform allScreens
Section titled “Screens”Home Screen
Section titled “Home Screen”The main dashboard showing connection status:
┌─────────────────────────────────────┐│ Bifrost VPN │├─────────────────────────────────────┤│ ││ ┌───────────────┐ ││ │ │ ││ │ 🔒 │ ││ │ Connected │ ││ │ │ ││ └───────────────┘ ││ ││ [ Disconnect ] ││ ││ ┌─────────────┐ ┌─────────────┐ ││ │ ↑ Sent │ │ ↓ Received │ ││ │ 1.2 GB │ │ 3.4 GB │ ││ └─────────────┘ └─────────────┘ ││ ││ Server: us-west.example.com ││ Connected: 2h 34m ││ │├─────────────────────────────────────┤│ 🏠 Home │ 📡 Servers │ 📊 Stats │ ⚙️ │└─────────────────────────────────────┘Servers Screen
Section titled “Servers Screen”Server selection with status indicators:
┌─────────────────────────────────────┐│ Available Servers │├─────────────────────────────────────┤│ ││ ┌─────────────────────────────────┐││ │ 🟢 US West ✓ 45ms │││ │ us-west.example.com │││ │ HTTP │││ └─────────────────────────────────┘││ ││ ┌─────────────────────────────────┐││ │ 🟢 Europe 120ms │││ │ eu.example.com │││ │ HTTP │││ └─────────────────────────────────┘││ ││ ┌─────────────────────────────────┐││ │ 🟡 Asia Pacific 200ms │││ │ asia.example.com │││ │ SOCKS5 │││ └─────────────────────────────────┘││ ││ ┌─────────────────────────────────┐││ │ 🔴 Development offline │││ │ dev.example.com │││ │ HTTP │││ └─────────────────────────────────┘││ │├─────────────────────────────────────┤│ 🏠 Home │ 📡 Servers │ 📊 Stats │ ⚙️ │└─────────────────────────────────────┘Status indicators:
- 🟢 Online - Server available
- 🟡 Busy - High load
- 🔴 Offline - Server unavailable
Stats Screen
Section titled “Stats Screen”Detailed connection statistics:
┌─────────────────────────────────────┐│ Connection Stats │├─────────────────────────────────────┤│ ││ ┌─────────────┐ ┌─────────────┐ ││ │ ↑ Sent │ │ ↓ Received │ ││ │ 1.2 GB │ │ 3.4 GB │ ││ └─────────────┘ └─────────────┘ ││ ││ Current Session ││ ───────────────────────────────── ││ Duration 2h 34m ││ Total Data 4.6 GB ││ Status Connected ││ ││ Connection Details ││ ───────────────────────────────── ││ Protocol WireGuard ││ Encryption ChaCha20-Poly1305 ││ Port 51820 ││ MTU 1420 ││ ││ Network ││ ───────────────────────────────── ││ Local IP 10.0.0.2 ││ Gateway 10.0.0.1 ││ DNS 1.1.1.1, 8.8.8.8 ││ Interface bifrost0 ││ │├─────────────────────────────────────┤│ 🏠 Home │ 📡 Servers │ 📊 Stats │ ⚙️ │└─────────────────────────────────────┘Settings Screen
Section titled “Settings Screen”Configuration and preferences:
┌─────────────────────────────────────┐│ Settings │├─────────────────────────────────────┤│ ││ Connection ││ ───────────────────────────────── ││ Auto-connect [ 🔘 ] ││ Connect on app launch ││ ││ Kill Switch [🔘 ] ││ Block traffic if VPN disconnects ││ ││ Split Tunneling [ 🔘 ] ││ Exclude certain apps ││ [Configure →] ││ ││ Server ││ ───────────────────────────────── ││ ┌─────────────────────────────────┐││ │ proxy.example.com:7080 [Save] │││ └─────────────────────────────────┘││ ││ Notifications ││ ───────────────────────────────── ││ Connection Alerts [🔘 ] ││ Notify on connect/disconnect ││ ││ Data & Privacy ││ ───────────────────────────────── ││ [ Clear Cached Data ] ││ ││ About ││ ───────────────────────────────── ││ Version 1.0.0 ││ Server Status Connected ││ │├─────────────────────────────────────┤│ 🏠 Home │ 📡 Servers │ 📊 Stats │ ⚙️ │└─────────────────────────────────────┘Configuration
Section titled “Configuration”The mobile client connects to a Bifrost client running on your network. Configure the server address in Settings.
Connecting to Client
Section titled “Connecting to Client”- Start the Bifrost client on your computer/server
- Note the API address (default:
http://192.168.x.x:7383) - Enter this address in the mobile app Settings
API Configuration
Section titled “API Configuration”The mobile app uses these API endpoints:
| Endpoint | Description |
|---|---|
GET /api/v1/status | Client status |
GET /api/v1/vpn/status | VPN connection status |
POST /api/v1/vpn/enable | Enable VPN |
POST /api/v1/vpn/disable | Disable VPN |
GET /api/v1/servers | Available servers |
POST /api/v1/servers/{id}/select | Select server |
GET /api/v1/config | Get configuration |
PUT /api/v1/config | Update configuration |
Development
Section titled “Development”Project Structure
Section titled “Project Structure”mobile/├── src/│ ├── components/ # Reusable UI components│ ├── screens/ # Screen components│ │ ├── HomeScreen.tsx│ │ ├── ServersScreen.tsx│ │ ├── StatsScreen.tsx│ │ └── SettingsScreen.tsx│ ├── services/ # API and utilities│ │ └── api.ts│ └── App.tsx # Main app component├── app.json # Expo configuration├── package.json└── tsconfig.jsonTechnology Stack
Section titled “Technology Stack”- React Native: Cross-platform UI framework
- Expo: Development and build tooling
- React Query: Data fetching and caching
- React Navigation: Screen navigation
Adding a New Screen
Section titled “Adding a New Screen”- Create screen component in
src/screens/ - Add to navigation in
App.tsx - Add tab bar icon if needed
API Integration
Section titled “API Integration”The app uses React Query for data fetching:
import { useQuery, useMutation } from '@tanstack/react-query'import { api } from '../services/api'
function MyScreen() { const { data, isLoading, error } = useQuery({ queryKey: ['vpn-status'], queryFn: api.getVPNStatus, refetchInterval: 3000, })
const mutation = useMutation({ mutationFn: api.enableVPN, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['vpn-status'] }) }, })
// ...}Accessibility
Section titled “Accessibility”The Bifrost Mobile Client is designed with accessibility in mind, supporting both VoiceOver (iOS) and TalkBack (Android) screen readers.
Supported Accessibility Features
Section titled “Supported Accessibility Features”| Feature | Support |
|---|---|
| Screen Reader | Full support |
| Accessibility Labels | All interactive elements |
| Accessibility Roles | Semantic roles for buttons, tabs, switches |
| Accessibility States | Disabled, selected, checked states |
| Accessibility Hints | Context-aware action hints |
VoiceOver Testing (iOS)
Section titled “VoiceOver Testing (iOS)”How to Test
Section titled “How to Test”- Enable VoiceOver: Settings > Accessibility > VoiceOver
- Navigate using swipe gestures
- Double-tap to activate
- Use two-finger scroll for lists
Expected Behavior
Section titled “Expected Behavior”Home Screen:
- Connect/Disconnect button announces: “Connect to VPN, button” or “Disconnect from VPN, button”
- Status text announces: “Connection status: Protected” or similar
- Error alerts are announced immediately with role “alert”
- Upload/Download cards announce: “Upload: 1.2 GB” and “Download: 3.4 GB”
Servers Screen:
- Server items announce full context: “Server Name, address, protocol, status, selected/not selected”
- Offline servers announce disabled state
- Pull-to-refresh announces “Pull to refresh server list”
Stats Screen:
- All stat rows announce label and value pairs: “Duration: 2h 34m”
- StatusCard components announce: “Total Sent: 1.2 GB”, “Total Received: 3.4 GB”
Settings Screen:
- Switch controls announce their label and current state
- Configure button announces: “Configure split tunneling, button”
- Text input announces: “Server address, Enter the server address in host:port format”
Tab Navigation:
- Tab icons announce: “Home tab, selected” or “Settings tab”
- Uses proper tab role with selected state
TalkBack Testing (Android)
Section titled “TalkBack Testing (Android)”How to Test
Section titled “How to Test”- Enable TalkBack: Settings > Accessibility > TalkBack
- Navigate by swiping left/right
- Double-tap to activate
- Use two-finger scroll for content
Expected Behavior
Section titled “Expected Behavior”All behaviors match VoiceOver testing above with Android-specific variations:
importantForAccessibility="no"hides decorative elementsimportantForAccessibility="no-hide-descendants"groups child elements- Swipe gestures map to Android TalkBack conventions
- Focus indicators appear on currently selected element
Accessibility Implementation Details
Section titled “Accessibility Implementation Details”The following accessibility props are used throughout the app:
// Button example<TouchableOpacity accessibilityRole="button" accessibilityLabel="Connect to VPN" accessibilityHint="Double tap to establish VPN connection" accessibilityState={{ disabled: isLoading }}>
// Switch example<Switch accessibilityLabel="Auto-connect toggle" accessibilityHint="When enabled, the app will connect automatically on launch" accessibilityState={{ checked: isEnabled }}/>
// Grouped content example<View accessible={true} accessibilityRole="summary" accessibilityLabel={`${title}: ${value}`}> <Text importantForAccessibility="no">{title}</Text> <Text importantForAccessibility="no">{value}</Text></View>Known Accessibility Considerations
Section titled “Known Accessibility Considerations”- Emoji Icons: Tab bar uses emoji icons which are hidden from screen readers; proper labels are provided instead
- Pull-to-Refresh: Custom accessibility labels describe the refresh action
- Dynamic Content: Status updates may not be immediately announced; users should navigate to the status area to hear updates
- Error States: Error messages use the
alertrole for immediate screen reader announcement
Troubleshooting
Section titled “Troubleshooting”Cannot Connect to Client
Section titled “Cannot Connect to Client”- Verify client is running and API is enabled
- Check network connectivity (same network)
- Ensure correct IP address and port
- Check firewall settings on client machine
App Crashes on Start
Section titled “App Crashes on Start”- Clear app data and reinstall
- Check for conflicting VPN apps
- Update to latest version
High Battery Usage
Section titled “High Battery Usage”- Increase refetch intervals in settings
- Disable notifications if not needed
- Disconnect when not in use
Stats Not Updating
Section titled “Stats Not Updating”- Check network connection
- Verify client is running
- Pull down to refresh manually