Building an Uber Clone with Flutter and Supabase
Building an Uber Clone with Flutter and Supabase
com/blog/flutter-uber-clone
1 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
App Overview
An actual Uber app has two apps, the consumer facing app and the
driver facing app. This article only covers the consumer facing app. The
app works by first choosing a destination, and then waiting for the
driver to come pick them up. Once they are picked up, they head to
the destination and the journey is complete once they arrive at the
destination. Throughout the lifecycle of the app, the driver’s position is
shared on screen in real-time.
The focus of the app is to showcase how to use Supabase realtime with
geographical data, so handling payments will not be covered in this
article.
2 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Prerequisites
1 Flutter installed
1 supabase_flutter: ^2.5.9
2 google_maps_flutter: ^2.7.0
3 geolocator: ^12.0.0
4 duration: ^3.0.13
5 intl: ^0.19.0
3 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
also draw and move icons on the map. geolocator is used to access
the GPS information. duration is used to parse duration value
returned from Google’s routes API, and intl is used to display
currencies nicely.
1 import 'package:supabase_flutter/supabase_flutter.dart';
2
3 void main() async {
4 await Supabase.initialize(
5 url: 'YOUR_SUPABASE_URL',
6 anonKey: 'YOUR_SUPABASE_ANON_KEY',
7 );
8 runApp(const MainApp());
9 }
10
11 final supabase = Supabase.instance.client;
We need to create two tables for this application. The drivers table
holds the vehicle information as well as the position. Notice that we
have a latitude and longitude generated column. These columns
are generated from the location column, and will be used to display
4 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Let’s also set row level security policies for the tables to secure our
database.
Lastly, we will create a few database functions and triggers. The first
function and trigger updates the driver status depending on the status
5 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
function and trigger updates the driver status depending on the status
of the ride. This ensures that the driver status is always in sync with the
status of the ride.
The second function is for the customer to find available drivers. This
function will be called from the Flutter app, which automatically find
available drivers within 3,000m radius and returns the driver ID and a
newly created ride ID if a driver was found.
6 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
39 limit 1;
40
41 -- return null if no available driver is found
42 if v_driver_id is null then
43 return;
44 end if;
45
46 insert into public.rides (driver_id, passenger_id, origin, de
47 values (v_driver_id, auth.uid(), origin, destination, fare)
48 returning id into v_ride_id;
49
50 return query
51 select v_driver_id as driver_id, v_ride_id
52 end $$ security definer;
Start by defining the models for this app. The AppState enum holds
the 5 different state that this app could take in the order that it
proceeds. The Ride and Driver class are simple data class for the
rides and drivers table we created earlier.
1 enum AppState {
2 choosingLocation,
3 confirmingFare,
4 waitingForPickup,
5 riding,
6 postRide,
7 }
8
9 enum RideStatus {
10 picking_up,
11 riding,
12 completed,
13 }
14
15 class Ride {
16 final String id;
17 final String driverId;
18 final String passengerId;
19 final int fare;
20 final RideStatus status;
21
22 Ride({
7 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
23 required this.id,
24 required this.driverId,
25 required this.passengerId,
26 required this.fare,
27 required this.status,
28 });
29
30 factory Ride.fromJson(Map<String, dynamic> json) {
31 return Ride(
32 id: json['id'],
33 driverId: json['driver_id'],
34 passengerId: json['passenger_id'],
35 fare: json['fare'],
36 status: RideStatus.values
37 .firstWhere((e) => e.toString().split('.').last
38 );
39 }
40 }
41
42 class Driver {
43 final String id;
44 final String model;
45 final String number;
46 final bool isAvailable;
47 final LatLng location;
48
49 Driver({
50 required this.id,
51 required this.model,
52 required this.number,
53 required this.isAvailable,
54 required this.location,
55 });
56
57 factory Driver.fromJson(Map<String, dynamic> json) {
58 return Driver(
59 id: json['id'],
60 model: json['model'],
61 number: json['number'],
62 isAvailable: json['is_available'],
63 location: LatLng(json['latitude'], json['longitude'
64 );
65 }
66 }
8 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
4 In-ride - The customer has got on the car, and they are headed to
the destination
For statuses 3, 4, and 5, the status update happens on the driver’s app,
which we don’t have. So you can directly modify the data from the
Supabase dashboard and update the status of the ride.
9 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
20
21 /// The current location of the user.
22 LatLng? _currentLocation;
23
24 final Set<Polyline> _polylines = {};
25 final Set<Marker> _markers = {};
26
27 /// Fare in cents
28 int? _fare;
29 StreamSubscription<dynamic>? _driverSubscription;
30 StreamSubscription<dynamic>? _rideSubscription;
31 Driver? _driver;
32
33 LatLng? _previousDriverLocation;
34 BitmapDescriptor? _pinIcon;
35 BitmapDescriptor? _carIcon;
36
37 @override
38 void initState() {
39 super.initState();
40 _signInIfNotSignedIn();
41 _checkLocationPermission();
42 _loadIcons();
43 }
44
45 @override
46 void dispose() {
47 _cancelSubscriptions();
48 super.dispose();
49 }
50
51 // TODO: Add missing methods
52
53 @override
54 Widget build(BuildContext context) {
55 return Scaffold(
56 appBar: AppBar(
57 title: Text(_getAppBarTitle()),
58 ),
59 body: Stack(
60 children: [
61 _currentLocation == null
62 ? const Center(child: CircularProgressIndicator
63 : GoogleMap(
64 initialCameraPosition: _initialCameraPosition,
65 onMapCreated: (GoogleMapController controller) {
66 _mapController = controller;
67 },
68 myLocationEnabled: true,
69 onCameraMove: _onCameraMove,
70 polylines: _polylines,
10 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
71 markers: _markers,
72 ),
73 if (_appState == AppState.choosingLocation)
74 Center(
75 child: Image.asset(
76 'assets/images/center-pin.png',
77 width: 96,
78 height: 96,
79 ),
80 ),
81 ],
82 ),
83 floatingActionButton: _appState == AppState.choosingLocation
84 ? FloatingActionButton.extended(
85 onPressed: _confirmLocation,
86 label: const Text('Confirm Destination'),
87 icon: const Icon(Icons.check),
88 )
89 : null,
90 floatingActionButtonLocation: FloatingActionButtonLocation
91 bottomSheet: _appState == AppState.confirmingFare
92 _appState == AppState.waitingForPickup
93 ? Container(
94 width: MediaQuery.of(context).size.width,
95 padding: const EdgeInsets.all(16)
96 .copyWith(bottom: 16 + MediaQuery.of(context).padding.
97 decoration: BoxDecoration(
98 color: Colors.white,
99 boxShadow: [
100 BoxShadow(
101 color: Colors.grey.withOpacity(0.5),
102 spreadRadius: 5,
103 blurRadius: 7,
104 offset: const Offset(0, 3),
105 ),
106 ],
107 ),
108 child: Column(
109 mainAxisSize: MainAxisSize.min,
110 children: [
111 if (_appState == AppState.confirmingFare) ...[
112 Text('Confirm Fare',
113 style: Theme.of(context).textTheme.titleLarge),
114 const SizedBox(height: 16),
115 Text(
116 'Estimated fare: ${NumberFormat
117 symbol:
118 '\$', // You can change this to your prefe
119 decimalDigits: 2,
120 ).format(_fare! / 100)}',
121 style: Theme of(context).textTheme.titleMedium),
11 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
The code above still has many missing methods, so do not worry if you
see many errors.
12 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
13 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Let’s also create the route edge functions. This function calls the
routes API from Google, which provides us the array of lines on the
map to take us from the customer’s current location to the destination.
1 # initialize Supabase
2 npx supabase init
3
4 # Create a new function named route
5 npx supabase functions new route
1 type Coordinates = {
2 latitude: number
3 longitude: number
4 }
5
6 Deno.serve(async (req) => {
14 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
15 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Now, once a route is displayed on the map and the customer agrees on
the fare, a driver needs to be found. We created a convenient method
for this earlier, so we can just call the method to find a driver and
create a new ride.
16 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
We will not make an app for the driver in this article, but let’s imagine
we had one. As the driver’s car moves, it could update it’s position on
the drivers table. In the previous step, we are listening to the
driver’s position being updated, and using those information, we could
move the car in the UI as well.
17 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
18 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Finally when the car arrives at the destination (when the driver updates
the status to completed ), a modal thanking the user for using the app
shows up. Implement _showCompletionModal to greet our valuable
customers.
Upon closing the modal, we reset the app’s state so that the user can
take another ride.
1 /// Shows a modal to indicate that the ride has been completed.
2 void _showCompletionModal() {
3 showDialog(
4 context: context,
5 barrierDismissible: false,
6 builder: (BuildContext context) {
7 return AlertDialog(
8 title: const Text('Ride Completed'),
9 content: const Text(
10 'Thank you for using our service! We hope you had a great r
11 actions: <Widget>[
12 TextButton(
13 child: const Text('Close'),
14 onPressed: () {
15 Navigator.of(context).pop();
16 _resetAppState();
17 },
18 ),
19 ],
20 );
21 },
22 );
23 }
24
25 void _resetAppState() {
26 setState(() {
27 _appState = AppState.choosingLocation;
28 _selectedDestination = null;
29 _driver = null;
30 _fare = null;
31 _polylines.clear();
19 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
31 _polylines.clear();
32 _markers.clear();
33 _previousDriverLocation = null;
34 });
35 _getCurrentLocation();
36 }
With the edge function deployed, you should be able to run the app at
this point. Note that you do need to manually tweak the driver and ride
data to test out all the features. I have created a simple script that
simulates the movement and status updates of a driver so that you can
enjoy the full Uber experience without actually manually updating
anything from the dashboard.
You can also find the complete code here to fully see everything put
together.
Conclusion
This tutorial has walked you through the process of building a basic
Uber clone using Flutter and Supabase. The application demonstrates
how easy it is to handle real-time geospatial data using Supabase and
Flutter.
Want to learn more about Maps and PostGIS? Make sure to follow
our Twitter and YouTube channels to not miss out! See you then!
20 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Last post
Next post
21 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
22 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
Product Resources
Database Support
Realtime Integrations
Storage Experts
GA Week DPA
SOC2
HIPAA
Developers Company
Documentation Blog
Contributing Careers
Privacy Policy
Privacy Settings
Support Policy
Humans.txt
Lawyers.txt
Security.txt
23 of 24 29/10/24, 18:29
Building an Uber Clone with Flutter and Supabase https://supabase.com/blog/flutter-uber-clone
© Supabase Inc
24 of 24 29/10/24, 18:29