I am trying to embed native android
view of google map in my flutter
app. I know we already have google_map_plugin
on pub.dev
but to improve myself as a developer i am trying to integrate native android code in my flutter app
Here is my dart code
const myGoogleMapView = 'myGoogleMapView';
class MyGoogleMapView extends StatelessWidget {
const MyGoogleMapView({super.key});
@override
Widget build(BuildContext context) {
return Platform.isAndroid
? const AndroidView(
viewType: myGoogleMapView,
layoutDirection: TextDirection.ltr,
creationParams: null,
creationParamsCodec: StandardMessageCodec(),
)
: const UiKitView(
viewType: myGoogleMapView,
layoutDirection: TextDirection.ltr,
creationParams: null,
creationParamsCodec: StandardMessageCodec(),
);
}
}
Next on the android side i added my apikey in manifest
and internet permission as well
In MainActivity.kt
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine
.platformViewsController
.registry
.registerViewFactory("myGoogleMapView", MyGoogleMapViewFactory(this))
}
}
Then i created MyGoogleMapViewFactory
& MyGoogleMapView
class MyGoogleMapViewFactory(private val activity: FlutterActivity) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val creationParams = args as Map<String?, Any?>?
return MyGoogleMapView(context, viewId, creationParams,activity)
}
}
class MyGoogleMapView(context: Context, id: Int, creationParams: Map<String?, Any?>?,activity: FlutterActivity) :
PlatformView, OnMapReadyCallback {
private val mapview: MapView = MapView(context)
private var loadedCallbackPending = false
private var mMap: GoogleMap? = null
private var currentMarker: Marker? = null
override fun getView(): View {
return mapview
}
override fun dispose() {}
init {
val layoutParams: ViewGroup.LayoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
mapview.layoutParams = layoutParams
mapview.onCreate(null)
mapview.getMapAsync(this)
}
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
val myLocation = LatLng(37.7749, -122.4194)
if (currentMarker != null) {
currentMarker?.remove()
}
currentMarker = mMap?.addMarker(
MarkerOptions().position(myLocation).title("Marker Title")
)
mMap?.moveCamera(CameraUpdateFactory.newLatLngZoom(myLocation, 10f))
}
private fun invalidateMapIfNeeded() {
if (mMap == null || loadedCallbackPending) {
return
}
loadedCallbackPending = true
mMap!!.setOnMapLoadedCallback {
loadedCallbackPending = false
postFrameCallback {
postFrameCallback {
mapview.invalidate()
}
}
}
}
private fun postFrameCallback(f: Runnable) {
Choreographer.getInstance().postFrameCallback { f.run() }
}
}
I just see an empty google map with my marker on it. I am 100% sure my apikey is correct as i am using the same one with same package name in my native android
application & it works fine
I also checked the google map plugin’s code on github
and they had written invalidateMapIfNeeded
which i copy pasted and tried calling it in different places like init
, onMapReady
etc but didn’t work for me
Also i tried to use Hybrid
composition on dart side as well
return PlatformViewLink(
viewType: myGoogleMapView,
surfaceFactory: (context, controller) {
return AndroidViewSurface(
controller: controller as AndroidViewController,
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
);
},
onCreatePlatformView: (params) {
return PlatformViewsService.initSurfaceAndroidView(
id: params.id,
viewType: myGoogleMapView,
layoutDirection: TextDirection.ltr,
creationParams: null,
creationParamsCodec: const StandardMessageCodec(),
onFocus: () {
params.onFocusChanged(true);
},
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
},
);
but this also does not work. when i try to use simple views like TextView
or EditText
from native android side then it works fine. Not sure what is the problem with google map
Logs are here as i was excedding the text limit
Output
One more thing i noticed is when i run the app for first time the gooogle map is empty like i showed above but if i keep doing hot reload multiple times the map starts showing up slowly. Check this video to know more
2
Answers
This behavior could be caused by a variety of factors, and debugging it may require some investigation. Here are some steps you can take to diagnose and resolve the issue:
Network Connection: Ensure that your device or emulator has an active network connection when you run the app. Google Maps requires an internet connection to load maps.
Initialization: Confirm that you are initializing the Google Maps component correctly in your code. You should typically do this in the onMapCreated callback if you’re using the GoogleMap widget in Flutter.
Error Handling: Implement error handling for Google Maps initialization. Check for any error messages or exceptions thrown during map initialization and display them in your app’s UI or log them for debugging purposes.
Logs and Debugging: Use the developer tools and logs to gather more information about what might be causing the issue. Look for any error messages or warnings related to the Google Maps component in your logs.
State Management: Ensure that the state management in your Flutter app is correctly set up. In some cases, hot reloading may help "fix" the issue by reinitializing the state.
Dependencies: Check your project’s dependencies and ensure that they are up to date, especially any packages related to maps or location services.
Rebuild Process: Understand how hot reloading and rebuilding work in Flutter. It’s possible that rebuilding the app multiple times somehow triggers the correct initialization process for the map.
Plugin Compatibility: Ensure that the Flutter plugin you are using for Google Maps is compatible with your Flutter version. Sometimes, compatibility issues can lead to unexpected behavior.
Caching: Check if there’s any caching of map data or initialization happening after multiple hot reloads that might be causing the map to display.
Testing on Different Devices: Try running your app on different devices or emulators to see if the issue is specific to a particular environment.
This error seems to be related with the Google Maps APi from google console and authorizations. Did you placed the SHa-1 in and restricted the API? I remember geting this kind of error once.