Skip to content

React Native / Mobile

Yoro works in mobile applications. The codec is pure math — no server needed. This guide covers both approaches: a JavaScript port for client-side encoding, and API calls to a Yoro server.

Approach 1: JavaScript Codec (Offline)

The Yoro algorithm can be ported to any language. A JavaScript implementation is available for React Native, Flutter (via JS bridge), or any mobile web app.

React Native Example

// yoro.js — minimal Yoro codec for React Native
const ALPHABET = '23456789ABCDEFGHJKMNPQRSTVWXY';
const BASE = 29;

const DOMAINS = {
    'CI': { lat_min: 4.36, lat_max: 10.74, lon_min: -8.6, lon_max: -2.49 },
    'BF': { lat_min: 9.0, lat_max: 15.5, lon_min: -5.5, lon_max: 2.5 },
    // Add other domains as needed
};

function codeLength(p) {
    return Math.ceil(2 * p * Math.log(2) / Math.log(BASE));
}

function canonicalPrecision(k) {
    return Math.floor(k * Math.log(BASE) / (2 * Math.log(2)));
}

// ... (Hilbert curve functions — see repository for full source)

export function encode(lat, lon, precision = 12, domain = 'CI') {
    // Full implementation in the repository
}

export function decode(code) {
    // Full implementation in the repository
}

Usage in a React Native Screen

import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import MapView, { Marker, Polygon } from 'react-native-maps';
import { encode, decode } from './yoro';

export default function YoroMapScreen() {
    const [code, setCode] = useState(null);
    const [cell, setCell] = useState(null);

    const handleMapPress = (e) => {
        const { latitude, longitude } = e.nativeEvent.coordinate;
        const yoroCode = encode(latitude, longitude, 12, 'CI');
        const decoded = decode(yoroCode);

        setCode(yoroCode);
        setCell(decoded.bounds);
    };

    return (
        <View style={styles.container}>
            <MapView
                style={styles.map}
                initialRegion={{
                    latitude: 7.5, longitude: -5.5,
                    latitudeDelta: 5, longitudeDelta: 5,
                }}
                onPress={handleMapPress}
            >
                {cell && (
                    <Polygon
                        coordinates={[
                            { latitude: cell.lat_min, longitude: cell.lon_min },
                            { latitude: cell.lat_min, longitude: cell.lon_max },
                            { latitude: cell.lat_max, longitude: cell.lon_max },
                            { latitude: cell.lat_max, longitude: cell.lon_min },
                        ]}
                        strokeColor="#e65100"
                        strokeWidth={2}
                        fillColor="rgba(230, 81, 0, 0.1)"
                    />
                )}
            </MapView>

            {code && (
                <View style={styles.codePanel}>
                    <Text style={styles.codeText}>{code}</Text>
                </View>
            )}
        </View>
    );
}

const styles = StyleSheet.create({
    container: { flex: 1 },
    map: { flex: 1 },
    codePanel: {
        position: 'absolute', bottom: 40,
        alignSelf: 'center',
        backgroundColor: 'white',
        padding: 16, borderRadius: 12,
        shadowColor: '#000', shadowOpacity: 0.2,
        shadowRadius: 8, elevation: 5,
    },
    codeText: {
        fontSize: 28, fontWeight: 'bold',
        fontFamily: 'monospace', color: '#e65100',
    },
});

Approach 2: API Calls (Online)

If your mobile app has connectivity, call the Yoro API:

// Using the FastAPI server or Django backend
const YORO_API = 'https://your-server.com/api/yoro';

async function encodeLocation(lat, lon, domain = 'CI') {
    const resp = await fetch(
        `${YORO_API}/encode/?lat=${lat}&lon=${lon}&domain=${domain}`
    );
    return resp.json();
}

async function decodeCode(code) {
    const resp = await fetch(
        `${YORO_API}/decode/?code=${encodeURIComponent(code)}`
    );
    return resp.json();
}

Approach 3: Python Mobile (Kivy / BeeWare)

Since Yoro is pure Python with zero dependencies, it works directly with Kivy or BeeWare:

# Kivy example
from kivy.app import App
from kivy.uix.label import Label
import yoro

class YoroApp(App):
    def build(self):
        code = yoro.encode(5.345, -4.028, domain="CI")
        return Label(text=f"Yoro: {code}")

YoroApp().run()

Offline-First Pattern

The recommended pattern for field applications:

  1. Encode locally — Yoro codec runs on-device, no network needed
  2. Cache codes — store encoded locations in local SQLite
  3. Sync when online — push codes to the server in batches
// React Native: offline-first encoding
import AsyncStorage from '@react-native-async-storage/async-storage';
import { encode } from './yoro';

async function saveLocation(lat, lon, metadata) {
    const code = encode(lat, lon, 12, 'CI');  // Works offline!

    // Store locally
    const entry = { code, lat, lon, ...metadata, synced: false };
    const pending = JSON.parse(await AsyncStorage.getItem('pending') || '[]');
    pending.push(entry);
    await AsyncStorage.setItem('pending', JSON.stringify(pending));

    return code;
}

async function syncPending(apiUrl) {
    const pending = JSON.parse(await AsyncStorage.getItem('pending') || '[]');
    const unsynced = pending.filter(e => !e.synced);

    if (unsynced.length === 0) return;

    const resp = await fetch(`${apiUrl}/sync/push`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ entries: unsynced }),
    });

    if (resp.ok) {
        const synced = pending.map(e => ({ ...e, synced: true }));
        await AsyncStorage.setItem('pending', JSON.stringify(synced));
    }
}

Key advantage: offline encoding

Unlike services like what3words or Google Plus Codes that require an API call, Yoro encoding is a pure mathematical bijection. It produces the same code anywhere, anytime, with zero connectivity. This is critical for field agents in rural West Africa.