Skip to main content

Overview

The location sharing feature allows passengers and drivers to share their real-time location during active trips. This enables:
  • Passengers to see driver’s approaching location
  • Drivers to navigate to passenger pickup location
  • Real-time trip tracking for safety

Location Sharing URL

The location sharing module is available at:
{baseUrl}/location_sharing
Configuration:
class AppConfig {
  static String get locationSharingUrl => '$baseUrl/location_sharing';
  
  static String buildShareUrl(String token) =>
      '${websiteUrl.trimRight()}/share/$token';
  
  static String buildDeepLink(String token) => 'viax://share/$token';
}

Generate Sharing Token

The exact endpoint for generating location sharing tokens depends on your backend implementation. Typically, this would be part of the trip creation or assignment process.

Sharing Token Structure

class LocationShareToken {
  final String token;           // Unique share token
  final int tripId;            // Associated trip ID
  final DateTime expiresAt;    // Token expiration
  final String shareUrl;       // Full sharing URL
  final String deepLink;       // Deep link for app
  
  LocationShareToken({
    required this.token,
    required this.tripId,
    required this.expiresAt,
  }) : shareUrl = AppConfig.buildShareUrl(token),
       deepLink = AppConfig.buildDeepLink(token);
}

Update Driver Location

POST /conductor/update_location.php
Update the driver’s real-time location during an active trip.

Request Body

conductor_id
integer
required
Driver ID
latitud
number
required
Current latitude
longitud
number
required
Current longitude

Request Example

Dart
Future<void> updateDriverLocation(
  int conductorId,
  double lat,
  double lng,
) async {
  await http.post(
    Uri.parse('https://76.13.114.194/conductor/update_location.php'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({
      'conductor_id': conductorId,
      'latitud': lat,
      'longitud': lng,
    }),
  );
}

// Usage with location tracking:
StreamSubscription<Position>? _locationSubscription;

void startLocationTracking(int conductorId) {
  _locationSubscription = Geolocator.getPositionStream(
    locationSettings: LocationSettings(
      accuracy: LocationAccuracy.high,
      distanceFilter: 10, // Update every 10 meters
    ),
  ).listen((position) {
    updateDriverLocation(
      conductorId,
      position.latitude,
      position.longitude,
    );
  });
}

void stopLocationTracking() {
  _locationSubscription?.cancel();
}

Location Tracking Best Practices

Update Frequency

Don’t update location too frequently to avoid:
  • Excessive battery drain
  • High network usage
  • Server overload
Recommended settings:
  • Distance filter: 10-20 meters
  • Time interval: 5-10 seconds
  • Accuracy: High (for active trips)
const LocationSettings optimalSettings = LocationSettings(
  accuracy: LocationAccuracy.high,
  distanceFilter: 15, // meters
  timeLimit: Duration(seconds: 5),
);

Battery Optimization

class AdaptiveLocationTracker {
  LocationSettings getSettings(TripStatus status) {
    switch (status) {
      case TripStatus.enCurso:
        // High accuracy during active trip
        return LocationSettings(
          accuracy: LocationAccuracy.high,
          distanceFilter: 10,
        );
      
      case TripStatus.aceptado:
      case TripStatus.enRuta:
        // Medium accuracy when approaching
        return LocationSettings(
          accuracy: LocationAccuracy.medium,
          distanceFilter: 20,
        );
      
      default:
        // Low accuracy when idle
        return LocationSettings(
          accuracy: LocationAccuracy.low,
          distanceFilter: 100,
        );
    }
  }
}

Real-Time Location Display

Passenger View (Track Driver)

class DriverTrackingMap extends StatefulWidget {
  final int tripId;
  
  @override
  _DriverTrackingMapState createState() => _DriverTrackingMapState();
}

class _DriverTrackingMapState extends State<DriverTrackingMap> {
  GoogleMapController? _mapController;
  Timer? _updateTimer;
  LatLng? _driverLocation;
  
  @override
  void initState() {
    super.initState();
    _startTracking();
  }
  
  void _startTracking() {
    _updateTimer = Timer.periodic(
      Duration(seconds: 5),
      (_) => _fetchDriverLocation(),
    );
  }
  
  Future<void> _fetchDriverLocation() async {
    // Fetch driver location from trip data
    final trip = await getTripById(widget.tripId);
    if (trip.conductorId != null) {
      // Update map with driver location
      setState(() {
        _driverLocation = LatLng(
          trip.driverLatitud ?? 0,
          trip.driverLongitud ?? 0,
        );
      });
      
      _mapController?.animateCamera(
        CameraUpdate.newLatLng(_driverLocation!),
      );
    }
  }
  
  @override
  void dispose() {
    _updateTimer?.cancel();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return GoogleMap(
      onMapCreated: (controller) => _mapController = controller,
      markers: {
        if (_driverLocation != null)
          Marker(
            markerId: MarkerId('driver'),
            position: _driverLocation!,
            icon: BitmapDescriptor.defaultMarkerWithHue(
              BitmapDescriptor.hueBlue,
            ),
          ),
      },
      // ... other map properties
    );
  }
}

Generate a shareable link for real-time location tracking:
Future<String> generateShareLink(int tripId) async {
  // Generate unique token for this trip
  final token = generateSecureToken();
  
  // Store token with trip association
  await storeShareToken(token, tripId);
  
  // Build public share URL
  final shareUrl = AppConfig.buildShareUrl(token);
  
  return shareUrl;
}

Future<void> shareLocationWithContact(String shareUrl) async {
  await Share.share(
    'Sigue mi viaje en tiempo real: $shareUrl',
    subject: 'Compartir ubicación - Viax',
  );
}

Privacy and Security

Privacy Considerations:
  • Location data should only be shared during active trips
  • Share tokens should expire after trip completion
  • Implement rate limiting to prevent abuse
  • Allow users to stop sharing at any time

Token Expiration

class ShareToken {
  final String token;
  final DateTime expiresAt;
  
  bool get isExpired => DateTime.now().isAfter(expiresAt);
  
  static ShareToken create(int tripId, {Duration validFor = const Duration(hours: 3)}) {
    return ShareToken(
      token: generateToken(),
      expiresAt: DateTime.now().add(validFor),
    );
  }
}

WebSocket Integration (Future)

For real-time updates with lower latency, consider implementing WebSocket support:
final channel = WebSocketChannel.connect(
  Uri.parse('wss://76.13.114.194/ws/location/$tripId'),
);

channel.stream.listen((data) {
  final location = jsonDecode(data);
  updateDriverMarker(location);
});

Error Handling

Future<void> safeUpdateLocation(
  int conductorId,
  double lat,
  double lng,
) async {
  try {
    await updateDriverLocation(conductorId, lat, lng);
  } catch (e) {
    // Log error but don't interrupt the app
    print('Failed to update location: $e');
    // Retry logic could be added here
  }
}

See Also

Build docs developers (and LLMs) love