skip to Main Content

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

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 to know more

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search