Courier Service Mobile App Development
Courier accepted an order and left — the app crashed in background-killed on Android Xiaomi with MIUI. FusedLocationProvider stopped providing coordinates, the track broke, the dispatcher can't see the vehicle. This isn't a hypothetical scenario — it's a standard problem for courier apps on aggressive launchers (MIUI, OneUI, EMUI) where the foreground service gets killed by the battery optimizer.
Problem: Geotacking on Android
On Android, continuous geolocation requires a Foreground Service with explicit status bar notification. Without it, on Xiaomi/Huawei/OPPO, the app will die within 5–10 minutes in background regardless of WakeLock. And even a foreground service isn't a cure-all: MIUI adds battery restrictions even on running services if the user hasn't allowed auto-launch manually.
Right approach: on first launch show Intent to the system "Auto-launch" screen (for MIUI — com.miui.securitycenter, for Huawei — com.huawei.systemmanager). It's not always pretty, but it's the only way to guarantee tracking. Plus — batch coordinate sending: accumulate points in memory, send every 10–15 seconds in one request instead of 15 separate ones.
On iOS there are fewer problems: CLLocationManager with allowsBackgroundLocationUpdates = true and pausesLocationUpdatesAutomatically = false works reliably. But significant-change location updates aren't suitable for couriers — they only trigger on cell change (~500 m accuracy), which isn't good for real-time map display.
Two-App Architecture
A courier service is almost always two separate apps: one for the courier and one for the customer. Sometimes a third is added — dispatcher web interface. But the mobile part can be in one project with different flavors/schemes:
-
Android Flavors:
courierApp/clientApp— differentapplicationId, icons, permissions - iOS Targets: two targets in one Xcode project, shared code via SPM package
This allows reusing business logic (network layer, data models, geolocation module) between the two apps without code duplication.
Order Assignment and Routing
Order distribution logic lives on the server. The mobile client only receives assignment via push (FCM/APNs with priority: high) and confirms acceptance. Important: FCM high priority on Android guarantees delivery even in Doze mode, but only if the app has RECEIVE_BOOT_COMPLETED and FirebaseMessagingService properly configured.
Route to recipient built via Google Maps Directions API or OSRM (if you need self-hosted without API fees). Don't implement turn-by-turn navigation in the app — open Google Maps / Yandex Navigator via deep link, passing the delivery point coordinates.
ETA and Tracking for Customer
Customer sees the courier on the map — this is WebSocket or Server-Sent Events from server to client app. Coordinates update every 5–10 seconds. On the map use Marker with animation to make the point move smoothly not jump — ValueAnimator (Android) or CABasicAnimation (iOS).
ETA calculated on the server via Google Maps Distance Matrix API or HERE Routing API and sent to client. Don't compute ETA on the device — it doesn't have current traffic data.
Delivery Confirmation
Three most common confirmation options:
- Package/door photo —
CameraX(Android) orAVFoundation(iOS) + upload to S3/GCS - PIN-code that the recipient knows — simple TOTP or static code from the order
- On-screen signature —
Canvas/UIBezierPath, save as SVG or PNG
Signature code with strokeWidth depending on finger movement speed — looks significantly more natural than constant-width lines.
Development Stages and Timeline
Minimum viable product — two apps (courier + customer) with geotacking, order assignment, and delivery confirmation: 6–10 weeks with team of 2 developers + designer. Full platform with dispatch module, analytics, and integration with external OMS/WMS systems — 4–6 months. Cost calculated individually after requirements analysis.







