Flutter-geolocator: El futuro nunca se resuelve en IOS13

Creado en 29 abr. 2020  ·  63Comentarios  ·  Fuente: Baseflow/flutter-geolocator

🐛 Informe de error

Cuando intento getCurrentLocation, nunca se resuelve. No soy un experto en IOS, así que si me olvidé de hacer algo, explícamelo.

Future<Position> getCurrentPosition({
    LocationAccuracy accuracy = LocationAccuracy.best,
    GeolocationPermission geolocationPermission =
        GeolocationPermission.location,
  }) =>
      _geolocator.getCurrentPosition(
        desiredAccuracy: accuracy,
        locationPermissionLevel: geolocationPermission,
      );

Podfile:

config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',

        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
         'PERMISSION_LOCATION=1',
      ]

Info.plist:

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Need location when in use</string>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>Always and when in use!</string>
    <key>NSLocationUsageDescription</key>
    <string>Older devices need location.</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Can I haz location always?</string>

EDITAR:

Lo probé en un dispositivo Android real y el problema también está ocurriendo.

Mis permisos de ubicación de manifiesto:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Comportamiento esperado

Devolver una Posición.

Pasos de reproducción

Simplemente llame a geolocator.GetCurrentPosition.

Versión: 5.1.5.

Plataforma:

  • [x] :iphone: iOS (Probado con IOS Simulator)
  • [x] :robot: Android (Probado en un Xiomi Pocophone F1 con Android 10QkQ1.190828.002)
android ios triage

Comentario más útil

Hola a todos,

Me complace anunciar que (finalmente) lancé la versión 6.0.0-rc.1 que debería eliminar todos estos problemas.

Te agradecería mucho si pudieras probarlo y darme tu opinión.

Todos 63 comentarios

Estoy recibiendo el mismo error. Esto sucede tanto en iOS como en Android...

Recibo el mismo error en el simulador que ejecuta iOS 10.3 o iOS 13.4 y también en mi iPad con iOS 13.4 .

micódigo.dardo:

Position pos = await Geolocator()
              .getCurrentPosition(
                  locationPermissionLevel:
                      GeolocationPermission.locationWhenInUse,
                  desiredAccuracy: LocationAccuracy.high)

Info.plist:

<key>NSLocationAlwaysUsageDescription</key>
<string>Can I haz location always?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Need location when in use</string>

Versión: 5.3.1

Mismo problema para mí en Android 8.0. Considero escribir un temporizador de 10 segundos directamente en el código fuente que arroja si se alcanza.

@brenoasm , ¿está experimentando este problema en el simulador o en un dispositivo real?

@dammel En el simulador, es importante configurar el simulador para emitir una ubicación. Esto se puede hacer usando los siguientes elementos del menú de la aplicación del simulador: Funciones -> Ubicación -> (seleccione una opción que no sea "ninguna").

@mvanbeusekom ¿Qué sucede si un dispositivo real no emite una ubicación? No debería si el usuario hubiera apagado el GPS, ¿o sí?

@mvanbeusekom Lo probé en el Simulador para IOS (no tengo un iPhone para probarlo en un dispositivo real). Lo probé en un dispositivo Android real y tuve el mismo problema... Editaré y agregaré la información de mi dispositivo Android.

Tengo el mismo problema con un dispositivo Android real...

@mvanbeusekom Gracias por su ayuda. Su Tipp para los simuladores funcionó para mí.
No he cambiado nada, pero ahora está funcionando en el iPad (dispositivo real) nuevamente.

Probado en un simulador de iOS y un dispositivo iOS, no tuve ningún problema pero tengo el mismo problema en un emulador de Android

Voy a tratar de explicar mi caso en detalle.

Primero, el problema ocurre tanto en dispositivos Android como iPhone (estoy usando Testflight para probar la aplicación con mi equipo de control de calidad), pero también en Android Emulator y iOS Simulator.

El método 'getCurrentPosition' a veces no devuelve una posición, pero después de una sucesión de intentos sí lo hace. Normalmente tengo este problema cuando instalo la aplicación por primera vez. Después de un período de tiempo, de repente el método comienza a mostrarle la posición actual.

El problema de este problema es que no siempre sucede. Puede instalar la aplicación y, a veces, en el primer intento, el método devuelve la posición actual...

Notas adicionales:

  1. Si el método comienza a funcionar bien y realizo una recarga en caliente o un reinicio en caliente, el método continúa funcionando bien
  2. El método no lanza ninguna excepción... pero si pones un 'esperar' se detiene indefinidamente
  3. Intenté usar una versión anterior de Geolocator y el problema persiste
  4. Estoy usando Google Maps en mi proyecto, así que pensé "¿tal vez hay un conflicto con una versión reciente de Maps...?". No. Compilo con versiones antiguas de Google Maps y el problema persiste
  5. Lo curioso es que hace unas semanas no experimentaba este problema...

Mi entorno:

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Linux, locale en_GB.UTF-8)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Android Studio (version 3.6)
[✓] IntelliJ IDEA Community Edition (version 2019.3)
[✓] Connected device (2 available)

• No issues found!

Solución temporal en mi proyecto:

  1. Agregué un tiempo de espera al método 'getCurrentPosition', y si devuelve 'null', inicio un temporizador y lo intento una y otra vez... después de un tiempo (a veces segundos, a veces incluso un minuto) el método devuelve la posición actual
  2. Si necesito una posición inicial, uso el método 'getLastKnownPosition()'

Supongo que #375 y #386 están relacionados con este problema.

Mismo problema aquí, LG G6, Android 9.0.

Nunca resuelve.

Hay una manera extraña de cómo puedo hacer que funcione:
Comienzo la aplicación Google Maps para obtener la posición allí. Para eso necesito activar el sensor de posición y wifi (probablemente también funcionaría la conexión de datos móviles, no probada).
Así obtengo la posición en google maps.
Después de eso, también funciona en mi aplicación (sin importar si mi aplicación se inició después o ya se está ejecutando).
Si termino el wifi o apago la posición, entonces ya no funciona, incluso si los vuelvo a encender.

Cerrar Google Maps en cualquier momento, incluso antes de abrir mi aplicación, no importa (pero a veces tengo que abrir Google Maps más de una vez).
Me parece que Google Maps establece algo que persiste incluso después de que Maps está cerrado y que el geolocalizador necesita.

Editar/Corrección:
Es aún más complicado, el procedimiento con google maps funcionó con todos los argumentos para "desiredAccuracy", pero al cambiar de wifi había 2 categorías:

  • LocationAccuracy.best y LocationAccuracy.high seguían funcionando pero se volvieron más lentos
  • LocationAccuracy.medium, LocationAccuracy.lower y LocationAccuracy.lowest ya no se resolvieron, también con esos argumentos, el símbolo de ubicación en la barra de estado nunca se muestra.

Después de reiniciar, la ubicación del dispositivo ya no se resuelve. Así que necesito repetir la ubicación con Google Maps y luego vuelve a funcionar como se describe.

(Algo probablemente sin importancia, sin relación, después de una nueva instalación de la aplicación, el cuadro de diálogo de permiso se ve diferente, no tiene la casilla de verificación "No volver a preguntar", pero solo la primera vez que se muestra el cuadro de diálogo, después de eso siempre es el mismo diálogo con la casilla de verificación)

Mismo problema, Android 10, OnePlus 7 Pro.

El truco descrito anteriormente con Google Maps no funcionó para mí, pero de alguna manera, después de un tiempo, la ubicación comenzó a resolverse sin que yo hiciera nada específico. Estaba leyendo una página previamente abierta en el navegador, luego volví a mi aplicación y vi un cuadro de diálogo que me decía la ubicación: el cuadro de diálogo está configurado para mostrar cuándo se resuelve el futuro, por lo que finalmente se resolvió, pero tomó un tiempo . Después de eso, la ubicación se resolvió bien en cada intento.
Como se mencionó anteriormente, después de reiniciar, la ubicación ya no se resuelve.

En el simulador todo funciona bien.

Después del mensaje de @SchmadenSchmuki , realicé algunas pruebas en mi proyecto, y esta es mi conclusión: hay algo mal con el complemento de Google Maps que afecta el complemento Geolocator. Hay una incompatibilidad entre ellos.

Este es el flujo de mi aplicación cuando la inicio por primera vez:

  1. Muestra una pantalla de inicio
  2. Mientras tanto, la aplicación se conecta a una API para extraer datos del usuario.
  3. Uso Geolocator para ubicar la posición actual del usuario
  4. La aplicación sale de la pantalla de inicio y luego muestro un mapa que muestra dónde se encuentra el usuario

Con este flujo, la aplicación falla. El método 'getCurrentPosition()' de Geolocator falla, nunca devuelve un valor. NOTA: los métodos 'isLocationServiceEnabled()' y 'getLastKnownPosition()' funcionan bien.

PERO si cambio el flujo a:

  1. la pantalla de inicio
  2. Conéctese a la API para extraer datos de usuario
  3. Renderizar el mapa con una ubicación aleatoria
  4. Utilice Geolocator para localizar la posición actual del usuario
  5. Mover la cámara del mapa a la posición actual

¡¡¡¡¡FUNCIONA!!!!!

Entonces, mi conclusión es que, de alguna manera, el complemento de Google Maps ocupa "algo" que bloquea otros complementos para usar el servicio de geolocalización. Cuando Google Maps renderiza, libera ese "algo" y entonces todos pueden trabajar sin problema.

Si alguien más puede confirmar eso, podemos abrir un problema para que los chicos de Flutter vean esto.

@KnucklesEQ muchas gracias por los extensos informes. Comenzaré a depurar este problema y pasaré más tiempo reproduciendo y, con suerte, solucionando el problema. Sería muy útil si otros aquí pudieran verificar si todos ellos también usan el complemento de Google Maps.

Sin embargo, creo que hay varios problemas (diferencias entre Android 9 + Android 10, iOS a veces tarda muchos segundos en devolver una ubicación, usando Geolocator en combinación con Google Maps) y comenzaré a centrarme en todos ellos y veré si puedo. mejorar la situación. Sin embargo, esto llevará algún tiempo, así que tengan paciencia conmigo mientras hago lo mejor que puedo e intentaré dejar actualizaciones aquí sobre mi progreso.

No estoy usando el complemento Maps. He notado que cuando otorgo permiso solo mientras la aplicación se está ejecutando (ubicación cuando está en uso), la próxima vez que lo pida no se mostrará y nunca se resolverá (solo en Android, en IOS nunca funcionó desde que abrí este problema).

No estoy usando el complemento de Google Maps.

No usar el complemento de Google Maps tampoco.
(Al tener problemas, verifiqué si la aplicación de Google Maps también tiene problemas para obtener la ubicación y luego vi que obtener la ubicación allí tuvo un efecto en mi aplicación)

más detalles:
el problema ocurre cuando se cumplen las siguientes condiciones

  • estoy usando el administrador de ubicación (Geolocator().forceAndroidLocationManager = true)
  • estoy usando la precisión de ubicación predeterminada, que es LocationAccuracy.best
  • Estoy dentro

Lo rastreé a través del código y lo que sucede es que bajo las primeras 2 condiciones, el proveedor de ubicación que se elige es 'gps' y el dispositivo simplemente no puede captar la señal gps interna. Salí al balcón y casi de inmediato las cosas empezaron a funcionar con normalidad.

No intenté jugar con la precisión de la ubicación para ver cómo afecta la elección del proveedor de ubicación, pero sí intenté forzar al proveedor a "conectarse" (mediante codificación). Eso funciona, pero la precisión en la ubicación recuperada obviamente no fue muy buena: ~ 1080 metros.

@minusminuszero tiene razón, es lo mismo para mí.
Entonces, para mí, está haciendo lo que debería, también inmediatamente después de reiniciar, disculpe las molestias.
(No configuro el administrador de ubicación, por lo que es forceAndroidLocationManager = false en mi caso. Uso LocationAccuracy.best y supongo que también funcionaría con LocationAccuracy.high, probablemente no funcione para precisiones más bajas porque en estos casos el símbolo de ubicación no aparece en la barra de estado, pero ya hay un problema para eso).

También estoy experimentando lo anterior, con exactamente los mismos pasos para reproducir (estar dentro, ubicación predeterminada, etc.)

más detalles:
el problema ocurre cuando se cumplen las siguientes condiciones

  • estoy usando el administrador de ubicación (Geolocator().forceAndroidLocationManager = true)
  • estoy usando la precisión de ubicación predeterminada, que es LocationAccuracy.best
  • Estoy dentro

Lo rastreé a través del código y lo que sucede es que bajo las primeras 2 condiciones, el proveedor de ubicación que se elige es 'gps' y el dispositivo simplemente no puede captar la señal gps interna. Salí al balcón y casi de inmediato las cosas empezaron a funcionar con normalidad.

No intenté jugar con la precisión de la ubicación para ver cómo afecta la elección del proveedor de ubicación, pero sí intenté forzar al proveedor a "conectarse" (mediante codificación). Eso funciona, pero la precisión en la ubicación recuperada obviamente no fue muy buena: ~ 1080 metros.

¿Cómo hiciste para forzar la ubicación de "red"? Esto sería suficiente para mí en términos de solucionar el problema, ya que sucede en interiores al menos

¿Cómo hiciste para forzar la ubicación de "red"? Esto sería suficiente para mí en términos de solucionar el problema, ya que sucede en interiores al menos

Lo hice codificando el valor del proveedor de ubicación directamente en el código del complemento del geolocalizador. Supongo que elegir la baja precisión tendría el mismo efecto, pero no lo intenté.

Probablemente el método debería tener un parámetro de tiempo de espera, ¿no?

¿El equipo de Flutter/Geolocator está trabajando en este problema?

sí somos

¡Gracias @mvanbeusekom!
¿Sabes cuál es el origen del problema?
¿Ha encontrado una manera de eludirlo (o algún tipo de solución temporal)?
(bajar a 4.0.3 no lo resolvió para nosotros)

En el simulador es importante configurar el simulador para emitir una ubicación. Esto se puede hacer usando los siguientes elementos del menú de la aplicación del simulador: Funciones -> Ubicación -> (seleccione una opción que no sea "ninguna").

Eso solucionó el problema para mí. Pero es un error muy confuso ya que simplemente falla sin excepciones ni nada.

En el simulador es importante configurar el simulador para emitir una ubicación. Esto se puede hacer usando los siguientes elementos del menú de la aplicación del simulador: Funciones -> Ubicación -> (seleccione una opción que no sea "ninguna").

Eso solucionó el problema para mí. Pero es un error muy confuso ya que simplemente falla sin excepciones ni nada.

Sí, para mí también.
Agregue tiempo de espera en la solicitud de ubicación y genere una excepción en el simulador que no tiene una ubicación establecida.

Gracias :)

Tengo el mismo problema en iOS, también estoy usando el complemento de Google Maps.
Tengo una aplicación que usa getLocationStream pero no aparece un cuadro de diálogo de permiso hasta que voy a la pestaña donde tengo un mapa de Google.
Tengo otra aplicación en la que ya no usaba Google Maps, pero olvidé eliminar el complemento y tuve el mismo problema. Eliminé el complemento de Google Maps y ahora funciona correctamente.

¿Alguna actualización sobre esto?

Hola a todos, estoy trabajando duro en este problema. Básicamente, hemos decidido construir el geolocalizador desde cero y solucionar múltiples problemas a la vez.

Los puntos que se incluirán son:

  • Solucionar problemas de permisos;
  • Asegúrese de que el getCurrentLocation se recupere dentro de un tiempo razonable;
  • Agregue el tiempo de espera a los métodos getCurrentLocation y getPositionStream , de modo que si la adquisición de la ubicación demora más de lo esperado, la solicitud expirará y podrá reiniciarla;
  • Mejorar los posibles mensajes de error;
  • Mover a la estructura de complementos federados para que estemos listos para el soporte web;
  • Actualización al complemento de Android v2;

El primer paso a seguir fue sacar las funciones de geocodificación y alojarlas en su propio complemento (que ahora está disponible en pub.dev .

El segundo paso fue crear y probar unitariamente todo el código Dart necesario, que ahora está listo y se puede ver en la rama federated_plugin .

Los siguientes pasos son agregar implementaciones de iOS y Android y corregir la aplicación de ejemplo. Esto es en lo que estoy trabajando ahora, con suerte podré terminar todo en las próximas dos semanas (tenga en cuenta que también necesito hacer esto en mi tiempo libre ;)).

De todos modos, quiero agradecer a todos por su paciencia y sus comentarios, esperen un poco más.

@mvanbeusekom
Esas son buenas noticias. Me alegra que se tome el tiempo para proporcionarnos este complemento.

¡Un gran agradecimiento va para ti!

Espero las siguientes actualizaciones.

Gracias y un saludo

¡Agradable! Háganos saber cuando se publique para que podamos probar.

Para una solución temporal, puede verificar el estado en el dispositivo con el método GeolocationStatus checkGeolocationPermissionStatus() . Si la ubicación está desactivada, este método devuelve "deshabilitado". Entonces no necesita llamar al método getCurrentPosition() .

Ejemplo:

  Future<Position> getCurrentPosition() async {
    Position position;
    GeolocationStatus status = await _geolocator.checkGeolocationPermissionStatus(); 

    if (status != GeolocationStatus.disabled) {
      position = await _geolocator.getLastKnownPosition();

      if (position == null && status == GeolocationStatus.granted) {
        position = await _geolocator.getCurrentPosition(
          desiredAccuracy: LocationAccuracy.high,
          locationPermissionLevel: GeolocationPermission.locationWhenInUse,
        );
      }
    }

    return position;
  }

Pequeña actualización aquí, esta mañana he enviado una nueva actualización a la rama federated_plugin que incluye soporte completo en iOS, incluida una aplicación de ejemplo de Flutter.

También comenzamos a trabajar en Android, que admite la verificación del estado de los permisos, ahora implementaremos la solicitud de permisos y el manejo de los servicios de ubicación.

No dude en consultar el código o incluso intentar integrarlo en una aplicación de prueba y ejecutarlo en iOS. Tenga en cuenta que incluye una gran cantidad de cambios importantes que se documentarán. Por ahora, solo quería que todos supieran que hay progreso, aunque lleva algo de tiempo. Nuevamente gracias por toda su paciencia.

Pequeña actualización aquí, esta mañana he enviado una nueva actualización a la rama federated_plugin que incluye soporte completo en iOS, incluida una aplicación de ejemplo de Flutter.

También comenzamos a trabajar en Android, que admite la verificación del estado de los permisos, ahora implementaremos la solicitud de permisos y el manejo de los servicios de ubicación.

No dude en consultar el código o incluso intentar integrarlo en una aplicación de prueba y ejecutarlo en iOS. Tenga en cuenta que incluye una gran cantidad de cambios importantes que se documentarán. Por ahora, solo quería que todos supieran que hay progreso, aunque lleva algo de tiempo. Nuevamente gracias por toda su paciencia.

Gracias por trabajar duro en esto. ¿Actualizará el paquete geolocator en pub.dev con este cambio?

¿También es este el archivo para el ejemplo que mencionaste anteriormente: position_updates_example_widget.dart?

Gracias por trabajar duro en esto. ¿Actualizará el paquete geolocator en pub.dev con este cambio?

¿También es este el archivo para el ejemplo que mencionaste anteriormente: position_updates_example_widget.dart?

No, no publicaré en pub.dev por el momento. Esta es una reelaboración completa del complemento geolocalizador y aún no es compatible con Android. Una vez que Android y la documentación estén terminados, lo publicaré en pub.dev.

Sí, este widget es parte de la aplicación de ejemplo y demuestra cómo puede escuchar las actualizaciones de posición.

Hola,

Gracias por este paquete.

¿Alguna posibilidad de completar todas las tareas mencionadas anteriormente para Android en esta semana?

¿Algún avance en esto?

Solo esperando el retraso de la ubicación cuando se solicita por primera vez.

¿Alguna actualización sobre cuándo se lanzará la versión modificada? @mvanbeusekom

@dalmia007 , aún no tengo una fecha, pero se está avanzando. He agregado soporte rudimentario para Android en la rama feature/federated_android . Contiene la solicitud de permisos, la obtención de la última ubicación conocida, la ubicación actual y las actualizaciones de ubicación, todo utilizando el cliente del proveedor de ubicación fusionado (parte de Google Play Services).

Todavía estoy trabajando en lo siguiente:

Específico de Android:

  • Implementación de las funciones anteriores cuando los servicios de Google Play no están disponibles;
  • Resuelva automáticamente los problemas cuando los servicios de ubicación no estén habilitados;

General:

  • Actualizar la documentación

Siéntase libre de comprobarlo aquí

@mvanbeusekom ¡muchas gracias por la actualización! 👍

Hola a todos,

Me complace anunciar que (finalmente) lancé la versión 6.0.0-rc.1 que debería eliminar todos estos problemas.

Te agradecería mucho si pudieras probarlo y darme tu opinión.

Lamento decir esto, pero se bloqueó dos veces, lo suficiente como para volver a 4.0.3 ya.

E/AndroidRuntime(19881): java.lang.RuntimeException: Failure delivering result ResultInfo{who=<strong i="6">@android</strong>:requestPermissions:, request=24, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.packagename.consumer.app/com.packagename.consumer.app.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.baseflow.geolocator.permission.PermissionResultCallback.onResult(com.baseflow.geolocator.permission.LocationPermission)' on a null object reference

Ocurrió cuando presioné Permitir otorgar en el cuadro de diálogo y también cuando presioné Denegar. Avísame si me perdí algo.

@Dohmanlechx solo para asegurarme, ¿obtuviste esto en 6.0.0-rc.x o en la versión 5.3.2?

Obtuve esto en 6.0.0-rc.1 (el IDE me pidió que "actualizara" a 5.3.2+2 , FYI)

@Dohmanlechx gracias a sus comentarios, encontré un problema. Aparentemente, en su caso, el geolocalizador está recibiendo comentarios de otro complemento (supongo que está usando el controlador de permisos para manejar los permisos desde el código de solicitud == 24, que es lo mismo que el controlador de permisos) que intenta procesar, lo que obviamente falla. En estos casos, el geolocalizador simplemente debe ignorar esos mensajes ya que no pertenecen al geolocalizador. Arreglaré esto hoy y lanzaré una nueva versión candidata.

¡Gracias por tus comentarios!

Oh, de hecho, estamos usando permission_handler . ¡Buen descubrimiento!

Todos los créditos son para ti @Dohmanlechx ;). Gracias a sus comentarios, pude descubrir este error y pronto podré lanzar una nueva versión.

@Dohmanlechx Acabo de lanzar la versión 6.0.0-rc.3 que debería corregir el error que experimentó.

Muy bueno, probado cuidadosamente en el emulador de Android, otorgando y denegando, manipulando la ubicación, funcionó perfectamente. También funcionó bien en mi dispositivo Android real.

Pero no se muestra ninguna solicitud del sistema para el simulador de iOS, ¿supongo que está previsto? Sin embargo, al menos no se bloqueará y la aplicación funciona como se desea sin ninguna ubicación disponible. Desafortunadamente, todavía no puedo probar en mi iPhone debido a un problema de conexión con Xcode y no quiero implementar una compilación en TestFlight solo para probar ahora. Te avisaré tan pronto como lo haya probado en iPhone.

Pero hasta ahora, todo bien!

¡Muchas gracias por las extensas pruebas @Dohmanlechx , es muy apreciado!

De hecho, el complemento no muestra una solicitud de servicio en iOS, ya que no hay una API (pública) para hacerlo. La única opción que tenemos aquí es mostrar manualmente al usuario un mensaje explicando cómo actualizar la configuración manualmente. Tenemos una opción para redirigir al usuario a la aplicación Configuración (llamando a los métodos openAppSettings() o openLocationSettings() ). He documentado esto más detalladamente en el archivo README.md .

Lamento informar esto, pero funcionó como un desastre en mi iPhone XS Max, OS 13.6.1.

La primera vez que buscó la posición funcionó igual que la versión anterior, devolvió la posición correcta pero aún tomó 7-8 segundos.

Pero a partir de la segunda vez y más, siguió lanzando al instante. Tuve que cambiar de Exception err a dynamic err debido a:
_ Excepción no controlada: el tipo '_TypeError' no es un subtipo del tipo 'Exception' _.

Los obtengo cuando falla (después de la primera vez que los busqué):

2020-08-26 14:01:45.670206+0200 Runner[4565:206487] aleteo: no se pudo recuperar la ubicación: mal estado: ningún elemento
2020-08-26 14: 01: 45.670416 + 0200 Runner [4565: 206487] aleteo: no se pudo obtener la ubicación: instancia de 'NoLocationFoundException'

( NoLocationFoundException es mi clase personalizada)

_Bad state: No element_ no dice mucho desafortunadamente... debajo está mi código:

static Future<void> _getUserLocation({bool isSneaky = false}) async {

  void _throw(dynamic err) {
    print("Could not fetch location: $err");
    if (!isSneaky) Fluttertoast.showToast(msg: getTranslation("location_fetch_error"));
    throw NoLocationFoundException();
  }

  await GeolocatorPlatform.instance
      .getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high,
        timeLimit: const Duration(seconds: _TIMEOUT_DELAY),
      )
      .then((position) => _userLatestPosition = position)
      .catchError(
    (err) {
      // Debug only, remove later
      Fluttertoast.showToast(msg: "error: $err");

      if (err is TimeoutException) {
        GeolocatorPlatform.instance.getLastKnownPosition().then((position) {
          if (position == null) _throw(err);
          return position;
        }, onError: (err) {
          _throw(err);
        });
      } else if (err is PermissionDeniedException) {
        XxlPermissionsHandler.request(Permission.location);
      } else {
        _throw(err);
      }
    },
  ).catchError((err) => _throw(err));
}

Espero sinceramente que puedas reproducir esto en tu iPhone.

@Dohmanlechx , gracias por los extensos comentarios, creo que encontré el problema aquí. Ahora necesito encontrar una buena manera de solucionarlo;)

En resumen, el método getCurrentPosition llama a getPositionStream y toma el primer elemento y luego cierra la transmisión. El problema es que getPositionStream tiene un código como este:

    if (_positionStream != null) {
      return _positionStream;
    }

Lo que puede adivinar causa la excepción Bad state: No element cuando llama a getCurrentPosition por segunda vez, porque llamará a first en una transmisión ya cerrada. Estaré trabajando en esto y lanzaré un nuevo candidato pronto.

@Dohmanlechx , el problema donde obtiene el "Estado incorrecto: ningún elemento" debería haberse solucionado en 6.0.0-rc.4 que acabo de publicar. No pude reproducir el problema, pero pude asegurarme de que el getCurrentPosition usará una nueva transmisión cuando lo llame por segunda vez (y en cualquier subsiguiente).

Te lo agradecería mucho si puedes intentarlo de nuevo y me avisas si funciona.

Lo que noté es que usas directamente el GeolocatorPlatform.instance.<some_method> , al hacer esto estás pasando cualquier lógica que se encuentra en el paquete geolocator y vas directamente a la implementación predeterminada que está en el geolocator_platform_instance paquete. Por ahora no hay una implementación específica en el paquete geolocator pero es mejor no pasarlo por alto.

Si importa el paquete geolocator, debería poder llamar directamente a los métodos globales, por ejemplo:

import 'package:geolocator/geolocator.dart';

final position = await getCurrentPosition();

Si se encuentra con colisiones o simplemente le gusta prefijar los métodos globales, puede agregar un alias a la importación, así:

import 'package:geolocator/geolocator.dart' as geolocator;

final position = await geolocator.getCurrentPosition();

Gracias, también cambié el código de acuerdo con sus sugerencias.

El accidente se ha ido ahora, pero desafortunadamente, todavía es demasiado inestable. 3 de cada 10 veces es extremadamente rápido (realmente desearía que fuera 10 de cada 10 veces), pero 7 de cada 10 veces supera el límite de tiempo (10 segundos) y la función falla. ¿Probaste en tu iPhone, enviando spam al getCurrentPosition() ? Probé en iPhone XS Max, OS 13.6.1.

_4.0.3_ es lento pero estable
_6.0.0-rc.4_ es rápido pero inestable

Pero no se preocupe, esto está completamente bien y no es un desastre para nosotros, especialmente porque escribí mi propio límite de tiempo para la versión 4.0.3.

@Dohmanlechx me alegra saber que se resolvió el bloqueo, eso es algo al menos;)

Estoy realmente interesado en saber por qué sigues recibiendo actualizaciones lentas ya que no puedo reproducirlas. Creé una aplicación de demostración muy simple para probarla:

dardo principal:

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  <strong i="10">@override</strong>
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Position> _positions = <Position>[];

  <strong i="11">@override</strong>
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        body: ListView.builder(
          itemCount: _positions.length,
          itemBuilder: (BuildContext context, int index) {
            return ListTile(title: Text(_positions[index].toString()),);
          },),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () => getCurrentPosition().then((position) {
            setState(() {
              _positions.add(position);
            });
          }),
        ),
      ),
    );
  }
}

Info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>$(DEVELOPMENT_LANGUAGE)</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>geolocator_issue</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>$(FLUTTER_BUILD_NAME)</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleVersion</key>
    <string>$(FLUTTER_BUILD_NUMBER)</string>
    <key>LSRequiresIPhoneOS</key>
    <true/>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIMainStoryboardFile</key>
    <string>Main</string>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>The example App requires access to the device's location.</string>
</dict>
</plist>

Entonces, cada vez que presiono el botón de acción flotante, se llama getCurrentPosition y el resultado se agrega a ListView . Probé esta aplicación en mi iPhone 7 personal, el iPhone 6 de mi esposa y el simulador (todos con la última versión de iOS), pero puedo enviar spam al botón y la ubicación se devuelve casi de inmediato. Estoy realmente desconcertado por qué tienes una experiencia diferente. ¿Tal vez pueda probar este código de muestra y ver si todavía tiene el mismo problema?

Realmente admiro tu persistencia. Creé un nuevo proyecto y usé sus códigos, casi rompí la pantalla del iPhone al enviar spam al botón, la ubicación regresaba de inmediato todo el tiempo. ¡Increíble! Mañana intentaré encontrar tiempo para solucionar problemas en nuestro código, comenzando con ejecutar getCurrentPosition() directamente en el Widget y luego moverlo más y más lejos hasta su lugar previsto para encontrar al culpable. Sospecho que es por el complemento de permisos, pero ya veremos.

Gracias por los comentarios y las amables palabras, realmente lo aprecio. Me esforcé mucho en reconstruir el geolocalizador y este problema fue el que realmente me hizo decidir comenzarlo, así que me gustaría que fuera bueno esta vez ;)

Por favor, hágame saber cómo va y si puedo ayudar.

getCurrentPosition().then((position) {
   print(position);
}).catchError((err) {
   print(err);
});

Probé esto directamente en el Widget y cada vez que hacía clic, ¡se registraba una ubicación en la consola! Así que definitivamente es nuestro código. Ahora depende de nosotros, ¡gracias por todo!

Sin embargo, esto _a veces_ sucede al buscar la posición:

I/flutter (  393): ══╡ EXCEPTION CAUGHT BY SERVICES LIBRARY ╞══════════════════════════════════════════════════════════
I/flutter (  393): The following PlatformException was thrown while de-activating platform stream on channel
I/flutter (  393): flutter.baseflow.com/geolocator_updates:
I/flutter (  393): PlatformException(error, No active stream to cancel, null)
I/flutter (  393): 
I/flutter (  393): When the exception was thrown, this was the stack:
I/flutter (  393): #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:572:7)
I/flutter (  393): #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:161:18)
I/flutter (  393): <asynchronous suspension>
I/flutter (  393): #2      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:334:12)
I/flutter (  393): #3      EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:554:29)
I/flutter (  393): #4      EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:551:18)
I/flutter (  393): #18     MethodChannelGeolocator.getPositionStream.<anonymous closure> (package:geolocator_platform_interface/src/implementations/method_channel_geolocator.dart:135:13)
I/flutter (  393): (elided 24 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
I/flutter (  393): ════════════════════════════════════════════════════════════════════════════════════════════════════

@mvanbeusekom No puedo obtener el puesto en absoluto con la versión 6.0.0+1 más reciente. Probado en el simulador de iOS, emulador de Android API 29, OnePlus 6 físico. El tiempo de espera se lanza cada vez.

image

image

No sé qué más puedo agregar aquí para ayudarlo a encontrar el problema, getCurrentPosition devuelve el tiempo de espera o simplemente se bloquea si no se especifica el parámetro timeLimit . He probado diferentes precisiones de ubicación. ¿Alguien tiene éste problema?

La versión 5.3.2+2 funciona bien en el simulador de iOS (con la ubicación personalizada especificada), el dispositivo real de Android y el emulador de Android

@mvanbeusekom , he leído todo esto y estoy actualizando a la última versión para solucionar el problema de retraso de 10 segundos.

Tal vez me estoy perdiendo algo, pero hay algo que ya no puedo hacer en la nueva versión (geocodificación).
Solía ​​​​poder configurar manualmente una Posición en el centro de la ciudad (en caso de que el usuario niegue la ubicación), haciendo lo siguiente:

Position userLocation;
List<Placemark> listAddresses = [];
if(permission.toString() != "PermissionStatus.granted"){
        listAddresses = await placemarkFromAddress("$city, $state");
         userLocation = listAddresses[0].position;
    }else{
getCurrentPosition...
}

Ahora, parece que _placemarkFromAddress_ se ha cambiado a _ locationFromAddress _, así que traté de adaptarme haciendo los siguientes cambios en mi fórmula:

Position userLocation;
List<Location> listAddresses = [];
if(permission.toString() != "PermissionStatus.granted"){
        listAddresses = await locationFromAddress("$city, $state");
         userLocation = listAddresses[0].position;
    }else{
getCurrentPosition...
}

Pero estoy recibiendo el siguiente error:

A value type 'Location' can't be assigned to a variable of type 'Position'.

¿Cómo puedo convertir la ubicación en Posición o, en última instancia, en caso de que el usuario niegue la ubicación, cómo puedo ahora establecer su Posición en el centro de su ciudad?

Gracias.

Actualicé a la última versión, me solucionó el problema 👍👍👍

¿Fue útil esta página
0 / 5 - 0 calificaciones