In this article we will cover how to collect the value of the speed of a vehicle through GPS. We will use as a basis for this project the Flutter framework that has been widely used by several developers.
We will cover the following topics:
- Creating a Standard Project with Flutter
- Installing and configuring the “geolocator: ^8.2.0” plugin
- Save the speed data as the device moves.
Step 1. Creating a Standard Project with Flutter
flutter create -i objc -a java my_speed
Step 2. Install & Configure Geolocator Plugin
To save GPS device moves, we will use the “geolocator: ^8.2.0” flutter plugin available in the official package repository for Dart and Flutter applications.
The “geolocator: ^8.2.0” is a simple yet powerful tool to collect this data. To use this plugin, we need to install and configure some settings.
To simplify what was done in this project, I will bring here all the configurations made in a simpler way.
flutter pub add geolocator:8.1.1
or by editing your pubspec.yaml file:
dependencies:
geolocator: ^8.2.0
Import the plugin to your main.dart file:
import 'package:geolocator/geolocator.dart';
3. Save the speed data as the device moves
add new permission to plaform specific manifest, like Android or iOS. For android, edit the android/app/src/main/AndroidManifest.xml files. Add this permission:
also the gradle properties:
android.useAndroidX=true android.enableJetifier=true
for iOS platform, edit ios/Runner/Info.plist files and add:
NSLocationWhenInUseUsageDescription This app needs access to location when open. NSLocationAlwaysUsageDescription This app needs access to location when in the background. NSLocationTemporaryUsageDescriptionDictionary NSLocationTemporaryUsageDescriptionDictionary YourPurposeKey The example App requires temporary access to the device's precise location.
In your main.dart files, add geolocator variables:
class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override StatecreateState() => _MyHomePageState(); } class _MyHomePageState extends State { double? latitude = 0.0; double? longitude = 0.0; double? altitude = 0.0; double? speed = 0.0; DateTime? timestamp = DateTime.now(); //Resto do codigo }
Create the run Permission() method in the My HomePage class, this class will be responsible for checking if the application has permission to use the device's GPS.
runPermission() async { LocationPermission permission; permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied || permission == LocationPermission.whileInUse) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.deniedForever) { _showDialog(); } } }
At first it checks if it has the permission with the parameter ”Geolocator.checkPermission()” if it doesn't have it, or if it only allowed it while the “application is in use” it will make a request through the parameter “Geolocator.requestPermission()”.
In order for the application to respond appropriately to the user if he does not give permission, create a _showDialog(), this method will execute a pop-up on the user's screen informing him that permission has been denied.
void _showDialog() { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text("Permissao para Acessar local"), content: const Text( "Deve escolher opção de permição: 'Permitir o tempo todo'"), actions:[ TextButton( child: Text("OK"), onPressed: () async { Navigator.of(context).pop; }, ), ], ); }, ); }
Continued in the MyHomePage class create the runLocation() method. This method will be responsible for implementing the code that will verify the location as the vehicle moves. In this method, by calling getPositionStream(), it is possible to “listen” to the location changes.
Set the accuracy and distanceFilter according to the code below.
runLocation() async { // ignore: prefer_const_constructors final LocationSettings locationSettings = LocationSettings( accuracy: LocationAccuracy.high, distanceFilter: 10, ); StreamSubscriptionpositionStream = Geolocator.getPositionStream(locationSettings: locationSettings) .listen((Position? position) { setState(() { latitude = position?.latitude; longitude = position?.longitude; altitude = position?.altitude; speed = position?.speed; timestamp = position?.timestamp; }); print(position == null ? 'Unknown' : '${position.latitude.toString()}, ${position.longitude.toString()}'); }); }
Use the setState() method and insert the variables for the data to be collected. setState() is used to update the values of your View in real time.
The runLocation() has to be asynchronous and as the device moves, this method will be executed and automatically update the values of the latitude, longitude, altitude, speed and timestamp variables.
A good place to insert external API communication for data synchronization is inside the getPositionStream() method. Since this method will always be executed as the device moves.
Use the standard flutter method initState() to call the two created methods runPermission() and runLocation().
@override void initState() { runPermission(); runLocation(); }
All the methods we need to get the GPS parameters were created, to make the application look more pleasant, we can edit the Widget from within the MyHomePage class and take advantage of it and pass our variables
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( elevation: 0, toolbarHeight: 150, backgroundColor: Color.fromARGB(255, 230, 229, 229), centerTitle: true, title: GradientText( 'My Speed', style: const TextStyle(fontSize: 40), gradient: LinearGradient(colors: [ Colors.blue.shade400, Color.fromARGB(255, 144, 13, 161), ]), ), ), body: Center( child: Container( child: Padding( padding: const EdgeInsets.all(16.0), child: ListView(children: [ //Latitude Card Card( clipBehavior: Clip.antiAlias, child: Column( children: [ ListTile( leading: const RotatedBox( quarterTurns: 1, child: Icon(Icons.height_rounded), ), title: const Text('Latitude'), subtitle: Text( '$latitude', style: TextStyle( color: Colors.black.withOpacity(0.6)), ), ), ], ), ), //Longitude Card Card( clipBehavior: Clip.antiAlias, child: Column( children: [ ListTile( leading: const Icon(Icons.height_rounded), title: const Text('Longitude'), subtitle: Text( '$longitude', style: TextStyle( color: Colors.black.withOpacity(0.6)), ), ), ], ), ), //Altitude Card Card( clipBehavior: Clip.antiAlias, child: Column( children: [ ListTile( leading: const Icon(Icons.terrain), title: const Text('Altitude'), subtitle: Text( '$altitude', style: TextStyle( color: Colors.black.withOpacity(0.6)), ), ), ], ), ), //speed Card Card( clipBehavior: Clip.antiAlias, child: Column( children: [ ListTile( leading: const Icon(Icons.speed), title: const Text('Velocidade'), subtitle: Text( "${(speed! * 3.6)} km/h", style: TextStyle( color: Colors.black.withOpacity(0.6)), ), ), ], ), ), //Date Time Card Card( clipBehavior: Clip.antiAlias, child: Column( children: [ ListTile( leading: const Icon(Icons.access_time), title: const Text('Data & Hora'), subtitle: Text( '$timestamp', style: TextStyle( color: Colors.black.withOpacity(0.6)), ), ), ], ), ), ])))), ); } }
Create cards for each GPS variable that will allow you to see each one independently. The GradientText that shows in the Title of the AppBar is another class made inside the main.dart file
class GradientText extends StatelessWidget { const GradientText( this.text, { required this.gradient, this.style, }); final String text; final TextStyle? style; final Gradient gradient; @override Widget build(BuildContext context) { return ShaderMask( blendMode: BlendMode.srcIn, shaderCallback: (bounds) => gradient.createShader( Rect.fromLTWH(0, 0, bounds.width, bounds.height), ), child: Text(text, style: style), ); } }
After completing all these steps in the application, it is now possible to capture GPS data as the device is moved.
0 comments:
Post a Comment