Search This Blog

Monday, July 9, 2018

Flutter - Google map plugin.

Flutter team has been building Google map plugin for display google map in Ios and Android. In this post, we going to view the progress of Google map plugin.  Before starting a google map Flutter project. Let's know about the power of Google map.
.
static google map
Google Maps is a web-based service that gives us information about geographical regions around the world. Google Maps offers aerial and satellite views of many places. In some cities, Google Maps offers street views photographs that are taken from its official vehicles.

Google Maps offers several services as part of the larger application, as follows.

1. A route planner offers directions for drivers, bikers, walkers, and users of public transportation who want to take a trip from one location to another.
2. The Google maps application program API's makes it possible for web site administrators to embed Google Maps into a proprietary site such as a real estate guide or community service page.
3. Google maps for mobile offers a location service for motorists that utilizes the Global Positioning System (GPS) location of the mobile device.
4. Google Street View enables users to view and navigate through horizontal and vertical panoramic street-level images of various cities around the world.



As we know,  Google Maps SDK have a large API. In this post, we'll cover the following API. 

  • Markers
  • The ability to show maps inline
  • Camera Updates
  • Map callbacks


MapView for native Ios and Android application is still in progress. So, we can't add it inside of Flutter hierarchy widgets. But don't worry, we have an alternative solution to use the Google Maps. We can use static map API for show maps inline while using the Google Maps SDK for iOS and Android to allow the user to interact with the full-screen map.

Before start Flutter google map application development we have to get google map API key. So, let's get it first.


Creating your API Key
We have to create a google map key for use Google Map API.

1. First of all, you have to create a google account.
2. After that Sign into https://console.developers.google.com/. 
3. On the Google API console, set up a new project.
4. Now move to API dashboard labeled Enable APIs and Services.
5. After that enable the following API for this project

Android — Enable the Google Maps Android API.
Ios — Enable the Google Maps iOS API.
Static Inline Maps — Enable the Google Static Maps API.

6. Next, we have to generate an API key. In the drawer on the left-hand side, tap on Credentials. Then tap the  Create Credentials button and select API Key. This will create a new API key that has access to all of the API’s you’ve enabled.

Now, Move to Flutter Application tools. In this project, we use static API to display a static location. You can change it by using the TextField that's a flutter widget. Once, static map load. You can move on the dynamic map after tap on Static Picture. It's all about our project. Let's start its implementation.

1. Create a new Flutter Project and give name flutter_google_map and add google map plugin  map_view: "^0.0.12" into pubspec.yaml,

2. After that, we have to do some changes for Ios and Android.

Android

  • In your AndroidManifest.xml, add the following uses-permission above the <application> tag.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

  • In your AndroidManifest.xml, add the following lines inside of the application tag. Be sure to replace your google map API. 

<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="your_api_key"/>
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>

  • Add the MapActivity to your AndroidManifest.xml

<activity android:name="com.apptreesoftware.mapview.MapActivity" android:theme="@style/Theme.AppCompat.Light.DarkActionBar"/>
  • After that move to android/build.gradle file. Under buildScript dependencies and add it.
  classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.51'

Ios

Set the NSLocationWhenInUseUsageDescription in ios/Runner/Info.plist.
<key>NSLocationWhenInUseUsageDescription</key>
<string>Using location to display on a map</string>
    
3. Now, move to the core part of Flutter application and edit main. dart file
main.dart
void main() { MapView.setApiKey(MapUtil.api_key); runApp(new MaterialApp( debugShowCheckedModeBanner: false, theme: new ThemeData( primaryColor: const Color(0xFF02BB9F), primaryColorDark: const Color(0xFF167F67), accentColor: const Color(0xFFFFAD32), ), home: new MapScreen(), )); }
As you can see above main.dart code snippet initialize the MapView with it's key. We have updated theme of App and created a new dart file map_screen.dart. It'll manage the widget hierarchy of our project.   

4. As you can see, we have made map_screen.dart as StateFullWidget. Because we'll render map if found changes on screen. 
map_screen.dart
@override void initState() { super.initState(); mapUtil = new MapUtil(); mapUtil.init(); mapView = new MapView(); teLatitude.text = mapUtil.getCamera().center.latitude.toString(); teLongitude.text = mapUtil.getCamera().center.longitude.toString(); teZoomLevel.text = mapUtil.getCamera().zoom.toString(); }
in this snippet, we have initialized the widgets and created an instance of MapUtil and MapView.


4. Now, we going to create a screen widget that displays static google, three TextField, and a Button. It'll change the static map after edit values.
map_screen.dart
new Container( height: 230.0, child: new Stack( children: <Widget>[ new Center( child: Container( child: new Text( "Google Map Box", textAlign: TextAlign.center, ), padding: const EdgeInsets.all(20.0), ), ), new GestureDetector( onTap: () => mapUtil.showMap(mapView), child: new Center( child: new Image.network(mapUtil.getStaticMap().toString()), ), ), ], ), ),
the above snippet displays a text that'll display before static map visible. When static map load it'll become hide behind the static map.
mapp_screen.dart
new Container( margin: new EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), padding: new EdgeInsets.only(top: 10.0), child: new Text( "Change Lat and long for get your location map", style: new TextStyle(fontWeight: FontWeight.bold), ), ), new Container( padding: new EdgeInsets.all(20.0), child: new Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ getTextField("latitude", teLatitude), getTextField("Lontitude", teLongitude), getTextField("Zoom level", teZoomLevel), new GestureDetector( onTap: () => updateStaticMap(), child: new Container( margin: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: getButton("Get Static map", EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 0.0)), ), ), ], ), ),
As you can see, in the above snippet. We created three TextField and Button for change static map.

Now, let's merge the above code and you will see complete map_screen.dart look like below:
map_screen.dart
import 'package:flutter/material.dart'; import 'package:flutter_google_map/map_util.dart'; import 'package:map_view/map_view.dart'; class MapScreen extends StatefulWidget { @override _MapScreenState createState() => new _MapScreenState(); } class _MapScreenState extends State<MapScreen> { final teLatitude = TextEditingController(); final teLongitude = TextEditingController(); final teZoomLevel = TextEditingController(); MapView mapView; MapUtil mapUtil; @override void initState() { super.initState(); mapUtil = new MapUtil(); mapUtil.init(); mapView = new MapView(); teLatitude.text = mapUtil.getCamera().center.latitude.toString(); teLongitude.text = mapUtil.getCamera().center.longitude.toString(); teZoomLevel.text = mapUtil.getCamera().zoom.toString(); } @override Widget build(BuildContext context) { var screenWidget = new Column( children: <Widget>[ new Container( height: 230.0, child: new Stack( children: <Widget>[ new Center( child: Container( child: new Text( "Google Map Box", textAlign: TextAlign.center, ), padding: const EdgeInsets.all(20.0), ), ), new GestureDetector( onTap: () => mapUtil.showMap(mapView), child: new Center( child: new Image.network(mapUtil.getStaticMap().toString()), ), ), ], ), ), new Container( margin: new EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), padding: new EdgeInsets.only(top: 10.0), child: new Text( "Change Lat and long for get your location map", style: new TextStyle(fontWeight: FontWeight.bold), ), ), new Container( padding: new EdgeInsets.all(20.0), child: new Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ getTextField("latitude", teLatitude), getTextField("Lontitude", teLongitude), getTextField("Zoom level", teZoomLevel), new GestureDetector( onTap: () => updateStaticMap(), child: new Container( margin: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: getButton("Get Static map", EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 0.0)), ), ), ], ), ), ], ); return new Scaffold( appBar: AppBar( title: new Text( "Flutter Google maps", textAlign: TextAlign.center, style: new TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ), ), ), body: new SingleChildScrollView( child: screenWidget, ), ); } Widget getTextField( String inputBoxName, TextEditingController inputBoxController) { var loginBtn = new Padding( padding: const EdgeInsets.all(5.0), child: new TextFormField( controller: inputBoxController, decoration: new InputDecoration( hintText: inputBoxName, ), ), ); return loginBtn; } Widget getButton(String buttonLabel, EdgeInsets margin) { var staticMapBtn = new Container( margin: margin, padding: EdgeInsets.all(8.0), alignment: FractionalOffset.center, decoration: new BoxDecoration( color: const Color(0xFF167F67), border: Border.all(color: const Color(0xFF28324E)), borderRadius: new BorderRadius.all(const Radius.circular(6.0)), ), child: new Text( buttonLabel, style: new TextStyle( color: const Color(0xFFFFFFFF), fontSize: 20.0, fontWeight: FontWeight.w300, letterSpacing: 0.3, ), ), ); return staticMapBtn; } updateStaticMap() { mapUtil.updateLocation(new Location(double.tryParse(teLatitude.text) ?? 0.0, double.tryParse(teLongitude.text) ?? 0.0)); mapUtil.updateZoomLevel(double.tryParse(teZoomLevel.text) ?? 12.0); setState(() { }); } }


5. After that create another dart file and give name map_util.dart. Here, We going to write our map methods and we create our static location instance. As you can see, I have given lat and long of my location. You can replace it with your location. In the following until class, you have to replace your google map key.


map_util.dart
import 'package:flutter/material.dart'; import 'package:map_view/map_view.dart'; class MapUtil { static var api_key = "Google_Map_key"; var staticMapProvider; CameraPosition cameraPosition; var location = new Location(30.7269882, 76.8354053); var zoomLevel = 12.0; init() { staticMapProvider = new StaticMapProvider(MapUtil.api_key); cameraPosition = new CameraPosition(getMyLocation(), zoomLevel); } List<Marker> getMarker() { List<Marker> markers = <Marker>[ new Marker("1", "The Lalit", 30.7265995, 76.8361955, color: Colors.amber), new Marker("2", "Tech mahindra", 30.7290226, 76.8339204, color: Colors.red), new Marker("3", "Infosys", 30.7285108, 76.8388771, color: Colors.green), ]; return markers; } Uri getStaticMap() { return staticMapProvider.getStaticUri(getMyLocation(), zoomLevel.toInt(), height: 400, width: 900); } Location getMyLocation() { return location; } CameraPosition getCamera() { return cameraPosition; } showMap(MapView mapView) { mapView.show( new MapOptions( mapViewType: MapViewType.normal, initialCameraPosition: getCamera(), showUserLocation: true, title: "Recent Location"), toolbarActions: [new ToolbarAction("Close", 1 )] ); mapView.zoomToFit(padding: 100); mapView.onMapReady.listen((_) { mapView.setMarkers(getMarker()); print("Map ready"); }); mapView.onLocationUpdated.listen((location) => updateLocation(location)); mapView.onTouchAnnotation.listen((marker) => print("marker tapped")); mapView.onMapTapped.listen((location) => updateLocation(location)); } updateLocation(Location location) { this.location = location; print("location changed $location"); } updateZoomLevel(double zoomLevel) { this.zoomLevel = zoomLevel; } }
in the above code snippet, we have created a method for markers and we have given some static location lat and long. When you tab on a static map. In the new window, dynamic google map visible. There you can see markers as well.

At the end, your project structure looks like: 


We hope that with this google map plugin you’ll be able to start using maps in your Flutter applications. We will continue to evolve this plugin to try to cover the expansive Google Maps API. If you have any issue to implement the above project. You can get the full source code from Github.


Source Code              


Flutter - How can draw route on google map between markers.


If you have any query regarding the above project feel free to ask it in the comment section below.




Share:

5 comments:

  1. Thank you for the tutorial.
    map_view does work on Android. Failed to compile. IOS works good.

    "The Android Gradle plugin supports only Kotlin Gradle plugin version 1.2.51 and higher. Project 'map_view' is using version 1.2.50."

    Is there any workaround or alternative map library?

    ReplyDelete
    Replies
    1. Yew, we have some alternative. like:

      1. https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter (Flutter Team Plugin)
      2. https://pub.dartlang.org/packages/mapbox_gl

      Delete
  2. "The Android Gradle plugin supports only Kotlin Gradle plugin version 1.2.51 and higher. Project 'map_view' is using version 1.2.50." How to solve this error??..

    ReplyDelete
    Replies
    1. For people having this issue.

      1. Open the Android project and go to the MapView module, then select MapViewPlugin.kt inside the java folder (This should be the file path: .pub-cache\hosted\pub.dartlang.org\map_view-0.0.14\android\src\main\kotlin\com\apptreesoftware\mapview)

      2. If you are using Android Studio you will already see red warnings. Go to line 168 where you'll find val cameraDict = mapOptions["cameraPosition"] as Map

      3. Change it to this val cameraDict = mapOptions!!["cameraPosition"] as Map

      Now it should work.

      Delete
  3. A problem occurred evaluating project ':app'.
    > Could not resolve all artifacts for configuration 'classpath'.
    > Could not find lint-gradle-api.jar (com.android.tools.lint:lint-gradle-api:26.1.2).
    Searched in the following locations:
    https://jcenter.bintray.com/com/android/tools/lint/lint-gradle-api/26.1.2/lint-gradle-api-26.1.2.jar

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

    * Get more help at https://help.gradle.org

    BUILD FAILED in 19s

    Finished with error: Please review your Gradle project setup in the android/ folder.

    ReplyDelete

WE'RE SOCIAL

Facebook Gruop

Promotional

  • Cover art Blend

    Blend app is very advanced app there are lots of features like shayari, status, chat, feed....

Categories