sg-delivery-partner/mobile_delivery_app_integration.md

3.9 KiB

Mobile App Integration Guide (Delivery Partner)

This developer guide details how to implement the real-time delivery dispatch flow in the Delivery Partner mobile application (e.g. React Native, Flutter, or Native iOS/Android).


Step 1: Establish Socket Connection (on Login / Going Online)

Initialize the socket connection and pass the JWT token in the handshake authentication options.

import { io } from "socket.io-client";

// Replace with your backend server URL
const socket = io("http://YOUR_BACKEND_IP:8000", {
  auth: {
    token: DRIVER_JWT_TOKEN // Pass the verified driver token here
  }
});

socket.on("connect", () => {
  console.log("Connected to dispatch server!");
});

Step 2: Listen for Incoming Offers (delivery_offer)

When the socket receives the delivery_offer event, display a modal or popup banner in your UI with the order details and Accept/Reject buttons.

socket.on("delivery_offer", (offer) => {
  console.log("New offer received:", offer);
  
  // Example UI action: Open the screen showing details
  showNewOfferModal({
    deliveryId: offer.deliveryId,
    orderId: offer.orderId,
    pickupAddress: offer.pickupAddress.label,
    dropAddress: offer.dropAddress.label,
    amount: offer.totalAmount,
    distance: offer.distanceKm
  });
});

Step 3: Respond to the Offer (Accept / Reject)

When the driver clicks Accept or Reject, hit the existing REST endpoint POST /delivery-partners/deliveries/{id}/respond.

async function respondToOffer(deliveryId, isAccepted) {
  const action = isAccepted ? "ACCEPT" : "REJECT";
  
  try {
    const response = await fetch(`http://YOUR_BACKEND_IP:8000/delivery-partners/deliveries/${deliveryId}/respond`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${DRIVER_JWT_TOKEN}`
      },
      body: JSON.stringify({ action })
    });
    
    const result = await response.json();
    if (response.ok) {
      console.log(`Successfully responded with action: ${action}`);
      // Close the modal or update app state
    } else {
      console.error(result.message);
    }
  } catch (error) {
    console.error("Network error: ", error);
  }
}

Step 4: Handle App Restarts / Notification Clicks

If the app was closed when the offer was dispatched or opened via a push notification:

  1. On app launch, call GET /delivery-partners/deliveries/pending-offer.
  2. If the offer is not null, load the accept/reject screen immediately.
async function checkPendingOffers() {
  const response = await fetch("http://YOUR_BACKEND_IP:8000/delivery-partners/deliveries/pending-offer", {
    headers: { 'Authorization': `Bearer ${DRIVER_JWT_TOKEN}` }
  });
  
  const data = await response.json();
  if (data.offer) {
    showNewOfferModal(data.offer); // Load the screen if there's a pending offer
  }
}

App State Lifecycle & Flow Handling

Depending on the operational state of the delivery partner's mobile application, the offer is received and presented to the rider in different ways:

App State Delivery Offer Trigger Mechanism What Happens
Foreground (Open & Active) WebSocket Listener The delivery_offer WebSocket event fires instantly (handled in Step 2). The modal or bottom sheet overlay pops up immediately in front of the rider.
Background (Open but Minimized) Push Notification (FCM / APNs) Mobile OSs sleep WebSocket connections when minimized. The backend dispatches a push notification. Tapping the notification brings the app to the foreground and calls checkPendingOffers() (handled in Step 4) to display the offer.
Closed / Killed (Not Running) Push Notification (FCM / APNs) The backend dispatches a push notification. Tapping it starts up the app, which then runs checkPendingOffers() on load to retrieve the pending offer.