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:
- Encode locally — Yoro codec runs on-device, no network needed
- Cache codes — store encoded locations in local SQLite
- 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.