Flutter Google Map Crashes on first open in IOS - google-maps

I have a google map on the very first page of my application after the splash screen.
When I run the app for the first time and a very new build, it crashes with this error on IOS: PlatformException(create_failed, can't create a view on a headless engine, null).
This is my google Map code and the crash happens only in IOS for the first time when the app is installed.
GoogleMap(
myLocationEnabled: false,
myLocationButtonEnabled: false,
zoomGesturesEnabled: true,
scrollGesturesEnabled: true,
rotateGesturesEnabled: false,
tiltGesturesEnabled: false,
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: _location,
zoom: 12,
/* tilt: 50.0,
bearing: 45.0,*/
),
mapType: _currentMapType,
markers: Set<Marker>.of(markers.values),
onCameraMove: _onCameraMove,
onCameraIdle: _onCameraIdle,
)
I am following up on this issue on GitHub : https://github.com/flutter/flutter/issues/36310
but it is not having a proper solution.
Can anyone please help me with this?

Have you registered your API key properly and in the right spot?
This needs to be registered within the appDelegate class before the flutter engine kicks in. (Please note that this is a swift file)
import UIKit
import GoogleMaps
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("super_secret_api_key")
GeneratedPluginRegistrant.register(with: self);
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

Related

Flutter: How to animate the camera of Google Maps

I'm trying to build an app that loads a GoogleMap(), then after getting the user latitude and longitude moves to the that specific location.
I came up with this idea (code below), but it works only if I restart the app and if I don't it gives error: animateCamera was called on null.
How is it possible ? and how can i fix it ?
Thanks for answering :D
...
var mapController;
...
GoogleMap createMap() {
var initMap = GoogleMap(
onMapCreated: onMapCreated,
initialCameraPosition:
CameraPosition(target: LatLng(47.290542, 8.322641), zoom: 6.7),
);
return initMap;
}
...
void onMapCreated(controller) {
mapController = controller;
}
...
void moveCameraToUserLocation(searchedLocation2) async {
var location = await Geocode().getLatLng(searchedLocation2);
print("moving to: $location");
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: location,
zoom: 20,
),
),
);
...
build(context) {
return Scaffold(
body: createMap(),
...
Based on how you describe the problem, it looks like you are only calling the animate function as the map loads.
I suggest that you create a button that would handle and trigger the animate function and move the camera to the device location whenever tapped.
The following code snippet uses a ClipOval button and inside the OnTap() event you can call the method to get the device current location which will be triggered whenever the button is tapped.
ClipOval(
child: Material(
color: Colors.green[100], // button color
child: InkWell(
splashColor: Colors.green, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.my_location),
),
onTap: () {
// Add methods here that will be called whenever the button is tapped
mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: LatLng(_currentPosition.latitude, _currentPosition.longitude),
zoom: 17.0)));
setState(() {
allMarkers.add(Marker(
markerId: MarkerId('Current Position'),
draggable: false,
position:
LatLng(_currentPosition.latitude, _currentPosition.longitude)));
});
},
),
),
)
Probably you are calling moveCameraToUserLocation function before map is created. From this part of the code I cannot se when you call thi function but my guess is that you call it from initstate. If you want to call this function immediately after widget is created move it to onMapCreated.
void onMapCreated(controller) {
mapController = controller;
moveCameraToUserLocation();
}

Google Maps camera position updating issues in Flutter

I'm building an application with Flutter, based on a map. So I use the Google Maps package and all's working fine. But, I tried to add a FloatingActionButton to recenter the map on my location, and here, I got a problem. First, the map doesn't recenter on my location and second, I get an horrible red error. Here are the code, the flutter doctor, and the error code.
My code:
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import 'package:spotycar/providers/location_service.dart';
import '../../models/user_location.dart';
class MapWidget extends StatefulWidget {
MapWidget({#required Key key}) : super(key: key);
#override
_MapWidgetState createState() => _MapWidgetState();
}
var locationClicked = false;
class _MapWidgetState extends State<MapWidget> {
#override
Widget build(BuildContext context) {
CameraUpdate cameraUpdate;
GoogleMapController mapController;
var location = Provider.of<UserLocation>(context);
final provider = Provider.of<LocationService>(context);
final double _zoom = 17.0;
final double _tilt = 37.0;
var _coord;
if (provider.loadedLocation) {
_coord = LatLng(location.latitude, location.longitude);
cameraUpdate = CameraUpdate.newCameraPosition(CameraPosition(
target: _coord,
bearing: location.heading,
zoom: _zoom,
tilt: _tilt,
));
}
if (locationClicked == true) {
mapController.moveCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: _coord,
bearing: location.heading,
zoom: _zoom,
tilt: _tilt,
),
),
);
setState(() {
locationClicked = false;
});
}
return Scaffold(
body: !provider.loadedLocation
? Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.purple),
),
)
: GoogleMap(
onMapCreated: (GoogleMapController controller) {
mapController = controller;
mapController.animateCamera(cameraUpdate);
},
myLocationEnabled: true,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
initialCameraPosition: CameraPosition(
target: _coord,
zoom: _zoom,
tilt: _tilt,
),
rotateGesturesEnabled: true,
),
);
}
}
class LocationRechercheWidget extends StatefulWidget {
#override
_LocationRechercheWidgetState createState() =>
_LocationRechercheWidgetState();
}
class _LocationRechercheWidgetState extends State<LocationRechercheWidget> {
#override
Widget build(BuildContext context) {
return FloatingActionButton(
child: Icon(
Icons.location_searching,
color: Colors.purple,
size: 25,
),
backgroundColor: Colors.white,
onPressed: () {
setState(() {
locationClicked = true;
});
},
);
}
}
My Flutter doctor :
[√] Flutter (Channel master, 1.20.0-3.0.pre.124, on Microsoft Windows [version 10.0.18362.900], locale fr-FR)
• Flutter version 1.20.0-3.0.pre.124 at C:\flutter
• Framework revision ec3368ae45 (2 days ago), 2020-07-02 01:58:01 -0400
• Engine revision 65ac8be350
• Dart version 2.9.0 (build 2.9.0-20.0.dev f8ff12008e)
[√] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
• Android SDK at C:\Users\adrie\AppData\Local\Android\sdk
• Platform android-29, build-tools 29.0.2
• Java binary at: C:\Program Files\Android\Android Studio1310\jre\bin\java
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)
• All Android licenses accepted.
[√] Android Studio (version 3.6)
• Android Studio at C:\Program Files\Android\Android Studio1310
• Flutter plugin version 45.1.1
• Dart plugin version 192.7761
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)
[√] VS Code (version 1.46.1)
• VS Code at C:\Users\adrie\AppData\Local\Programs\Microsoft VS Code
• Flutter extension version 3.12.1
[√] Connected device (1 available)
• Mi Note 10 (mobile) • 53bd04cc • android-arm64 • Android 10 (API 29)
• No issues found!
And The error that I'm getting when I click on the FloatingActionButton :
═╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building MapWidget-[#2721f](dirty, dependencies:
[InheritedProvider<UserLocation>, InheritedProvider<LocationService>], state:
_MapWidgetState#50617):
The method 'moveCamera' was called on null.
Receiver: null
Tried calling: moveCamera(Instance of 'CameraUpdate')
The relevant error-causing widget was:
MapWidget-[#2721f]
lib\screen\map_screen.dart:20
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 _MapWidgetState.build
package:spotycar/…/map_screen/map_widget.dart:39
#2 StatefulElement.build
package:flutter/…/widgets/framework.dart:4663
#3 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4546
#4 StatefulElement.performRebuild
package:flutter/…/widgets/framework.dart:4719
#5 Element.rebuild
package:flutter/…/widgets/framework.dart:4262
#6 BuildOwner.buildScope
package:flutter/…/widgets/framework.dart:2667
#7 WidgetsBinding.drawFrame
package:flutter/…/widgets/binding.dart:866
#8 RendererBinding._handlePersistentFrameCallback
package:flutter/…/rendering/binding.dart:286
#9 SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1115
#10 SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1054
#11 SchedulerBinding._handleDrawFrame
package:flutter/…/scheduler/binding.dart:970
#15 _invoke (dart:ui/hooks.dart:253:10)
#16 _drawFrame (dart:ui/hooks.dart:211:3)
(elided 3 frames from dart:async)
To solve this issue, you need to use a Completer instead of a simple GoogleMapController.
When you instantiate it :
Completer<GoogleMapController> _controller = Completer();
Then in the onMapCreated method inside your GoogleMap widget :
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
...
},
And whenever you wanna change the camera position :
Future<void> moveCamera() async {
final GoogleMapController controller = await _controller.future;
controller.moveCamera(CameraUpdate.newCameraPosition(CameraPosition(
target: LatLong(..., ...),
zoom: ...,
)));
}
And you should be good !
I had this issue, I had the exact code that was being used by Vayhuit. My pin would update but the cam whent to the last place I had searched. to solve this I had to change
static final CameraPosition _location = CameraPosition(
target: LatLng(lat!, lng!),
zoom: 15,
);
I had an init state so I created a
late CameraPosition _location;
and then
getLocation() {
_location = CameraPosition(
target: LatLng(lat!, lng!),
zoom: 15,
);
}
Then I just added getLocation(); to the initstate. seems to work now.
For those who are using FlutterMap or MapBox in Flutter
The above answers are right but I will add one thing, that was a big problem for me as well. How to keep the zoom level according to the user zoom because when you listen for the current location changes and update your camera position according to it then the zoom level is also picking the one that you provide at the start.
for example: you provide the zoom level 13 at the start and you zoom the screen to 16 then when the camera position updates it will bring you again to zoom level 13, and it is repeating after every second which is really annoying, So you have to provide the zoom level dynamically which will change according to the user zoom level.
First Listen to the location stream:
location.onLocationChanged.listen((event) {
final newLatLng = LatLng(event.latitude!, event.longitude!);
// Use mapController to access the move method
// move() method is used for the camera position changing e.g: move(LatLng center, double zoom)
mapController.move(newLatLng , 13); // this will set the zoom level static to 13
// but we want it to be dynamic according to the user zoom level,
// so then use the mapController.zoom property will dynamically adjust your zoom level
mapController.move(newLatLng , mapController.zoom);
});

How do I remove a Null exception on a themed map and is it worth it?

I have a map app that uses google_map_flutter package and displays a full screen themed map. My confusion is that when I build the app I receive an unhandled exception for setMapStyle, even though the map displays with the theme.
Unhandled Exception: NoSuchMethodError: The method 'setMapStyle' was
called on null. E/flutter (30877): Receiver: null E/flutter (30877):
Tried calling: setMapStyle("[\r\n {\r\n \"featureType\":
\"landscape\",\r\n \"elementType\": \"geometry\",\r\n.......
The theme is a json file that I load using the code in my initState below.
#override
void initState() {
super.initState();
// Show the campus Map
getSunData();
// _showCampusMap();
WidgetsBinding.instance.addObserver(this);
// Check location permission has been granted
PermissionHandler()
.checkPermissionStatus(PermissionGroup
.locationWhenInUse) //check permission returns a Future
.then(_updateStatus); // handling in callback to prevent blocking UI
rootBundle
.loadString('assets/themes/map/day/simple_bright.json')
.then((string) {
mapStyle = string;
});
getUserLocation();
}
My method for setting the style is here.
// method that is called on map creation and takes a MapController as a parameter
void _onMapCreated(GoogleMapController controller) async {
PermissionHandler()
.checkPermissionStatus(PermissionGroup
.locationWhenInUse) //check permission returns a Future
.then(_updateStatus); // handling in callback to prevent blocking UI
controller.setMapStyle(mapStyle);
}
Here is my GoogleMap code
_userLocation == null
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
backgroundColor: Theme.UniColour.primary[900],
),
SizedBox(height: 20.0),
Text("Retrieving your location..."),
],
),
)
: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: // required parameter that sets the starting camera position. Camera position describes which part of the world you want the map to point at.
CameraPosition(
target: _userLocation,
zoom: _defaultZoom,
tilt: _tiltAngle), //LatLng(53.467125, -2.233966)
scrollGesturesEnabled: _scrollGesturesEnabled,
tiltGesturesEnabled: _tiltGesturesEnabled,
compassEnabled: _compassEnabled,
rotateGesturesEnabled: _rotateGesturesEnabled,
myLocationEnabled: _myLocationEnabled,
buildingsEnabled: _buildingsEnabled, // not added to db
indoorViewEnabled: _indoorViewEnabled, // not added to db
mapToolbarEnabled: _mapToolbarEnabled, // not added to db
myLocationButtonEnabled:
_myLocationButtonEnabled, // not added to db
mapType: _currentMapType,
zoomGesturesEnabled: _zoomGesturesEnabled,
cameraTargetBounds: CameraTargetBounds(
new LatLngBounds(
northeast: uniCampusNE,
southwest: uniCampusSW,
),
),
minMaxZoomPreference:
MinMaxZoomPreference(_minZoom, _maxZoom),
),
Any ideas why this exception is occurring, does it need fixing and how would I do that?
[EDIT]
void _updateStatus(PermissionStatus status) {
if (status != _status) {
// check status has changed
setState(() {
_status = status; // update
_onMapCreated(controller);
});
} else {
if (status != PermissionStatus.granted) {
//print("REQUESTING PERMISSION");
PermissionHandler().requestPermissions(
[PermissionGroup.locationWhenInUse]).then(_onStatusRequested);
}
}
}
The argument type 'Completer' can't be assigned
to the parameter type 'GoogleMapController'.
[/EDIT]
thanks
You need to initialize the Completer class, under your State class write the following:
Completer<GoogleMapController> _controller = Completer();
Then use the variable _controller when calling setMapStyle:
void _onMapCreated(GoogleMapController controller) async {
PermissionHandler()
.checkPermissionStatus(PermissionGroup
.locationWhenInUse) //check permission returns a Future
.then(_updateStatus); // handling in callback to prevent blocking UI
_controller.setMapStyle(mapStyle);
}

WebView in Flutter for Web is not loading Google Maps or others

Hei there,
I have the Problem that my WebView doesn't load. It only shows me a loading Screen.
I am using the flutter_webview_plugin in Flutter for Web.
I have no idea why its always loading. It does this always, with whatever Website I tried.
import 'package:flutter/material.dart';
import 'package:website_aalen_by_night/widgets/info_card.dart';
import 'package:website_aalen_by_night/widgets/nav_bar.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AAlen by Night',
theme: ThemeData.dark(),
home: WebsiteAalenByNight(),
debugShowCheckedModeBanner: false,
);
}
}
class WebsiteAalenByNight extends StatefulWidget {
#override
WebsiteState createState() => WebsiteState();
}
ScrollController controller = new ScrollController();
class WebsiteState extends State {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
FlutterWebviewPlugin().onHttpError.listen((WebViewHttpError item) {
print(" WebView onHttpError.code: ${item.code}");
});
return Scaffold(
backgroundColor: Color.fromRGBO(79, 79, 79, 1),
body: Stack(
children: <Widget>[
Scrollbar(
child: ListView(
controller: controller,
children: <Widget>[
InfoCard(),
Image(
image: AssetImage("lib/images/map.png"),
//height: height,
width: width,
fit: BoxFit.cover,
),
InfoCard(),
LimitedBox(
maxWidth: width,
maxHeight: height,
child: WebviewScaffold(
url: "https://www.google.com",
withZoom: false,
withLocalStorage: false,
withJavascript: true,
withLocalUrl: true,
),
),
],
),
),
NavBar(),
],
),
);
}
}
The goal of this is to implement a Map with Markers on the Screen. So I believed I can try a WebView but with that I did come to a stop soon.
Maybe there is a better Way to implement a Map (tried a few other Things like using a map plugin instead but I didn't find any which works for Flutter for Web).
It is really important to get it working on Flutter for Web and NOT on
any other Platform!
Thanks for helping me....
Maybe in the Future I am able to answer such questions for others :D
I don't think that https://github.com/fluttercommunity/flutter_webview_plugin works in web since it uses native libraries.
HOWEVER, the great advantage of using a browser for your flutter app, is that you can use HTML and you don't need a webview there!
check this example of using a nested youtube player
void main() {
ui.platformViewRegistry.registerViewFactory(
'hello-world-html',
(int viewId) => IFrameElement()
..width = '640'
..height = '360'
..src = 'https://www.youtube.com/embed/IyFZznAk69U'
..style.border = 'none'
);
runApp(Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
width: 640,
height: 360,
child: HtmlElementView(viewType: 'hello-world-html'),
),
));
}
source
Of course the communication with the content it's another history, since it's an iframe and in web browsers CORS is enabled it means you can't access the iframe from flutter, in the case of Google maps, they have an URL api and pass your marker location there ;)

Flutter get coordinates from google maps

I use the package google_maps_flutter to use Google maps in my app. My problem is how to set a listener, show when I press in the map to get the coordination of this place. I don't find anything in documentation.
The only thing which I find is with controllerMap, which I use to set marker listener, is that it has a method,
.addListener(listener)
Any idea?
I have solved the problem using the onMarkerTapped callback methods below:
Note: mapController below is an instance of the GoogleMap Controller
mapController.**onMarkerTapped**.add((marker){
String title= marker.options.infoWindowText.title;
String latitude= marker.options.position.latitude.toString();
String longitude= marker.options.position.longitude.toString();
});
google map plugin has a lot of errors:), I prefer using this plugin : flutter_map
full example :
import 'package:location/location.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
class ContactPage extends StatefulWidget {
#override
ContactPageState createState() => new ContactPageState();
}
class ContactPageState extends State<ContactPage>
with TickerProviderStateMixin {
static LatLng myLocation = new LatLng(51.5, -0.09);
#override
void initState() {
super.initState();
setState(() {
new LatLng(51.5, -0.09);
});
}
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
double heigh = screenSize.height;
TextStyle whiteStyle = new TextStyle(fontSize: 20.0, color: Colors.white);
return new Directionality(
textDirection: TextDirection.rtl,
child: new Container(
padding: new EdgeInsets.only(bottom: 10.0, left: 1.0, right: 1.0),
color: Colors.white,
child: new FlutterMap(
options: new MapOptions(
center: myLocation,
zoom: 15.0,
maxZoom: 15.0,
minZoom: 3.0,
onTap: _handleTap),
layers: [
new TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
new MarkerLayerOptions(markers: markers)
],
)
)),
);
}
_handleTap(LatLng point) {
setState(() {
myLocation = point;
});
}
}
This functionality is currently not available in version 2.0 of the google flutter plugin, however there are two pull requests that have added this functionality.
1121
941
Pull request 1121 has example code on how to use the tap functionality.
With the current documentation, I only made the following change to the example of #lionelsanou and #Pradeep given above:
String latitude= marker.values.first.position.toString();
String longitude= marker.values.last.position.toString();
and it worked for me.