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][1] 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][3] to know more
Just add mapview.onResume()
in onMapReady. You don't need the invalidation code