[FIX] Android Custom Map no funciona en Xamarin.Forms 2.3.4

Como informáticos, siempre debemos estar preparados para el cambio, y Xamarin.Forms no es la excepción.

Luego de los últimos updates a Xamarin.Forms, la implementación de MapRenderer cambió un poco. Este cambio ha resultado un tanto molesto para algunos, ya que, si teníamos un Custom Renderer de mapas en Xamarin.Forms y actualizábamos a la última versión (ahora 2.3.4) algunas cosas podían dejar de funcionar mágicamente en Android al implementar IOnMapReadyCallback en nuestro renderer.

Este fue mi caso hace un par de días cuando andaba preparando un prototipo ligero de una app. La explicación a este problema la encontré en nuestro viejo amigo StackOverFlow (ver la respuesta completa).

El problema

Si nos dirigimos al código fuente de MapRenderer, podremos ver que dicha clase ahora ya implementa IOnMapReadyCallback. Es por esta razón que ya no se hace necesario reimplementar dicha interfaz en nuestro renderer; de lo contrario, podríamos causar conflictos como los que me tocaron a mí.

Como parte de los cambios, ahora también podemos obtener la instancia de nuestro GoogleMap a través de la propiedad NativeMap, por lo cual tampoco será necesario guardarla en una variable dentro de nuestro renderer.

Solución

Para este caso, he encontrado 2 salidas: refactorizar el código del renderer para adaptarlo a la nueva implementación, o simplemente realizar un pequeño hack que describiré a continuación.

Opción 1: Hack simple

La solución más rápida que hizo funcionar mi código sin tocar absolutamente nada fue agregar el siguiente método en mi renderer:

Y llamarlo en la primera línea de nuestro método OnMapReady. De esta forma:

Si tienes mucho apuro, esta puede ser una salida fácil al problema, aunque personalmente recomendaría ir por la opción 2.

Opción 2: Adaptar el código de nuestro renderer

Las soluciones podrán variar dependiendo cada caso, pero a continuación describiré puntos a tomar en cuenta para refactorizar el código exitosamente.

  1. Dejaremos de hacer que nuestra clase renderer implemente la interfaz IOnMapReadyCallback.
  2. Ya no se hará necesaria la sentencia Control?.GetMapAsync(this).
  3. El método OnMapReady que se ejecutaba por la llamada de IOnMapReadyCallBack quedará sin efecto, por lo tanto...
  4. El código que colocábamos en dicho método habrá que ponerlo en otro lado. En mi caso, ahora lo llamo desde OnElementPropertyChanged.
  5. Podemos quitar nuestra variable local GoogleMap map, y reemplazarla por la propiedad heredada NativeMap.

Precaución: Hay que tener cuidado al usar NativeMap, ya que al principio puede ser null.

Mi clase renderer con esta solución quedó así:

Este ejemplo es para detectar clics en el mapa, pero, repito, puede variar según el caso.

Ejemplo vivo

Subí a Github el proyecto completo de esta solución. Al principio apliqué la solución 1 (puedes revisar los commits), pero ahora logré refactorizarlo y hacer que todo funcione normalmente con la solución 2.
Por cierto, pueden contribuir al proyecto si desean :D.

MapApp

Eso es todo

Queda a criterio de cada uno la solución que se le dé a este problema, pero espero que les sirva este granito de arena de mi parte. Si tienen alguna otra solución interesante, ¡por favor, compártanmela!

¡Saludos!