androidfluttergoogle-mapsgoogle-maps-android-api-2

Google Map displays with empty location even with valid api key in flutter when app is launched and works properly when i do multiple hot reload


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

enter image description here

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


Solution

  • Just add mapview.onResume() in onMapReady. You don't need the invalidation code