Search code examples
flutterandroid-emulatorgeolocator

Flutter Geolocator 9.0.2 Not Working on Android Emulator


I am using the flutter Map and I want to get the device location using the geolocator package but it is not working.

This works perfectly well on Windows(desktop) and Chrome/Edge web. However, it won't work on Android Emulator.

I already followed the instructions on this thread but to no avail. Specifically, I have configured a position using the emulator settings and have clicked the "Set Location" button.

I also have setup a route in the Android emulator settings and chose the repeat the playback.

For my android manifest, I have tried using just the ACCESS_COARSE_LOCATION and just the ACCESS_FINE_LOCATION but still to no avail. I also tried using the two at once but it still didn't work.

Geolocator version:

PS: I followed the instructions on the package's official page. PSS: When I run the app on the emulator, I didn't even get the pop-up asking for permission to access the location.

Below are my codes:

compileSdkVersion 33

Gradle.properties

org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true

Android Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.spot_the_bird">
    
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

   
   <application
        android:label="spot_the_bird"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

Location Cubit:

import 'dart:developer';

import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:geolocator/geolocator.dart';

part 'location_state.dart';

class LocationCubit extends Cubit<LocationState> {
  LocationCubit() : super(const LocationInitial());

  Future<void> getLocation() async {
    LocationPermission locationPermission = await Geolocator.checkPermission();

    if (locationPermission != LocationPermission.denied ||
        locationPermission != LocationPermission.deniedForever) {
      emit(const LocationLoading());

      try {
        Position position = await Geolocator.getCurrentPosition(
            desiredAccuracy: LocationAccuracy.high);
        log("$position");

        emit(LocationLoaded(
            longitude: position.longitude, latitude: position.latitude));
      } catch (error) {
        emit(const LocationError(
            message: 'Error occured while fetching location'));
      }
    } else {
      Geolocator.requestPermission();
    }
  }
}

Location State:

part of 'location_cubit.dart';

abstract class LocationState extends Equatable {
  const LocationState();

  @override
  List<Object?> get props => [];
}

class LocationInitial extends LocationState {
  const LocationInitial();
}

class LocationLoading extends LocationState {
  const LocationLoading();
}

class LocationLoaded extends LocationState {
  const LocationLoaded({
    required this.longitude,
    required this.latitude,
  });
  final double longitude;
  final double latitude;

  @override
  List<Object?> get props => [latitude, longitude];
}

class LocationError extends LocationState {
  final String message;
  const LocationError({
    required this.message,
  });
}

map Screen

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:spot_the_bird/bloc/location_cubit.dart';

class MapScreen extends StatelessWidget {
  MapScreen({super.key});

  final MapController _mapController = MapController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: BlocListener<LocationCubit, LocationState>(
        listener: (prevState, currState) {
          if (currState is LocationError) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(currState.message),
                duration: const Duration(seconds: 3),
                backgroundColor: Theme.of(context).errorColor,
              ),
            );
          }
          if (currState is LocationLoaded) {
            _mapController.onReady.then((value) => _mapController.move(
                LatLng(currState.latitude, currState.longitude), 15));
          }
        },
        child: FlutterMap(
          mapController: _mapController,
          options: MapOptions(
            center: LatLng(4.8472226, 6.974604),
            zoom: 15,
            minZoom: 4,
          ),
          layers: [
            TileLayerOptions(
              urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
              subdomains: ['a', 'b', 'c'],
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.read<LocationCubit>().getLocation();
        },
        child: const Icon(Icons.navigation_outlined),
      ),
    );
  }
}

Dependencies in pubspec.yaml

  flutter:
    sdk: flutter
  flutter_map: ^2.2.0
  latlong2: ^0.8.1
  geolocator: ^9.0.2
  flutter_bloc: ^8.1.1
  equatable: ^2.0.5
  bloc: ^8.1.0
  cupertino_icons: ^1.0.2

Solution

  • The issue was with my location.cubit. Weirdly, When I checked for the location.denied and location.deniedPermanantly separately it worked.

    Below is my new location.cubit code:

     Future<void> getLocation() async {
        //   bool serviceEnabled;
        LocationPermission permission;
    
        permission = await Geolocator.checkPermission();
    
        if (permission == LocationPermission.denied) {
          permission = await Geolocator.requestPermission();
          if (permission == LocationPermission.denied) {
            Get.snackbar('', 'Location Permission Denied');
            return Future.error('Location permissions are denied');
          }
        }
    
        if (permission == LocationPermission.deniedForever) {
          // Permissions are denied forever, handle appropriately.
          return Future.error(
              'Location permissions are permanently denied, we cannot request permissions.');
        } else {
          emit(const LocationLoading());
    
          try {
            Position position = await Geolocator.getCurrentPosition(
                desiredAccuracy: LocationAccuracy.high);
            log("$position");
    
            emit(LocationLoaded(
                longitude: position.longitude, latitude: position.latitude));
          } catch (error) {
            emit(const LocationError(
                message: 'Error occured while fetching location'));
          }
        }
      }
    

    PS: By the way, credit to @ibrahim Eltayfe, adding the <uses-permission android:name="android.permission.INTERNET"/> made me see the issue in debug console. Thanks man.