Hi everyone.
Mapbox is a tremendous carrier to use maps, is high-quality due to the fact you can edit the maps as you prefer to exhibit them primarily based on your requirements. You may want to swap between exclusive types of layers to exhibit the maps, like outdoors, streets, monochromatic, and so on. For extra info, this is the respectable website:
In this example, we are going to use:
1. Mapbox
2. Location package
3. Flutter dot env package
4. Flutter bloc.
5. Very Good CLI to create a new package called location_repository.
Create an account and create a secret access token
Native configurations
Android
1- Go to the gradle.properties file and set the secret access token: MAPBOX_DOWNLOADS_TOKEN=YOUR_SECRET_MAPBOX_ACCESS_TOKEN
2- Create a new strings.xml file to set your secret key, to do that, you have to go to android/app/main/res/values and create a new file referred to as strings.xml and set up the information.
3- Configure the permissions on the AndroidManifest.xml file.
4- Change the minSdkVersion to 21 into the module-level build.gradle file.
iOS
1- The first step that you want to do is to create a .netrc file in your HOME Mac directory, observe these steps to create:
1. Open a Terminal
2. cd ~ (this is to go to the home directory)
3. touch .netrc (this is to create a file)
4. open .netrc (open .netrc file)
When the file is open you need to copy/paste this and set your secret password:
machine api.mapbox.com
login Mapbox
password YOUR_SECRET_MAPBOX_ACCESS_TOKEN
Save the records and shut the file.
The .netrc file is an undeniable textual content file that is used in sure improvement environments to save credentials used to get admission to far-flung servers.
2- Configure the public get right of entry to token:
Open the listing Runner.xcworkspace in XCode. Select on the left facet the root of the venture “Runner”, then on ambitions pick “Runner” and in the end, you have to pick out the Info tab. On Custom iOS Targets Properties you want to add a new one referred to as MBXAccessToken with your public token.
If you shut XCode and go to your flutter task on the ios/runner/info.plist file you may want to see a new line like this:
Additionally, you want to add a message to inform the consumer that the vicinity is mandatory, so you can add a new line into Info.plist like this:
3- Change the platform versión into the Podfile file.
4- Execute the subsequent instructions to clean, replace and installation the new pods:
cd /ios
rm -rf Pods/ Podfile.lock Flutter/Flutter.podspec
pod deintegrate
pod repo update
pod install
Try to execute the app. Are you facing this error?
installer.pods_project.build_configurations.eachdo|config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"]="arm64"
end
Okay, at this factor the native configurations are done. The subsequent step is to get the system vicinity to set our region on the map.
.ENV File
In this project, I’m going to use the flutter_dotenv bundle to cover my get admission to the token. It’s easy to use, you want to create a property folder in your root software and then create a .env file.
Inside this folder you are going to put your public Mapbox get entry to token like this:
MAPBOX_ACCESS_TOKEN = 'YOUR PUBLIC ACCESS TOKEN'
Then, to load the file and be capable to use it in our application, we want to add this line to our primary method.
await dotenv.load(fileName: "assets/.env");
If you want to get the price of our MAPBOX_ACCESS_TOKEN, you want to do it in this way:
dotenv.get('MAPBOX_ACCESS_TOKEN')
To cover this .env file in our Github assignment we want to add a new line to our .gitnore file:
/assets/.env
Location
In this tutorial we are going to do something different, we are going to create our personal package deal to host all the content material associated with “location”. This is an excellent way to have all greater shape and clean, and additionally, if you prefer to use this package deal in any other app you ought to do it due to the fact is impartial to the relaxation of the code.
To create it we are going to use Very Good CLI.
For more info, check this link: https://verygood.ventures/blog/flutter-starter-app-very-good-core-cli.
Location Repository Package
1- Create an applications folder on your root undertaking and open a new terminal on the new folder and put this:
dart pub global activate very_good_cli
very_good create location_repository -t dart_pkg
If you take a look at your programs folder you may want to note that there is a new bundle known as “location_repository”.
To use the vicinity we want to add the area package deal to our location_repository/pubspec.yaml file and run flutter pub get.
Now we can use the region package. To get the consumer machine region we want to test two vital matters earlier than getting the location:
Check if the provider is enabled.
Check if the consumer has the critical permissions (these permissions are the ones we introduced above).
I’ve created a “custom” exception referred to as CurrentLocationFailure to manage the exclusive blunders messages that we can throw to supply to the person extra information.
This is the full method.
Future<CurrentUserLocationEntity> getCurrentLocation() async {
final serviceEnabled = await _location.serviceEnabled();
if (!serviceEnabled) {
final isEnabled = await _location.requestService();
if (!isEnabled) {
throw CurrentLocationFailure(
error: "You don't have location service enabled",
);
}
}
final permissionStatus = await _location.hasPermission();
if (permissionStatus == PermissionStatus.denied) {
final status = await _location.requestPermission();
if (status != PermissionStatus.granted) {
throw CurrentLocationFailure(
error: "You don't have all the permissions granted."
'\nYou need to activate them manually.',
);
}
}
late final LocationData locationData;
try {
locationData = await _location.getLocation();
} catch (_) {
throw CurrentLocationFailure(
error: 'Something went wrong getting your location, '
'please try again later',
);
}
final latitude = locationData.latitude;
final longitude = locationData.longitude;
if (latitude == null || longitude == null) {
throw CurrentLocationFailure(
error: 'Something went wrong getting your location, '
'please try again later',
);
}
return CurrentUserLocationEntity(
latitude: latitude,
longitude: longitude,
);
}
Also, I created an object referred to as CurrentUserLocation to set the latitude and longitude of the person when the get current location technique returns the location data.
class CurrentUserLocationEntity {
const CurrentUserLocationEntity({
required this.latitude,
required this.longitude,
});
final double latitude;
final double longitude;
static const empty = CurrentUserLocationEntity(latitude: 0, longitude: 0);
}
This is the location_repository class:
import 'package:location/location.dart';
import 'package:location_repository/src/model/current_location.dart';
class CurrentLocationFailure implements Exception {
CurrentLocationFailure({
required this.error,
});
final String error;
}
/// {@template location_repository}
/// A Very Good Project created by Very Good CLI.
/// {@endtemplate}
class LocationRepository {
/// {@macro location_repository}
LocationRepository({
Location? location,
}) : _location = location ?? Location();
final Location _location;
Future<CurrentUserLocationEntity> getCurrentLocation() async {
final serviceEnabled = await _location.serviceEnabled();
if (!serviceEnabled) {
final isEnabled = await _location.requestService();
if (!isEnabled) {
throw CurrentLocationFailure(
error: "You don't have location service enabled",
);
}
}
final permissionStatus = await _location.hasPermission();
if (permissionStatus == PermissionStatus.denied) {
final status = await _location.requestPermission();
if (status != PermissionStatus.granted) {
throw CurrentLocationFailure(
error: "You don't have all the permissions granted."
'\nYou need to activate them manually.',
);
}
}
late final LocationData locationData;
try {
locationData = await _location.getLocation();
} catch (_) {
throw CurrentLocationFailure(
error: 'Something went wrong getting your location, '
'please try again later',
);
}
final latitude = locationData.latitude;
final longitude = locationData.longitude;
if (latitude == null || longitude == null) {
throw CurrentLocationFailure(
error: 'Something went wrong getting your location, '
'please try again later',
);
}
return CurrentUserLocationEntity(
latitude: latitude,
longitude: longitude,
);
}
}
Features
Now it’s time to go to our lib folder and create the shape to use the area and maps.
We are going to have two folders:
Location: right here we are going to create a bloc to deal with all the good judgment associated to getting the person location.
Map: right here we are going to cope with all the common sense associated to the maps.
To exhibit a map the first aspect that we want to do is to get the consumer location, to do that we are going to use our bundle location_repository, so we want to add the dependency to our pubspec.yaml file.
Okay, we have the dependency introduced and now we can use it to get the consumer location.
Location
In this feature, we want to create a bloc to use the vicinity repository bundle and be capable to get the person service, permissions, and location. As constantly we want three classes.
Location kingdom class.
part of 'location_bloc.dart';
enum LocationStateStatus { initial, success, error, loading }
extension LocationStateStatusX on LocationStateStatus {
bool get isInitial => this == LocationStateStatus.initial;
bool get isSuccess => this == LocationStateStatus.success;
bool get isError => this == LocationStateStatus.error;
bool get isLoading => this == LocationStateStatus.loading;
}
class LocationState extends Equatable {
const LocationState({
this.status = LocationStateStatus.initial,
LatLng? initLocation,
CurrentUserLocationEntity? currentUserLocation,
String? errorMessage,
}) : currentUserLocation =
currentUserLocation ?? CurrentUserLocationEntity.empty,
initLocation = initLocation ?? const LatLng(40.4167, -3.70325),
errorMessage = errorMessage ?? '';
final LocationStateStatus status;
final CurrentUserLocationEntity currentUserLocation;
final LatLng initLocation;
final String errorMessage;
@override
List<Object?> get props => [
status,
currentUserLocation,
initLocation,
errorMessage,
];
LocationState copyWith({
LocationStateStatus? status,
CurrentUserLocationEntity? currentUserLocation,
LatLng? initLocation,
Location? location,
String? errorMessage,
}) {
return LocationState(
status: status ?? this.status,
currentUserLocation: currentUserLocation ?? this.currentUserLocation,
initLocation: initLocation ?? this.initLocation,
errorMessage: errorMessage ?? this.errorMessage,
);
}
}
Location event class.
part of 'location_bloc.dart';
class LocationEvent extends Equatable {
@override
List<Object?> get props => [];
}
class GetLocation extends LocationEvent {}
Location bloc class: In this class, we are going to have an occasion for our region repository class.
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:location/location.dart';
import 'package:location_repository/location_repository.dart';
import 'package:mapbox_gl/mapbox_gl.dart';
part 'location_event.dart';
part 'location_state.dart';
class LocationBloc extends Bloc<LocationEvent, LocationState> {
LocationBloc({
required this.locationRepository,
}) : super(LocationState()) {
on<GetLocation>(_getLocationEvent);
}
final LocationRepository locationRepository;
void _getLocationEvent(GetLocation event, Emitter<LocationState> emit) async {
try {
emit(state.copyWith(status: LocationStateStatus.loading));
var _currentLocation = await locationRepository.getCurrentLocation();
emit(
state.copyWith(
currentUserLocation: _currentLocation,
status: LocationStateStatus.success,
),
);
} on CurrentLocationFailure catch (e) {
emit(
state.copyWith(
status: LocationStateStatus.error,
errorMessage: e.error,
),
);
// This is important to check errors on tests.
// Also you can see the error on the [BlocObserver.onError].
addError(e);
}
}
}
Now we can use this bloc on our Map feature.
Map
Here we are going to have two classes:
Map web page class: right here we are going to initialize our vicinity repository and additionally the place bloc.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:location_repository/location_repository.dart';
import 'package:maps_flutter/location/location_barrel.dart';
import 'package:maps_flutter/map/pages/map_layout.dart';
class MapPage extends StatelessWidget {
const MapPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RepositoryProvider(
create: (context) => LocationRepository(),
child: BlocProvider<LocationBloc>(
create: (context) => LocationBloc(
locationRepository: context.read<LocationRepository>(),
)..add(GetLocation()),
child: const MapLayout(),
),
);
}
}
Map design class: right here we are going to hear to the one-of-a-kind states of our region bloc to exhibit the right widget.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:maps_flutter/location/bloc/location_bloc.dart';
import 'package:maps_flutter/location/widgets/location_error_widget.dart';
import 'package:maps_flutter/map/widgets/map_success.dart';
class MapLayout extends StatelessWidget {
const MapLayout({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocBuilder<LocationBloc, LocationState>(
buildWhen: (previous, current) =>
current.status.isLoading ||
current.status.isError ||
current.status.isSuccess,
builder: (context, state) {
if (state.status.isSuccess) {
return MapSuccess(
locationData: state.locationData,
initLocation: state.initLocation,
);
}
if (state.status.isError) {
return LocationErrorWidget(
errorMessage: state.errorMessage,
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
);
}
}
ReplyDeleteWhat a comprehensive post! Extremely helpful and informative for a beginner like me. Thank you. By WDP Technologies