Flutter web - Geolocator not working when uploaded to server

Viewed 483

everyone.

I'm trying to develop a PWA with flutter 2.2.1 that shows a map using Mapbox_gl and displays the user current location using Geolocator.

So far everything works as expected while debuging the app, but when I run:

flutter build

or

flutter build --release

and then run

firebase deploy

the site gets uploaded, the map shows as intended and it asks for permissions but the user's location is never shown and Google Chrome's Console throws this error:

Uncaught TypeError: m.gfR is not a function
at Object.avh (main.dart.js:20405)
at main.dart.js:65755
at aiD.a (main.dart.js:5853)
at aiD.$2 (main.dart.js:34394)
at ahm.$1 (main.dart.js:34386)
at Rx.o1 (main.dart.js:35356)
at adi.$0 (main.dart.js:34770)
at Object.tQ (main.dart.js:5975)
at a5.mn (main.dart.js:34687)
at ada.$0 (main.dart.js:34731)

Here's the code I'm using on flutter:

mapbox.dart

import 'dart:async';
import 'dart:io';
import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:geolocator/geolocator.dart';
import 'package:kkc/main.dart';
import 'package:mapbox_gl/mapbox_gl.dart';
import 'package:kkc/services/location_service.dart';

class Mapbox extends StatefulWidget {
   const Mapbox();

   @override
   State createState() => MapboxState();
}

class MapboxState extends State<Mapbox> {
   final Random _rnd = new Random();

   Position? _currentLocation;
   LatLng _currentCoordinates = new LatLng(0,0);
   final List<_PositionItem> _positionItems = <_PositionItem>[];
   StreamSubscription<Position>? _positionStreamSubscription;

   late MapboxMapController _mapController;
   List<Marker> _markers = [];
   List<_MarkerState> _markerStates = [];

   CameraPosition _kInitialPosition = CameraPosition(
     target: LatLng(19.4274418, -99.1682147),
     zoom: 18.0,
     tilt: 70,
   );

   void _addMarkerStates(_MarkerState markerState) {
     _markerStates.add(markerState);
   }

   void _onMapCreated(MapboxMapController controller) {
     _mapController = controller;
     controller.addListener(() {
       if (controller.isCameraMoving) {
         _updateMarkerPosition();
       }
     });
   }

   void _onStyleLoadedCallback() {
     _updateMarkerPosition();
   }

   void _onCameraIdleCallback() {
     _updateMarkerPosition();
   }

   void _updateMarkerPosition() {
     final coordinates = <LatLng>[];

     for (final markerState in _markerStates) {
       coordinates.add(markerState.getCoordinate());
     }

     _mapController.toScreenLocationBatch(coordinates).then((points) {
       _markerStates.asMap().forEach((i, value) {
         _markerStates[i].updatePosition(points[i]);
       });
     });
  }

  void _addMarker(Point<double> point, LatLng coordinates) {
     setState(() {
       _markers.add(Marker(_rnd.nextInt(100000).toString(), coordinates, point, _addMarkerStates));
     });
  }

  @override
  void initState() {
     super.initState();
     _getCurrentLocation();
  }

  @override
  void dispose() {
     super.dispose();
  }

  @override
  Widget build(BuildContext context) {
     return new Scaffold(
       body: Stack(children: [
         MapboxMap(
           accessToken: Kukulcan.MAPBOX_ACCESS_TOKEN,
           trackCameraPosition: true,
           onMapCreated: _onMapCreated,
           onCameraIdle: _onCameraIdleCallback,
           onStyleLoadedCallback: _onStyleLoadedCallback,
           initialCameraPosition: _kInitialPosition,
         ),
         IgnorePointer(
             ignoring: true,
             child: Stack(
               children: _markers,
             ))
        ]),
     );
  }

  void _getCurrentLocation() async {
     _currentLocation = await LocationService.startLocationService();
     _currentCoordinates = new LatLng(_currentLocation!.latitude,_currentLocation!.longitude);

     await _mapController.animateCamera(CameraUpdate.newLatLng(_currentCoordinates));
     _addMarker(new Point(1, 1), _currentCoordinates);

     if (_positionStreamSubscription == null) {
       final positionStream = Geolocator.getPositionStream();
       _positionStreamSubscription = positionStream.handleError((error) {
         _positionStreamSubscription?.cancel();
         _positionStreamSubscription = null;
       }).listen((position) => setState(() => _positionItems.add(
         _PositionItem(_PositionItemType.position, position.toString()))));
       _positionStreamSubscription?.pause();
     }
   }
}

class Marker extends StatefulWidget {
   final Point _initialPosition;
   LatLng _coordinate;
   final void Function(_MarkerState) _addMarkerState;

   Marker(
       String key, this._coordinate, this._initialPosition, this._addMarkerState)
       : super(key: Key(key));

   @override
   State<StatefulWidget> createState() {
     final state = _MarkerState(_initialPosition);
     _addMarkerState(state);
     return state;
   }
}

class _MarkerState extends State with TickerProviderStateMixin {
   final _iconSize = 80.0;

   Point _position;

   _MarkerState(this._position);

   @override
   Widget build(BuildContext context) {
     var ratio = 1.0;

     //web does not support Platform._operatingSystem
     if (!kIsWeb) {
       // iOS returns logical pixel while Android returns screen pixel
       ratio = Platform.isIOS ? 1.0 : MediaQuery.of(context).devicePixelRatio;
     }

     return Positioned(
         left: _position.x / ratio - _iconSize / 2,
         top: _position.y / ratio - _iconSize / 2,
         child: Image.asset('assets/img/pin.png', height: _iconSize));
   }

   void updatePosition(Point<num> point) {
     setState(() {
       _position = point;
     });
   }

   LatLng getCoordinate() {
     return (widget as Marker)._coordinate;
   }
}

enum _PositionItemType {
   permission,
   position, 
}

class _PositionItem {
   _PositionItem(this.type, this.displayValue);

   final _PositionItemType type;
   final String displayValue;
}

Does anyone have an idea on what's the problem?

Cheers!

1 Answers

Anyway the solution i found is to use --no-sound-null-safety argument as stated by geolocat documentation

I quote:

NOTE: due to a bug in the dart:html library the web version of the Geolocator plugin does not work with sound null safety enabled and compiled in release mode. Running the App in release mode with sound null safety enabled results in a Uncaught TypeError (see issue #693). The current workaround would be to build your App with sound null safety disabled in release mode:

Related