expo-osm-sdk
Version:
OpenStreetMap component for React Native with Expo
1,004 lines (805 loc) β’ 28.6 kB
Markdown
# Expo OSM SDK
[](https://www.npmjs.com/package/expo-osm-sdk)
[](https://opensource.org/licenses/MIT)
[](https://www.typescriptlang.org/)
[](https://expo.dev/)
**Native OpenStreetMap SDK for Expo mobile development with zero configuration** πΊοΈ
## π **NEW: Complete Mobile Routing & Navigation!**
**v1.0.90** now includes **full native mobile routing with polylines and cross-platform support**! πΊοΈπ±
β
**FIXED (v1.0.90)**: All routing calculation issues resolved for drive, bike, transit, and walk modes!
```bash
# Latest stable with mobile routing
npm install expo-osm-sdk
```
β
**Native Mobile Polylines**: Real route visualization on iOS & Android
β
**Cross-Platform Routing**: Works seamlessly on mobile and web
β
**Multi-Transport Navigation**: Car π, Bike π΄, Walking πΆ, Transit π
β
**Turn-by-Turn Instructions**: Real navigation with step-by-step directions
β
**OSRM Integration**: Complete routing powered by OpenStreetMap
β
**Route Styling**: Custom colors, widths, and styling per transport mode
β
**Complete Search System**: Full geocoding with SearchBox UI component
## Installation
```bash
npm install expo-osm-sdk
# or
yarn add expo-osm-sdk
```
## πΊοΈ Mobile Routing & Navigation
**Version 1.0.88** introduces complete native mobile routing with cross-platform support:
### π± Mobile-First Routing Features
- **ποΈ Native Polylines**: Real route visualization using MapLibre native on iOS & Android
- **π¨ Custom Route Styling**: Colors, widths, and opacity for each transport mode
- **πΊοΈ Multi-Point Routes**: Navigate through multiple waypoints in sequence
- **π§ Turn-by-Turn Instructions**: Real navigation with step-by-step directions
- **π Distance Matrix**: Calculate route distance, duration, and estimated time
- **π£οΈ Route Profiles**: Support for driving, walking, and cycling routes
- **β‘ OSRM Integration**: Powered by OpenStreetMap's routing engine
- **π Auto-Fit Routes**: Automatically zoom to show complete routes
- **π Route Switching**: Seamless switching between transport modes
- **π Cross-Platform**: Works on iOS, Android, and Web with appropriate implementations
### π Mobile Navigation Examples
```tsx
import {
useOSRMRouting,
calculateRoute,
type Route,
type OSMViewRef
} from 'expo-osm-sdk';
// 1. Complete Mobile Navigation with Native Polylines
const routing = useOSRMRouting();
const mapRef = useRef<OSMViewRef>(null);
const startNavigation = async () => {
const from = { latitude: 40.7128, longitude: -74.0060 }; // NYC
const to = { latitude: 41.8781, longitude: -87.6298 }; // Chicago
// Calculate and display route with native polylines on mobile
const route = await routing.calculateAndDisplayRoute(
from, to, mapRef,
{
profile: 'driving',
routeStyle: {
color: '#007AFF', // Custom blue for driving
width: 5, // Route line width
opacity: 0.8 // Route transparency
}
}
);
if (route) {
console.log(`Route: ${routing.formatRouteDistance(route)} in ${routing.formatRouteDuration(route)}`);
console.log('Turn-by-turn:', route.steps.map(s => s.instruction));
// Auto-fit the route in view (works on both mobile and web)
await routing.fitRouteInView(route, mapRef, 50);
}
};
// 2. Multi-Transport Mode Navigation (like Google Maps)
const TRANSPORT_MODES = [
{ id: 'car', profile: 'driving', color: '#007AFF', icon: 'π' },
{ id: 'bike', profile: 'cycling', color: '#34C759', icon: 'π΄' },
{ id: 'walk', profile: 'walking', color: '#8E8E93', icon: 'πΆ' },
];
const calculateAllRoutes = async () => {
const from = { latitude: 51.5074, longitude: -0.1278 }; // London
const to = { latitude: 48.8566, longitude: 2.3522 }; // Paris
for (const mode of TRANSPORT_MODES) {
const route = await routing.calculateAndDisplayRoute(
from, to, mapRef,
{
profile: mode.profile,
routeStyle: { color: mode.color, width: 5 }
}
);
if (route) {
console.log(`${mode.icon} ${mode.id}: ${routing.formatRouteDistance(route)} in ${routing.formatRouteDuration(route)}`);
}
}
};
```
## Quick Start
### Installation
```bash
npm install expo-osm-sdk
```
### Configuration
Add the plugin to your `app.json`:
```json
{
"expo": {
"plugins": [
["expo-osm-sdk/plugin", {
"locationPermissionText": "This app uses location for map features"
}]
]
}
}
```
### Basic Usage
```tsx
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { OSMView } from 'expo-osm-sdk';
export default function App() {
return (
<View style={styles.container}>
<OSMView
style={styles.map}
initialCenter={{ latitude: 40.7128, longitude: -74.0060 }}
initialZoom={10}
onMapReady={() => console.log('Map ready!')}
/>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { flex: 1 },
});
```
### Build and Run
**β οΈ Important**: This SDK requires Expo development builds as it uses native code. It will **not** work in Expo Go.
```bash
# Install dependencies and build
npx expo install --fix
npx expo run:ios
# or
npx expo run:android
```
## π Search and Geocoding
### SearchBox Component
Add instant search to your map with the professional SearchBox component:
```tsx
import React, { useRef } from 'react';
import { View } from 'react-native';
import { OSMView, SearchBox } from 'expo-osm-sdk';
import type { OSMViewRef } from 'expo-osm-sdk';
export default function MapWithSearch() {
const mapRef = useRef<OSMViewRef>(null);
return (
<View style={{ flex: 1 }}>
<SearchBox
placeholder="Search for places, addresses..."
onLocationSelected={(location) => {
// Animate map to selected location
mapRef.current?.animateToLocation(
location.coordinate.latitude,
location.coordinate.longitude,
15
);
}}
onResultsChanged={(results) => {
console.log(`Found ${results.length} results`);
}}
maxResults={5}
autoComplete={true}
style={{ margin: 20, marginTop: 60 }}
/>
<OSMView
ref={mapRef}
style={{ flex: 1 }}
initialCenter={{ latitude: 40.7128, longitude: -74.0060 }}
initialZoom={13}
/>
</View>
);
}
```
### Search Functions
#### Quick Search (One-liner)
```tsx
import { quickSearch } from 'expo-osm-sdk';
const location = await quickSearch("Times Square");
if (location) {
console.log(location.displayName); // "Times Square, New York, NY, USA"
console.log(location.coordinate); // { latitude: 40.758, longitude: -73.985 }
}
```
#### Find Nearby Places
```tsx
import { searchNearby } from 'expo-osm-sdk';
// Find restaurants within 2km of a location
const restaurants = await searchNearby(
{ latitude: 40.7128, longitude: -74.0060 }, // NYC center
"restaurant",
2 // radius in km
);
console.log(`Found ${restaurants.length} restaurants`);
restaurants.forEach(restaurant => {
console.log(`${restaurant.displayName} - ${restaurant.distance}km away`);
});
```
#### Reverse Geocoding
```tsx
import { getAddressFromCoordinates } from 'expo-osm-sdk';
// Get address from coordinates (e.g., from map long press)
const address = await getAddressFromCoordinates({
latitude: 40.7589,
longitude: -73.9851
});
console.log(address); // "Broadway, New York, United States"
```
#### Smart Search (Handles Everything)
```tsx
import { smartSearch } from 'expo-osm-sdk';
// Works with coordinates
const results1 = await smartSearch("40.7128, -74.0060");
// Works with addresses
const results2 = await smartSearch("123 Main St, New York");
// Works with place names
const results3 = await smartSearch("Central Park");
// All return SearchLocation[] with .coordinate and .displayName
```
#### POI Discovery by Category
```tsx
import { searchPOI } from 'expo-osm-sdk';
// Find hospitals near a location
const hospitals = await searchPOI(
{ latitude: 40.7128, longitude: -74.0060 },
"hospital", // or "restaurant", "hotel", "gas", "shopping", etc.
5 // radius in km
);
```
### useNominatimSearch Hook
For custom search UI components:
```tsx
import React, { useState } from 'react';
import { TextInput, FlatList, Text, TouchableOpacity } from 'react-native';
import { useNominatimSearch } from 'expo-osm-sdk';
export default function CustomSearch() {
const [query, setQuery] = useState('');
const { search, isLoading, lastResults, error } = useNominatimSearch();
const handleSearch = async (text: string) => {
setQuery(text);
if (text.length > 2) {
await search(text);
}
};
return (
<>
<TextInput
value={query}
onChangeText={handleSearch}
placeholder="Search locations..."
/>
{isLoading && <Text>Searching...</Text>}
{error && <Text>Error: {error}</Text>}
<FlatList
data={lastResults}
keyExtractor={(item) => item.placeId}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => console.log(item)}>
<Text>{item.displayName}</Text>
</TouchableOpacity>
)}
/>
</>
);
}
```
## β¨ Features
### π **NEW: Complete Search System (v1.0.79)**
- β
**SearchBox Component** - Professional UI with autocomplete, debouncing, error handling
- β
**Location Search** - Find places, addresses, points of interest globally
- β
**Reverse Geocoding** - Get human-readable addresses from coordinates
- β
**POI Discovery** - Find nearby restaurants, hotels, hospitals by category
- β
**Smart Search** - Intelligent handling of coordinates, addresses, place names
- β
**Convenience Functions** - quickSearch, searchNearby, getAddressFromCoordinates
- β
**useNominatimSearch Hook** - React hook with comprehensive state management
- β
**Zero Setup** - No API keys required, uses OpenStreetMap Nominatim
### πΊοΈ **Core Map Features**
- β
**Vector Tile Support** - 40-60% better performance with OpenMapTiles vector rendering
- β
**Current Location** - Real-time GPS tracking with follow user mode
- β
**Fly To Animation** - Smooth camera transitions with animateToLocation()
- β
**Native Performance** - MapLibre GL Native rendering engine
- β
**No API Keys Required** - Uses OpenStreetMap data directly
- β
**Expo Compatible** - Works with Expo development builds
- β
**TypeScript Support** - Full TypeScript definitions included
- β
**Interactive Maps** - Native pan, zoom, and tap interactions
- β
**Custom Markers** - Add and customize map markers natively
- β
**Event Handling** - Respond to map and marker interactions
- β
**GPU Accelerated** - Hardware-accelerated rendering
- β
**Cross-Platform** - Native iOS and Android implementations
- β
**Battery Optimized** - Efficient native memory management
- β
**Web Fallback** - Graceful fallback for web builds
- β
**Production Ready** - Thoroughly tested with 125+ tests
## π― Platform Behavior Guide
Understanding how the SDK behaves across different platforms is crucial for development:
### π± **Development/Production Builds** (Recommended)
```bash
# Create development build
npx expo run:ios
npx expo run:android
# Or production build
eas build --platform ios
eas build --platform android
```
**Experience**:
- β
**Full Native Map**: Complete OpenStreetMap with MapLibre GL rendering
- β
**All Features**: Markers, zoom, pan, tap events, location services
- β
**Hardware Acceleration**: GPU-powered smooth performance
- β
**Production Ready**: Optimized for app store deployment
### π§ͺ **Expo Go** (Development Testing)
```bash
npx expo start
# Scan QR code with Expo Go app
```
**Experience**:
- β οΈ **Fallback UI**: Shows informative placeholder (not a real map)
- π‘ **Clear Messaging**: "This app requires a development build to display maps"
- π¨ **Professional Design**: Branded fallback with current coordinates
- π **Helpful Instructions**: Guides users to create development builds
**Why?** Expo Go cannot run custom native code. This is expected behavior for all native modules.
### π **Web Platform**
```bash
npx expo start --web
```
**Experience**:
- β
**Cross-Platform Routing**: OSRM routing calculations work on web
- β
**MapLibre GL JS Support**: Route visualization with web-based polylines
- β
**Professional Fallback**: Informative UI when MapLibre not available
- π± **Responsive Design**: Works on all browsers with appropriate fallbacks
### π **Development Workflow Recommendation**
1. **Quick Testing**: Use Expo Go for UI/layout testing (map shows placeholder)
2. **Map Testing**: Use development builds for full map functionality
3. **Production**: Deploy with EAS Build for app stores
### π¨ **Fallback UI Examples**
The SDK provides beautiful, informative fallbacks:
#### Expo Go Fallback:
```
π OpenStreetMap View
Development Build Required
This app requires a development build to display maps.
Expo Go does not support custom native modules.
Try running: npx expo run:ios or npx expo run:android
π Center: 40.7128, -74.0060
π Zoom: 13
```
#### Web Platform:
```
πΊοΈ Cross-Platform Routing
OSRM routing and search features:
β’ Route calculation across all platforms
β’ Web-compatible polyline display
β’ Professional fallback UI
β’ Responsive design for all browsers
```
## π Requirements
- **Expo SDK**: 49+ (recommended: 53+)
- **React Native**: 0.72+
- **iOS**: 13+
- **Android**: API 21+
- **Node.js**: 16+
- **Development Build**: Required (does not work in Expo Go)
## π Complete Setup Guide
### Step 1: Create Expo Project
```bash
# Create new Expo project
npx create-expo-app MyMapApp
cd MyMapApp
```
### Step 2: Install the SDK
```bash
npm install expo-osm-sdk
```
### Step 3: Configure App
Add the plugin to your `app.json`:
```json
{
"expo": {
"name": "MyMapApp",
"slug": "my-map-app",
"version": "1.0.0",
"plugins": [
["expo-osm-sdk/plugin", {
"locationPermissionText": "This app uses location for map features"
}]
]
}
}
```
### Step 4: Create Map Component
Replace your `App.tsx` with:
> π‘ **Want a complete example?** Check out our [comprehensive demo project](../demo-project/) with professional UI, multiple components, and best practices!
```tsx
import React, { useState } from 'react';
import { StyleSheet, View, Alert } from 'react-native';
import { OSMView, MarkerConfig, Coordinate } from 'expo-osm-sdk';
export default function App() {
const [markers, setMarkers] = useState<MarkerConfig[]>([
{
id: 'home',
coordinate: { latitude: 40.7128, longitude: -74.0060 },
title: 'New York City',
description: 'Welcome to NYC!'
}
]);
const handleMapPress = (coordinate: Coordinate) => {
const newMarker: MarkerConfig = {
id: `marker-${Date.now()}`,
coordinate,
title: 'New Marker',
description: `Added at ${coordinate.latitude.toFixed(4)}, ${coordinate.longitude.toFixed(4)}`
};
setMarkers([...markers, newMarker]);
};
const handleMarkerPress = (markerId: string) => {
const marker = markers.find(m => m.id === markerId);
if (marker) {
Alert.alert('Marker Info', `${marker.title}\n${marker.description}`);
}
};
return (
<View style={styles.container}>
<OSMView
style={styles.map}
initialCenter={{ latitude: 40.7128, longitude: -74.0060 }}
initialZoom={12}
markers={markers}
onMapReady={() => console.log('Map is ready!')}
onPress={handleMapPress}
onMarkerPress={handleMarkerPress}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
map: {
flex: 1,
},
});
```
### Step 5: Build and Run
```bash
# Install dependencies
npx expo install --fix
# Build for iOS
npx expo run:ios
# Build for Android
npx expo run:android
```
## π― New Features (v1.0.34+)
### πΊοΈ Vector Tiles (Better Performance)
By default, the SDK now uses OpenMapTiles vector tiles for 40-60% better performance:
```tsx
import { OSMView } from 'expo-osm-sdk';
// Vector tiles enabled by default (recommended)
<OSMView
style={styles.map}
initialCenter={{ latitude: 40.7128, longitude: -74.0060 }}
initialZoom={12}
// Vector tiles automatically used
/>
// Custom vector style
<OSMView
style={styles.map}
styleUrl="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
initialCenter={{ latitude: 40.7128, longitude: -74.0060 }}
initialZoom={12}
/>
// Switch back to raster tiles if needed
<OSMView
style={styles.map}
tileServerUrl="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
initialCenter={{ latitude: 40.7128, longitude: -74.0060 }}
initialZoom={12}
/>
```
### π Nominatim Search & Geocoding
Complete search functionality with autocomplete and reverse geocoding:
```tsx
import { SearchBox, useNominatimSearch, searchLocations, reverseGeocode } from 'expo-osm-sdk';
// Easy-to-use SearchBox component
function MapWithSearch() {
const handleLocationSelect = (location) => {
console.log('Selected:', location);
// Animate map to selected location
};
return (
<View style={styles.container}>
<SearchBox
placeholder="Search for places..."
onLocationSelect={handleLocationSelect}
style={styles.searchBox}
/>
<OSMView style={styles.map} />
</View>
);
}
// Advanced search hook
function AdvancedSearch() {
const {
query,
setQuery,
results,
isLoading,
error,
searchLocations: search,
clearResults
} = useNominatimSearch();
return (
<View>
<TextInput
value={query}
onChangeText={setQuery}
placeholder="Search locations..."
/>
{isLoading && <Text>Searching...</Text>}
{results.map(result => (
<TouchableOpacity key={result.place_id} onPress={() => search(result)}>
<Text>{result.display_name}</Text>
</TouchableOpacity>
))}
</View>
);
}
// Direct API usage
async function searchExample() {
// Search for locations
const results = await searchLocations('New York City');
console.log('Found:', results);
// Reverse geocoding
const address = await reverseGeocode(40.7128, -74.0060);
console.log('Address:', address);
}
```
### π Current Location & Navigation
Built-in location services and smooth animations:
```tsx
import { OSMView, OSMViewRef } from 'expo-osm-sdk';
function MapWithLocation() {
const mapRef = useRef<OSMViewRef>(null);
const goToCurrentLocation = async () => {
const location = await mapRef.current?.getCurrentLocation();
if (location) {
mapRef.current?.animateToLocation(location.latitude, location.longitude, 15);
}
};
return (
<View style={styles.container}>
<OSMView
ref={mapRef}
style={styles.map}
showUserLocation={true}
followUserLocation={false}
onUserLocationChange={(location) => {
console.log('User location:', location);
}}
/>
<Button title="Go to My Location" onPress={goToCurrentLocation} />
</View>
);
}
```
## π§ API Reference
### OSMView Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `style` | `ViewStyle` | `undefined` | Style for the map container |
| `initialCenter` | `Coordinate` | `{latitude: 0, longitude: 0}` | Initial center coordinate |
| `initialZoom` | `number` | `10` | Initial zoom level (1-18) |
| `styleUrl` | `string` | OpenMapTiles vector style | Vector tile style URL (new in v1.0.34) |
| `tileServerUrl` | `string` | `undefined` | Custom raster tile server URL |
| `showUserLocation` | `boolean` | `false` | Show user's current location |
| `followUserLocation` | `boolean` | `false` | Follow user location changes |
| `markers` | `MarkerConfig[]` | `[]` | Array of markers to display |
| `onMapReady` | `() => void` | `undefined` | Called when map is ready |
| `onRegionChange` | `(region: MapRegion) => void` | `undefined` | Called when map region changes |
| `onMarkerPress` | `(markerId: string) => void` | `undefined` | Called when marker is pressed |
| `onPress` | `(coordinate: Coordinate) => void` | `undefined` | Called when map is pressed |
| `onUserLocationChange` | `(location: Coordinate) => void` | `undefined` | Called when user location updates |
### TypeScript Types
```typescript
interface Coordinate {
latitude: number; // -90 to 90
longitude: number; // -180 to 180
}
interface MapRegion {
latitude: number;
longitude: number;
latitudeDelta: number;
longitudeDelta: number;
}
interface MarkerConfig {
id: string; // Unique identifier
coordinate: Coordinate; // Marker position
title?: string; // Marker title
description?: string; // Marker description
icon?: string; // Custom icon (future feature)
}
// New in v1.0.34: Search and Geocoding Types
interface NominatimSearchResult {
place_id: string;
display_name: string;
lat: string;
lon: string;
boundingbox: [string, string, string, string];
type: string;
importance: number;
}
interface SearchLocation {
id: string;
name: string;
coordinate: Coordinate;
address?: string;
distance?: number;
}
interface UseNominatimSearchReturn {
query: string;
setQuery: (query: string) => void;
results: SearchLocation[];
isLoading: boolean;
error: string | null;
searchLocations: (query: string) => Promise<void>;
clearResults: () => void;
}
interface SearchBoxProps {
placeholder?: string;
onLocationSelect: (location: SearchLocation) => void;
style?: ViewStyle;
maxResults?: number;
debounceMs?: number;
}
// Map Reference Interface
interface OSMViewRef {
animateToLocation: (latitude: number, longitude: number, zoom?: number) => void;
getCurrentLocation: () => Promise<Coordinate | null>;
zoomIn: () => void;
zoomOut: () => void;
setZoom: (level: number) => void;
}
```
## π― Advanced Examples
### Custom Tile Server
```tsx
<OSMView
style={styles.map}
tileServerUrl="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
initialCenter={{ latitude: 51.5074, longitude: -0.1278 }}
initialZoom={12}
/>
```
### Dynamic Marker Management
```tsx
const [markers, setMarkers] = useState<MarkerConfig[]>([]);
const addMarker = (coordinate: Coordinate) => {
const newMarker: MarkerConfig = {
id: `marker-${Date.now()}`,
coordinate,
title: 'New Marker',
description: 'Added by user'
};
setMarkers(prev => [...prev, newMarker]);
};
const removeMarker = (markerId: string) => {
setMarkers(prev => prev.filter(marker => marker.id !== markerId));
};
const clearMarkers = () => {
setMarkers([]);
};
```
### Region Change Handling
```tsx
const handleRegionChange = (region: MapRegion) => {
console.log('Map region changed:', region);
// Update state or perform actions based on region change
};
<OSMView
style={styles.map}
onRegionChange={handleRegionChange}
/>
```
## π Troubleshooting
### β οΈ **Important: Expected Behaviors (Not Bugs)**
Before troubleshooting, understand these are **normal** behaviors:
#### β
**Expo Go Shows Fallback UI**
- **Expected**: Fallback UI with "Development Build Required" message
- **Not a Bug**: Expo Go cannot run native modules
- **Solution**: Create development build with `npx expo run:ios` or `npx expo run:android`
#### β
**Web Shows Fallback UI**
- **Expected**: Fallback UI with web alternative suggestions
- **Not a Bug**: Native mobile SDKs don't run in browsers
- **Solution**: Use web-compatible map libraries for web platform
### Common Issues and Solutions
#### 1. "Package does not contain a valid config plugin"
**Solution**: Make sure you're using the correct plugin configuration:
```json
{
"expo": {
"plugins": [
["expo-osm-sdk/plugin", {
"locationPermissionText": "This app uses location for map features"
}]
]
}
}
```
#### 2. "Cannot use import statement outside a module"
**Solution**: This usually happens with incorrect package versions. Ensure you're using:
- Latest version of expo-osm-sdk
- Expo SDK 49+
- React Native 0.72+
#### 3. "OSMView is not defined" or Component Undefined
**Solutions**:
- Ensure you're using a development build (not Expo Go)
- Run `npx expo install --fix`
- Verify the plugin is configured in `app.json`
- Import correctly: `import { OSMView } from 'expo-osm-sdk';`
#### 4. Map Not Rendering
**Solutions**:
- Check that you're using a development build
- Verify the plugin is in your `app.json`
- Ensure you have proper location permissions
- Check console for error messages
#### 5. Build Errors
**Solutions**:
```bash
# Clean and rebuild
npx expo run:ios --clear
# or
npx expo run:android --clear
# If still having issues, try:
rm -rf node_modules package-lock.json
npm install
npx expo install --fix
```
### Development Tips
1. **Always Use Development Builds**: This SDK requires native code and won't work in Expo Go
2. **TypeScript**: The SDK includes full TypeScript definitions for better development experience
3. **Validation**: The SDK includes runtime validation in development mode
4. **Console Logging**: Check console for validation warnings and errors
5. **Physical Device Testing**: Always test on physical devices for best performance
## π± Platform Support
### iOS (Full Native Support)
- β
**iOS 13+** - iPhone and iPad
- β
**Native MapLibre GL** - Hardware-accelerated rendering
- β
**Development Builds** - Full map functionality
- β
**Production Ready** - App Store compatible
- β οΈ **Expo Go** - Shows fallback UI (expected behavior)
### Android (Full Native Support)
- β
**Android API 21+** - ARMv7 and ARM64 support
- β
**Native MapLibre GL** - Hardware-accelerated rendering
- β
**Development Builds** - Full map functionality
- β
**Production Ready** - Google Play compatible
- β οΈ **Expo Go** - Shows fallback UI (expected behavior)
### Web (Fallback Only)
- β
**Responsive Fallback** - Professional placeholder UI
- β
**Developer Guidance** - Suggests web-compatible alternatives
- β οΈ **No Native Map** - Use react-leaflet or similar for web
- π **Recommendation** - Build separate web experience
## π§ͺ Testing
The SDK includes comprehensive test coverage:
```bash
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run specific test suites
npm run test:unit
npm run test:integration
npm run test:performance
```
### Test Coverage (125+ Tests)
- β
**Unit Tests**: Component instantiation, prop validation, coordinate utilities
- β
**Integration Tests**: Component lifecycle, event handling, marker management
- β
**Performance Tests**: Large datasets, rapid updates, memory efficiency
- β
**Compatibility Tests**: Platform compatibility, device support
- β
**Accuracy Tests**: Coordinate calculations, distance measurements
## π Resources
- **npm Package**: [expo-osm-sdk](https://www.npmjs.com/package/expo-osm-sdk)
- **GitHub Repository**: [mapdevsaikat/expo-osm-sdk](https://github.com/mapdevsaikat/expo-osm-sdk)
- **π± Demo App**: See `demo-project/` directory - Complete example with modern UI
- **π§ͺ Basic Example**: See `example/` directory - Simple testing example
- **Issues**: [Report bugs or request features](https://github.com/mapdevsaikat/expo-osm-sdk/issues)
## π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## π License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## π Changelog
See [CHANGELOG.md](CHANGELOG.md) for a detailed history of changes.
**Made with β€οΈ by [Saikat Maiti](https://github.com/mapdevsaikat)**
*Experience native OpenStreetMap in your Expo app without complexity!*