Flutter-geolocator: Futuro nunca resolve no IOS13

Criado em 29 abr. 2020  ·  63Comentários  ·  Fonte: Baseflow/flutter-geolocator

🐛 Relatório de bugs

Quando tento getCurrentLocation, ele nunca resolve. Eu não sou especialista em IOS, então, por favor, se eu esqueci de fazer alguma coisa, apenas me explique.

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:

Eu testei em um dispositivo Android real e o problema está acontecendo também.

Minhas permissões de localização do manifesto:

    <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" />

Comportamento esperado

Retornar uma posição.

Etapas de reprodução

Basta chamar geolocator.GetCurrentPosition.

Versão: 5.1.5.

Plataforma:

  • [x] :iphone: iOS (Testado com IOS Simulator)
  • [x] :robot: Android (Testado em um Xiomi Pocophone F1 com Android 10QkQ1.190828.002)
android ios triage

Comentários muito úteis

Oi pessoal,

Estou feliz em anunciar que eu (finalmente) lancei a versão 6.0.0-rc.1 que deve eliminar todos esses problemas.

Eu realmente apreciaria se você pudesse experimentá-lo e me dar seu feedback.

Todos 63 comentários

Estou recebendo o mesmo erro. Isso está acontecendo tanto no iOS quanto no Android.....

Estou recebendo o mesmo erro no simulador executando iOS 10.3 ou iOS 13.4 e também no meu iPad com iOS 13.4 .

meucódigo.dart:

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>

Versão: 5.3.1

Mesmo problema para mim no Android 8.0. Eu considero escrever um temporizador de 10 segundos diretamente no código-fonte que é lançado se for alcançado.

@brenoasm você está enfrentando esse problema no simulador ou em um dispositivo real?

@dammel No simulador é importante configurar o simulador para emitir uma localização. Isso pode ser feito usando os seguintes itens de menu do aplicativo do simulador: Recursos -> Localização -> (selecione uma opção diferente de "nenhum").

@mvanbeusekom E se um dispositivo real não emitir uma localização? Não deveria se o usuário tivesse desligado o GPS, deveria?

@mvanbeusekom Testei no Simulador para IOS (não tenho IPhone para testar em um dispositivo real). Eu testei em um dispositivo Android real e tive o mesmo problema... Vou editar e adicionar as informações do meu dispositivo Android.

Eu tenho o mesmo problema com o dispositivo Android real ...

@mvanbeusekom Obrigado pela sua ajuda. Seu Tipp para os simuladores funcionou para mim.
Não mudei nada, mas agora está funcionando no iPad (dispositivo real) novamente.

Testado em um simulador iOS e um dispositivo iOS, não tive nenhum problema, mas tenho o mesmo problema em um emulador Android

Vou tentar explicar o meu caso em detalhes.

Primeiro, o problema ocorre em dispositivos Android e iPhone (estou usando o Testflight para testar o aplicativo com minha equipe de controle de qualidade), mas também no Android Emulator e no iOS Simulator.

O método 'getCurrentPosition' às vezes não retorna uma posição, mas após uma sucessão de tentativas retorna. Geralmente tenho esse problema quando instalo o aplicativo pela primeira vez. Após um período de tempo, de repente o método começa a trazer a posição atual.

O problema dessa questão é que nem sempre acontece. Você pode instalar o app, e as vezes na primeira tentativa o método retorna a posição atual...

Notas extras:

  1. Se o método começar a funcionar bem e eu fizer uma recarga a quente ou uma reinicialização a quente, o método continua funcionando bem
  2. O método não lança nenhuma exceção ... mas se você colocar um 'await' ele para indefinidamente
  3. Tentei usar uma versão mais antiga do Geolocator e o problema persiste
  4. Estou usando o Google Maps no meu projeto, então pensei "talvez haja um conflito com uma versão recente do Maps...?". Não. Eu compilo com versões antigas do Google Maps e o problema persiste
  5. O curioso é que algumas semanas atrás eu não experimentei esse problema ...

Meu ambiente:

$ 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!

Solução temporária no meu projeto:

  1. Eu adicionei um tempo limite ao método 'getCurrentPosition', e se ele retornar 'null' eu inicio um cronômetro e tento de novo e de novo ... depois de um tempo (às vezes segundos, às vezes até um minuto) o método retorna a posição atual
  2. Se eu precisar de uma posição inicial, eu uso o método 'getLastKnownPosition()'

Acho que #375 e #386 estão relacionados a esse problema

Mesmo problema aqui, LG G6, Android 9.0.

Nunca resolve.

Existe uma maneira estranha de fazer isso funcionar:
Eu começo o aplicativo do Google Maps para obter a posição lá. Para isso preciso ativar o positionsensor e wifi (provavelmente mobil dataconnection também funcionaria, não testado).
Então eu recebo a posição no google maps.
Depois disso, ele também funciona no meu aplicativo (não importa se o meu aplicativo foi iniciado depois ou já está em execução).
Se eu encerrar o wifi ou desligar a posição, ele não funcionará mais, mesmo que eu os ligue novamente.

Fechar o google maps a qualquer momento, mesmo antes de meu aplicativo ser aberto, não importa (mas às vezes eu tenho que abrir o google maps mais de uma vez).
Parece-me que o google maps estabelece algo que persiste mesmo depois que os mapas são fechados e que é necessário pelo geolocator.

Editar/Correção:
É ainda mais complicado, o procedimento com o google maps funcionou com todos os argumentos para "desiredAccuracy", mas ao trocar o wifi havia 2 categorias:

  • LocationAccuracy.best e LocationAccuracy.high ainda estavam funcionando, mas ficaram mais lentos
  • LocationAccuracy.medium, LocationAccuracy.lower e LocationAccuracy.lowest não resolveram mais, também com esses argumentos o símbolo de localização na barra de status nunca é mostrado.

Depois de reiniciar o local do dispositivo não resolve mais. Então eu preciso repetir a localização com o google maps e depois funciona novamente conforme descrito.

(Algo provavelmente sem importância, não relacionado, após uma nova instalação do aplicativo a caixa de diálogo de permissão fica diferente, não tem a caixa de seleção "Não perguntar novamente", mas apenas na primeira vez que a caixa de diálogo é exibida, depois disso é sempre a caixa de seleção mesma caixa de diálogo com a caixa de seleção)

Mesmo problema, Android 10, OnePlus 7 Pro.

O truque descrito acima com o google maps não funcionou para mim, mas de alguma forma, depois de algum tempo, o local começou a resolver sem que eu fizesse nada específico. eu estava lendo uma página aberta anteriormente no navegador, depois voltei para o meu aplicativo e vi uma caixa de diálogo que me dizia a localização - a caixa de diálogo está configurada para mostrar quando o futuro resolver, então, eventualmente, resolveu, mas demorou um pouco . Depois disso, o local estava resolvendo bem em todas as tentativas.
Como mencionado acima, após a reinicialização, o local não resolve mais.

No simulador tudo funciona bem.

Após a mensagem do @SchmadenSchmuki , fiz alguns testes no meu projeto, e esta é a minha conclusão: Há algo errado com o Plugin do Google Maps que afeta o plugin Geolocator. Há uma incompatibilidade entre eles.

Este é o fluxo do meu aplicativo quando o inicio pela primeira vez:

  1. Ele mostra uma tela inicial
  2. Enquanto isso, o aplicativo se conecta a uma API para extrair dados do usuário
  3. Eu uso o Geolocator para localizar a posição atual do usuário
  4. O aplicativo sai da tela inicial e, em seguida, mostro um mapa mostrando onde o usuário está localizado

Com esse fluxo, o aplicativo falha. O método 'getCurrentPosition()' do Geolocator falha, ele nunca retorna um valor. NOTA: os métodos 'isLocationServiceEnabled()' e 'getLastKnownPosition()' funcionam bem.

MAS se eu alterar o fluxo para:

  1. A tela inicial
  2. Conecte-se à API para extrair dados do usuário
  3. Renderize o mapa com um local aleatório
  4. Use Geolocator para localizar a posição atual do usuário
  5. Mova a câmera do mapa para a posição atual

FUNCIONA!!!!!

Então, minha conclusão é que, de alguma forma, o plugin do Google Maps ocupa "algo" que bloqueia outros plugins para usar o serviço de geolocalização. Quando o Google Maps renderiza, ele libera esse "algo" e então todos podem trabalhar sem problemas.

Se alguém puder confirmar isso, podemos abrir um problema para o pessoal do Flutter para ver isso

@KnucklesEQ muito obrigado pela extensa reportagem. Vou começar a depurar esse problema e passar mais tempo reproduzindo e, esperançosamente, corrigindo o problema. Seria muito útil se outros aqui pudessem verificar se todos também estão usando o plug-in do Google Maps?

No entanto, acho que existem vários problemas (diferenças entre Android 9 + Android 10, iOS às vezes leva muitos segundos para retornar um local, usando o Geolocator em combinação com o Google Maps) e vou começar a focar em todos eles e ver se consigo melhorar a situação. Isso levará algum tempo, então, por favor, tenha paciência comigo enquanto eu faço o meu melhor e tentarei deixar atualizações aqui sobre meu progresso.

Não estou usando o plug-in do Maps. Percebi que quando dou permissão apenas enquanto o aplicativo está em execução (locationWhenInUse), na próxima vez que eu perguntar, ele não será exibido e nunca resolve (somente Android, no IOS Nunca funcionou desde que abri esse problema).

Não estou usando o plug-in do Google Maps.

Também não está usando o plug-in do Google Maps.
(Ao ter problemas verifiquei se o aplicativo do google maps também tem problemas para obter a localização e então vi que obter a localização teve efeito no meu aplicativo)

mais detalhes:
o problema ocorre quando as seguintes condições são verdadeiras

  • estou usando o gerenciador de localização (Geolocator().forceAndroidLocationManager = true)
  • estou usando a precisão de localização padrão, que é LocationAccuracy.best
  • eu estou dentro

Eu o rastreei através do código e o que acontece é que, nas 2 primeiras condições, o provedor de localização escolhido é 'gps' e o dispositivo simplesmente não consegue pegar o sinal de gps dentro. Saí para a varanda e quase imediatamente as coisas começaram a funcionar normalmente.

Eu não tentei brincar com a precisão da localização para ver como isso afeta a escolha do provedor de localização, mas tentei apenas forçar o provedor a 'rede' (por codificação). Isso funciona, mas a precisão no local recuperado obviamente não era muito boa - ~1080 metros.

@minusminuszero está certo, é o mesmo para mim.
Então, para mim, está fazendo o que deveria, também imediatamente após a reinicialização, desculpe os inconvenientes.
(Eu não configuro o gerenciador de localização, então é forceAndroidLocationManager = false no meu caso. Eu uso LocationAccuracy.best e acho que também funcionaria com LocationAccuracy.high, provavelmente não funciona para precisões mais baixas porque nesses casos o símbolo de localização não aparece na barra de status, mas já existe um problema para isso.)

Estou experimentando o acima também, com exatamente os mesmos passos para reproduzir (estar dentro, localização padrão acc, etc)

mais detalhes:
o problema ocorre quando as seguintes condições são verdadeiras

  • estou usando o gerenciador de localização (Geolocator().forceAndroidLocationManager = true)
  • estou usando a precisão de localização padrão, que é LocationAccuracy.best
  • eu estou dentro

Eu o rastreei através do código e o que acontece é que, nas 2 primeiras condições, o provedor de localização escolhido é 'gps' e o dispositivo simplesmente não consegue pegar o sinal de gps dentro. Saí para a varanda e quase imediatamente as coisas começaram a funcionar normalmente.

Eu não tentei brincar com a precisão da localização para ver como isso afeta a escolha do provedor de localização, mas tentei apenas forçar o provedor a 'rede' (por codificação). Isso funciona, mas a precisão no local recuperado obviamente não era muito boa - ~1080 metros.

Como você fez para forçar a localização da "rede"? Isso seria suficiente para mim em termos de corrigir o problema, pois acontece em ambientes fechados, pelo menos

Como você fez para forçar a localização da "rede"? Isso seria suficiente para mim em termos de corrigir o problema, pois acontece em ambientes fechados, pelo menos

Fiz isso codificando o valor do provedor de localização diretamente no código do plug-in do geolocalizador. Suponho que escolher a baixa precisão teria o mesmo efeito, mas não tentei.

Provavelmente o método deveria ter um parâmetro de tempo limite, não?

A equipe do Flutter/Geolocator está trabalhando nesse problema?

sim, nós somos

Obrigado @mvanbeusekom!
Você sabe qual é a origem do problema?
Você encontrou uma maneira de ignorá-lo (ou algum tipo de solução temporária)?
(rebaixar para 4.0.3 não resolveu para nós)

No simulador é importante configurar o simulador para emitir uma localização. Isso pode ser feito usando os seguintes itens de menu do aplicativo do simulador: Recursos -> Localização -> (selecione uma opção diferente de "nenhum").

Isso resolveu o problema para mim. Mas é um bug muito confuso, pois simplesmente falha sem exceções ou qualquer coisa.

No simulador é importante configurar o simulador para emitir uma localização. Isso pode ser feito usando os seguintes itens de menu do aplicativo do simulador: Recursos -> Localização -> (selecione uma opção diferente de "nenhum").

Isso resolveu o problema para mim. Mas é um bug muito confuso, pois simplesmente falha sem exceções ou qualquer coisa.

Sim, para mim também.
Por favor, adicione tempo limite na solicitação de localização e lance uma exceção no simulador que não tem localização definida.

Obrigado :)

Estou com o mesmo problema no iOS, também estou usando o plugin do google maps.
Eu tenho um aplicativo que usa getLocationStream, mas não recebo uma caixa de diálogo de permissão até entrar na guia onde tenho um mapa do google.
Eu tenho outro aplicativo onde não usei mais o google maps mas esqueci de remover o plugin e tive o mesmo problema. Eu removi o plugin do Google Maps e agora está funcionando corretamente.

Alguma atualização sobre isso?

Olá a todos, estou trabalhando duro neste problema. Basicamente, decidimos construir o geolocalizador do zero e corrigir vários problemas de uma só vez.

Os pontos que serão incluídos são:

  • Corrigir problemas de permissão;
  • Certifique-se de que o getCurrentLocation seja recuperado dentro de um tempo razoável;
  • Adicione tempo limite aos métodos getCurrentLocation e getPositionStream , para que, se a aquisição do local demorar mais do que o esperado, a solicitação atingirá o tempo limite e você poderá reiniciar a solicitação;
  • Melhorar mensagens de erro em potencial;
  • Mude para a estrutura de plugins federados para que estejamos prontos para suporte na web;
  • Atualização para o plug-in Android v2;

O primeiro passo a tomar foi remover os recursos de geocodificação e hospedá-los em seu próprio plugin (que agora está disponível em pub.dev .

A segunda etapa foi criar e testar a unidade de todo o código Dart necessário, que agora está pronto e pode ser visualizado na ramificação federated_plugin .

As próximas etapas são adicionar implementações de iOS e Android e corrigir o aplicativo de exemplo. É nisso que estou trabalhando agora, espero conseguir terminar tudo nas próximas duas semanas (lembre-se de que também preciso fazer isso no tempo livre ;)).

De qualquer forma, quero agradecer a todos pela paciência e feedback, por favor, esperem um pouco mais.

@mvanbeusekom
Isso é uma boa notícia. Fico feliz que você esteja dedicando seu tempo para nos fornecer este plug-in.

Um grande obrigado vai para você!

Aguardo as seguintes atualizações.

Obrigado e cumprimentos

Agradável! Avise-nos quando for lançado para que possamos testar.

Para uma solução temporária, você pode verificar o status no dispositivo com o método GeolocationStatus checkGeolocationPermissionStatus() . Se o local estiver desativado, esse método retornará "desativado". Então você não precisa chamar o método getCurrentPosition() .

Exemplo:

  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;
  }

Pequena atualização aqui, esta manhã eu enviei uma nova atualização para o branch federated_plugin que inclui suporte total no iOS, incluindo um aplicativo de exemplo Flutter.

Também começamos a trabalhar no Android, que oferece suporte à verificação do status das permissões, implementaremos a solicitação de permissões e o tratamento dos serviços de localização agora.

Fique a vontade para conferir o código ou até mesmo tentar integrá-lo em um aplicativo de teste e rodar no iOS. Observe que inclui muitas alterações importantes que serão documentadas. Por enquanto, eu só queria que todos soubessem que há progresso, embora leve algum tempo. Mais uma vez obrigado por toda a sua paciência.

Pequena atualização aqui, esta manhã eu enviei uma nova atualização para o branch federated_plugin que inclui suporte total no iOS, incluindo um aplicativo de exemplo Flutter.

Também começamos a trabalhar no Android, que oferece suporte à verificação do status das permissões, implementaremos a solicitação de permissões e o tratamento dos serviços de localização agora.

Fique a vontade para conferir o código ou até mesmo tentar integrá-lo em um aplicativo de teste e rodar no iOS. Observe que inclui muitas alterações importantes que serão documentadas. Por enquanto, eu só queria que todos soubessem que há progresso, embora leve algum tempo. Mais uma vez obrigado por toda a sua paciência.

Obrigado por trabalhar duro nisso. Você atualizará o pacote geolocator em pub.dev com essa alteração?

Este também é o arquivo para o exemplo que você mencionou acima: position_updates_example_widget.dart?

Obrigado por trabalhar duro nisso. Você atualizará o pacote geolocator em pub.dev com essa alteração?

Este também é o arquivo para o exemplo que você mencionou acima: position_updates_example_widget.dart?

Não, ainda não publicarei no pub.dev. Este é um retrabalho completo do plugin geolocator e ainda não suporta Android. Assim que o Android e a documentação estiverem concluídos, eu o liberarei no pub.dev.

Sim, este widget faz parte do aplicativo de exemplo e demonstra como você pode ouvir atualizações de posição.

Oi,

Obrigado por este pacote.

Alguma chance de completar todas as tarefas acima mencionadas para Android nesta semana?

alguma atualização disso?

Apenas aguardando o atraso da localização quando solicitado pela primeira vez.

Alguma atualização sobre quando a versão reformulada será lançada? @mvanbeusekom

@dalmia007 , ainda não tenho uma data, mas o progresso está sendo feito. Adicionei suporte rudimentar para Android no branch feature/federated_android . Ele contém a solicitação de permissões, obtenção da última localização conhecida, obtenção da localização atual e atualizações de localização, tudo usando o cliente do provedor de localização fundido (parte do Google Play Services).

Ainda estou trabalhando no seguinte:

Específico do Android:

  • Implementação dos recursos acima quando o Google Play Services não estiver disponível;
  • Resolver problemas automaticamente quando os serviços de localização não estão ativados;

Em geral:

  • Atualize a documentação

Fique a vontade para conferir aqui

@mvanbeusekom muito obrigado pela atualização! 👍

Oi pessoal,

Estou feliz em anunciar que eu (finalmente) lancei a versão 6.0.0-rc.1 que deve eliminar todos esses problemas.

Eu realmente apreciaria se você pudesse experimentá-lo e me dar seu feedback.

Lamento dizer isso, mas caiu duas vezes agora, o suficiente para reverter para 4.0.3 já.

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

Aconteceu quando pressionei permitir conceder na caixa de diálogo e também quando pressionei negar. Deixe-me saber se eu perdi alguma coisa.

@Dohmanlechx apenas certificando-se, você conseguiu isso no 6.0.0-rc.x ou na versão 5.3.2?

Eu consegui isso em 6.0.0-rc.1 (o IDE me pediu para "atualizar" para 5.3.2+2 , FYI)

@Dohmanlechx, graças ao seu feedback, encontrei um problema. Aparentemente, no seu caso, o geolocalizador está recebendo feedback de outro plugin (suponho que você esteja usando o permission_handler para lidar com permissões desde o requestCode == 24, que é o mesmo que o permission_handler) que ele tenta processar, o que obviamente falha. Nesses casos, o geolocalizador deve simplesmente ignorar essas mensagens, pois elas não pertencem ao geolocalizador. Vou corrigir isso hoje e lançar um novo candidato a lançamento.

Obrigado pelo seu feedback!

Ah, de fato, estamos usando permission_handler . Bom achado!

Todos os créditos vão para você @Dohmanlechx ;). Graças ao seu feedback, consegui descobrir esse bug e poderei lançar uma nova versão em breve.

@Dohmanlechx Acabei de lançar a versão 6.0.0-rc.3 que deve corrigir o bug que você experimentou.

Muito legal, testado cuidadosamente no Android Emulator, concedendo e negando, manipulando a localização, funcionou perfeitamente. Funcionou bem no meu dispositivo Android real também.

Mas nenhuma solicitação do sistema está sendo exibida para o iOS Simulator, acho que é intencional? No entanto, pelo menos não travará e o aplicativo funcionará como desejado sem nenhum local disponível. Infelizmente ainda não consigo testar no meu iPhone devido ao problema de conexão do Xcode e não quero implantar uma compilação no TestFlight apenas para testar agora. Avisarei assim que testar no iPhone.

Mas até aí tudo bem!

Muito obrigado pelo extenso teste @Dohmanlechx , é muito apreciado!

O plugin realmente não mostra uma solicitação de serviço no iOS, pois não há API (pública) para fazê-lo. A única opção que temos aqui é mostrar manualmente ao usuário uma mensagem explicando como atualizar as configurações manualmente. Temos uma opção para redirecionar o usuário para o aplicativo Configurações (chamando os métodos openAppSettings() ou openLocationSettings() ). Documentei isso mais detalhadamente no arquivo README.md .

Lamento informar isso, mas funcionou como um desastre no meu iPhone XS Max, OS 13.6.1.

A primeira vez que busca a posição funcionou exatamente como a versão antiga, retornou a posição correta, mas ainda levou de 7 a 8 segundos.

Mas a partir da segunda vez em diante, continuou jogando instantaneamente. Tive que mudar de Exception err para dynamic err devido a:
_ Exceção não tratada: o tipo '_TypeError' não é um subtipo do tipo 'Exception' _.

Estou recebendo aqueles quando está falhando (após a primeira busca):

2020-08-26 14:01:45.670206+0200 Runner[4565:206487] flutter: não foi possível buscar o local: estado incorreto: sem elemento
2020-08-26 14:01:45.670416+0200 Runner[4565:206487] flutter: não foi possível buscar o local: instância de 'NoLocationFoundException'

( NoLocationFoundException é minha classe personalizada)

_Bad state: No element_ não está dizendo muito infelizmente... abaixo está meu 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 você possa reproduzir isso no seu iPhone.

@Dohmanlechx , obrigado pelo extenso feedback, acho que encontrei o problema aqui. Agora preciso encontrar uma boa maneira de corrigi-lo;)

Resumindo, o método getCurrentPosition chama o getPositionStream e pega o primeiro elemento e então fecha o stream. O problema é que o getPositionStream tem código assim:

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

O que você pode adivinhar causa a exceção Bad state: No element ao chamar o getCurrentPosition pela segunda vez, porque ele estará chamando first em um fluxo já fechado. Estarei trabalhando nisso e lançarei um novo candidato em breve.

@Dohmanlechx , você emite onde obtém o "Bad state: No element" deveria ter sido corrigido em 6.0.0-rc.4 que acabei de publicar. Não consegui reproduzir o problema, mas consegui garantir que o getCurrentPosition usará um novo fluxo quando você o chamar uma segunda vez (e qualquer subsequente).

Eu realmente aprecio se você pode dar-lhe outra tentativa e deixe-me saber se funciona.

O que notei é que você usa diretamente o GeolocatorPlatform.instance.<some_method> , fazendo isso você está passando qualquer lógica que esteja localizada no pacote geolocator e vá direto para a implementação padrão que está no geolocator_platform_instance pacote. Por enquanto não há implementação específica no pacote geolocator mas ainda é melhor não ignorá-lo.

Se você importar o pacote geolocator, poderá chamar diretamente os métodos globais, por exemplo:

import 'package:geolocator/geolocator.dart';

final position = await getCurrentPosition();

Se você se deparar com colisões ou simplesmente quiser prefixar os métodos globais, você pode adicionar um alias à importação, assim:

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

final position = await geolocator.getCurrentPosition();

Obrigado, também alterei o código de acordo com suas sugestões.

O crash já passou, mas infelizmente ainda está muito instável. 3 em cada 10 vezes é extremamente rápido (realmente gostaria que fosse 10 em cada 10 vezes), mas 7 em cada 10 vezes o Limite de Tempo (10 segundos) excede e a função é lançada. Você testou no seu iPhone, enviando spam a getCurrentPosition() ? Testei no iPhone XS Max, OS 13.6.1.

_4.0.3_ é lento, mas estável
_6.0.0-rc.4_ é rápido, mas instável

Mas não se preocupe, está tudo bem e absolutamente nenhum desastre para nós, especialmente porque eu escrevi o próprio limite de tempo para a versão 4.0.3.

@Dohmanlechx feliz em saber que a falha foi resolvida, isso é algo pelo menos;)

Estou realmente interessado em saber por que você ainda está recebendo atualizações lentas, pois não consigo reproduzi-las. Eu criei um aplicativo de demonstração muito simples para experimentá-lo:

main.dart:

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>

Então, toda vez que eu pressiono o botão de ação flutuante getCurrentPosition é chamado e o resultado é adicionado ao ListView . Eu testei este aplicativo no meu iPhone 7 pessoal, no iPhone 6 da minha esposa e no simulador (todos executando a versão mais recente do iOS), mas posso enviar spam ao botão e a localização é retornada quase imediatamente. Estou realmente intrigado por que você tem uma experiência diferente. Talvez você possa testar este código de exemplo e ver se ainda tem o mesmo problema?

Admiro muito sua persistência. Criei um novo projeto e usei seus códigos, quase quebrei a tela do iPhone mandando spam no botão, a localização retornou imediatamente o tempo todo. Impressionante! Amanhã tentarei encontrar tempo para solucionar problemas em nosso código, começando com a execução de getCurrentPosition() diretamente no Widget e depois afastá-lo cada vez mais até o local pretendido para encontrar o culpado. Eu suspeito que seja por causa do plugin de permissões, mas vamos ver.

Obrigado pelo feedback e pelas palavras gentis, muito obrigado. Eu me esforcei bastante na reconstrução do geolocalizador e esse problema foi o que realmente me fez decidir iniciá-lo, então gostaria muito que fosse bom dessa vez ;)

Por favor, deixe-me saber como vai e se eu puder ajudar.

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

Tentei isso diretamente no Widget e toda vez que clicava, um local era logado no console! Então é definitivamente o nosso código. Então é por nossa conta agora, obrigado por tudo!

No entanto, isso _às vezes_ acontece ao buscar a posição:

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 Não consigo obter a posição usando a versão 6.0.0+1 mais recente. Tentei no simulador iOS, API do emulador Android 29, OnePlus 6 físico. O tempo limite é lançado todas as vezes.

image

image

Não sei o que mais posso adicionar aqui para ajudá-lo a encontrar o problema, getCurrentPosition retorna o tempo limite ou apenas trava se o parâmetro timeLimit não for especificado. Eu tentei diferentes precisões de localização. Alguém tem este problema?

A versão 5.3.2+2 funciona bem no simulador iOS (com o local personalizado especificado), dispositivo real Android e emulador Android

@mvanbeusekom , li tudo isso e estou atualizando para a versão mais recente para corrigir o problema de atraso de 10 segundos.

Talvez esteja faltando alguma coisa, mas há algo que não posso mais fazer na nova versão (geocodificação).
Eu costumava definir manualmente uma posição para o centro da cidade (caso o usuário negasse a localização), fazendo o seguinte:

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

Agora, parece que _placemarkFromAddress_ foi alterado para _locationFromAddress_ , então tentei me adaptar fazendo as seguintes alterações na minha fórmula:

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

Mas estou recebendo o seguinte erro:

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

Como posso converter a localização em Posição ou, em última análise, caso o usuário negue a localização, como posso agora definir sua Posição para o centro da cidade?

Obrigado.

Atualizei para a versão mais recente, corrigi o problema para mim 👍👍👍

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

jaumard picture jaumard  ·  3Comentários

shrishti08 picture shrishti08  ·  3Comentários

long1eu picture long1eu  ·  4Comentários

seakmengc picture seakmengc  ·  3Comentários

Sammius picture Sammius  ·  4Comentários