Skip to content

TLocationSensor, gran error en Delphi 11, solución en Delphi 11.1?

Si estás desarrollando aplicaciones que utilizan el sensor de geolocación en Delphi 11, te habrás dado cuenta del gran error que posee esta versión.

El componente TLocationSensor no funciona en Android 11 ni en Android 12.

Son variados los tipos de errores que podemos ver en los diferentes dispositivos, desde no activar el componente y devolver la Latitud y Longitud en NAN, hasta creshear la App al querer utilizar dicho componente.

El error que he detectado a través del Monitor es el siguiente:

JNI DETECTED ERROR IN APPLICATION: can't call double android.location.Location.getLatitude() on instance of java.util.ArrayList
    in call to CallDoubleMethodA
    from java.lang.Object com.embarcadero.rtl.ProxyInterface.dispatchToNative(java.lang.String, java.lang.Object[], long)

Delphi 11 y el Parche Noviembre 21

En el mes de noviembre, cuando se largo el segundo parche para Delphi 11, creíamos que tendríamos la solución, pero no fué así, y hasta el día de escribir este artículo no la encontramos.

Solución? Delphi 11.1

Muchos desarrolladores en Delphi estamos buscando una solución fiable, pero parece que, hasta el momento, no la hay. ¿ Se solucionará con la llegada de Delphi 11.1 ? Aún hay que esperar un tiempo que solo Embarcadero sabe.

En la web de Embarcadero, en el apartado de informes de errores, Marc Schwarzkopf publicó una posible solución que no a todos funciona, en mi caso, me funcionó pero solo en Android 12, tengo una gran cantidad de dispositivos con Android 11 que aún no me funciona dicho componente.

Para llevar a cabo esta posible solución debemos:

  • Copiar los archivos Androidapi.JNI.Location.pas y System.Android.Sensors.pas a la carpeta del proyecto
  • Modificar el archivo Androidapi.JNI.Location.pas copiado a la carpeta del proyecto adaptando la interfaz “JLocationListener” de la siguiente manera:
  JLocationListener = interface(IJavaInstance)
    ['{D1CF3FB5-3BCB-4959-98D7-BD4D8F93D839}']
    procedure onLocationChanged(location: JObject); cdecl;
    procedure onProviderDisabled(provider: JString); cdecl;
    procedure onProviderEnabled(provider: JString); cdecl;
    procedure onStatusChanged(provider: JString; status: Integer; extras: JBundle); cdecl;
  end;
  • Y modificar la clase “TLocationListener” en el archivo System.Android.Sensors.pas de la siguiente manera:
  TLocationListener = class(TJavaLocal, JLocationListener)
  private
    FLocationSensor: TUIAndroidLocationSensor;
  public
    constructor Create(ALocationSensor: TUIAndroidLocationSensor);
    procedure onLocationChanged(P1: JObject); overload; cdecl;
    procedure onLocationChanged(P1: JLocation); overload; cdecl;
    procedure onLocationChanged(P1: JArrayList); overload; cdecl;
    procedure onStatusChanged(P1: JString; P2: Integer; P3: JBundle); cdecl;
    procedure onProviderEnabled(P1: JString); cdecl;
    procedure onProviderDisabled(P1: JString); cdecl;
  end;
  • Finalmente, añadiremos los siguientes procedimientos:
  procedure TUIAndroidLocationSensor.TLocationListener.onLocationChanged(P1: JObject);
  begin
    if TJNIResolver.IsInstanceOf(P1, TJArrayList.GetClsID) then
      onLocationChanged(TJArrayList.Wrap(P1))
    else if TJNIResolver.IsInstanceOf(P1, TJLocation.GetClsID) then
      onLocationChanged(TJLocation.Wrap(P1));
  end;
 
  procedure TUIAndroidLocationSensor.TLocationListener.onLocationChanged(P1: JArrayList);
  begin
    onLocationChanged(TJLocation.Wrap(P1.get(P1.size-1)))
  end;
  • Agregar ambos archivos al proyecto y compilar.

Esta solución la he probado y me funciona solo en Android 12, no en Android 11 como figura en la publicación.

Cuanto tiempo deberemos esperar para Delphi 11.1 ?