Tutorials
Popular article

Mobile-First in Africa: React Native Offline-First for Keneya

Wapiki Team
January 15, 2026
8 min read
React NativeMobileOffline-FirstSQLiteAfrica

Mobile-First: A Necessity in Africa

In Africa, 85% of internet access happens via mobile. For Keneya, ignoring mobile would have meant ignoring 85% of our users.

But mobile in Africa has specific constraints:

  • Unstable 3G connection
  • Frequent network cuts
  • High data cost
  • Entry-level phones
  • Our Offline-First Approach

    The Keneya Mobile app works even without connection. Data synchronizes as soon as the network returns.

    Data Architecture

    typescript
    // db/schema.ts
    import { create } from 'react-native-sqlite-storage'
    
    const db = await create({
      name: 'keneya.db',
      location: 'default'
    })
    
    // Main tables
    await db.executeSql(`
      CREATE TABLE IF NOT EXISTS consultations (
        id TEXT PRIMARY KEY,
        patient_id TEXT,
        doctor_id TEXT,
        date TEXT,
        status TEXT,
        synced INTEGER DEFAULT 0
      )
    `)
    
    await db.executeSql(`
      CREATE TABLE IF NOT EXISTS medical_records (
        id TEXT PRIMARY KEY,
        patient_id TEXT,
        content TEXT,
        updated_at TEXT,
        synced INTEGER DEFAULT 0
      )
    `)

    Smart Synchronization

    typescript
    // sync/sync-manager.ts
    class SyncManager {
      async syncAll() {
        if (!await this.hasConnection()) {
          console.log('No connection, sync postponed')
          return
        }
    
        // 1. Upload unsynced local data
        await this.uploadPendingData()
    
        // 2. Download new server data
        await this.downloadServerData()
    
        // 3. Resolve conflicts
        await this.resolveConflicts()
      }
    
      async uploadPendingData() {
        const pending = await db.executeSql(
          'SELECT * FROM consultations WHERE synced = 0'
        )
    
        for (const record of pending) {
          try {
            await api.post('/consultations', record)
            await db.executeSql(
              'UPDATE consultations SET synced = 1 WHERE id = ?',
              [record.id]
            )
          } catch (error) {
            console.error('Sync failed:', error)
          }
        }
      }
    }

    App Size Optimization

    For entry-level phones, every MB counts:

    1. Hermes Instead of JSC

    json
    // android/app/build.gradle
    project.ext.react = [
      enableHermes: true
    ]

    Result: APK reduced from 35MB to 22MB

    2. Optimized Images

  • Use **WebP** instead of PNG/JPG
  • Lazy loading of images
  • Local cache for avatars
  • 3. Code Splitting

    typescript
    // Lazy loading screens
    const ConsultationScreen = lazy(() => import('./screens/Consultation'))
    const MedicalRecordScreen = lazy(() => import('./screens/MedicalRecord'))

    Data Consumption Management

    typescript
    // Sync only on WiFi (user option)
    const settings = await AsyncStorage.getItem('sync_settings')
    
    if (settings.wifiOnly && !isWifiConnected()) {
      showNotification('Sync waiting for WiFi')
      return
    }
    
    // Compress images before upload
    const compressed = await ImageCompressor.compress(photo, {
      quality: 0.7,
      maxWidth: 1024
    })

    Concrete Results

  • 📱 **APK size**: 22MB (vs 35MB initially)
  • ⚡ **Works offline**: 100% of basic features
  • 📊 **Sync success rate**: 98%
  • 💾 **Data savings**: -40% with compression
  • Conclusion

    In Africa, mobile-first is not a choice, it's an obligation. And offline-first is the only viable approach to guarantee a smooth user experience.


    *Developing a mobile app for Africa? [Let's talk strategy](/contact).*

    Did you like this article?

    Share it with your network!