Flutter-geolocator: Будущее никогда не решается на IOS13

Созданный на 29 апр. 2020  ·  63Комментарии  ·  Источник: Baseflow/flutter-geolocator

🐛 Отчет об ошибке

Когда я пытаюсь получитьCurrentLocation, он никогда не разрешается. Я не эксперт по IOS, так что если я что-то забыл сделать, просто объясните мне.

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

Подфайл:

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

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

Информация.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>

РЕДАКТИРОВАТЬ:

Я проверил на реальном устройстве Android, и проблема тоже возникает.

Мои разрешения на местоположение манифеста:

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

Ожидаемое поведение

Вернуть позицию.

Шаги воспроизведения

Просто вызовите geolocator.GetCurrentPosition.

Версия: 5.1.5.

Платформа:

  • [x] :iphone: iOS (протестировано с помощью симулятора IOS)
  • [x] :robot: Android (Проверено на Xiomi Pocophone F1 с Android 10QkQ1.190828.002)
android ios triage

Самый полезный комментарий

Привет всем,

Я рад объявить о выпуске (наконец-то) версии 6.0.0-rc.1 , которая должна избавиться от всех этих проблем.

Я был бы очень признателен, если бы вы могли попробовать и дать мне свой отзыв.

Все 63 Комментарий

Я получаю ту же ошибку. Это происходит как на iOS, так и на Android.....

Я получаю ту же ошибку на симуляторе под управлением iOS 10.3 или iOS 13.4 , а также на своем iPad с iOS 13.4 .

мой код.дарт:

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

Информация.plist:

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

Версия: 5.3.1

Та же проблема у меня на Android 8.0. Я рассматриваю возможность написания 10-секундного таймера непосредственно в исходном коде, который срабатывает при достижении.

@brenoasm у вас возникла эта проблема на симуляторе или на реальном устройстве?

@dammel В симуляторе важно настроить симулятор для определения местоположения. Это можно сделать с помощью следующих пунктов меню приложения-симулятора: Функции -> Местоположение -> (выберите вариант, отличный от «нет»).

@mvanbeusekom Что делать, если реальное устройство не определяет местоположение? Не должно, если пользователь выключил GPS, не так ли?

@mvanbeusekom Я тестировал на Симуляторе для IOS (у меня нет IPhone, чтобы протестировать его на реальном устройстве). Я протестировал его на реальном устройстве Android и столкнулся с той же проблемой... Я отредактирую и добавлю информацию об устройстве Android.

У меня такая же проблема с реальным устройством Android...

@mvanbeusekom Спасибо за помощь. Ваш совет по тренажерам у меня сработал.
Я ничего не менял, но теперь он снова работает на iPad (на реальном устройстве).

Протестировано на симуляторе iOS и устройстве iOS, у меня не было проблем, но у меня такая же проблема на эмуляторе Android.

Постараюсь подробно описать свой случай.

Во-первых, проблема возникает как на устройствах Android, так и на iPhone (я использую Testflight для тестирования приложения с моей командой контроля качества), а также в эмуляторе Android и симуляторе iOS.

Метод getCurrentPosition иногда не возвращает позицию, но после серии попыток возвращает. У меня обычно такая проблема возникает, когда я устанавливаю приложение в первый раз. Через какое-то время метод внезапно начинает приносить вам текущую позицию.

Проблема этого вопроса в том, что это происходит не всегда. Вы можете установить приложение, и иногда с первого раза метод возвращает текущую позицию...

Дополнительные примечания:

  1. Если метод начинает работать хорошо, и я делаю горячую перезагрузку или горячий перезапуск, метод продолжает работать хорошо
  2. Метод не генерирует никаких исключений... но если вы нажмете "ожидание", он остановится на неопределенный срок.
  3. Я пытался использовать более старую версию Геолокатора, и проблема осталась
  4. Я использую Карты Google в своем проекте, поэтому я подумал: «Может быть, есть конфликт с последней версией Карт…?». Неа. Я компилирую со старыми версиями Google Maps, и проблема сохраняется
  5. Любопытно, что несколько недель назад я не сталкивался с этой проблемой...

Моя среда:

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

Временное решение в моем проекте:

  1. Я добавил тайм-аут в метод getCurrentPosition, и если он возвращает 'null', я запускаю таймер и пробую снова и снова... через некоторое время (иногда секунды, иногда даже минуту) метод возвращает текущую позицию
  2. Если мне нужна начальная позиция, я использую метод getLastKnownPosition().

Я предполагаю, что #375 и #386 связаны с этой проблемой

Та же проблема, LG G6, Android 9.0.

Никогда не решает.

Есть странный способ заставить его работать:
Я запускаю приложение Google Maps, чтобы получить там позицию. Для этого мне нужно активировать датчик положения и Wi-Fi (вероятно, мобильное соединение для передачи данных также будет работать, не проверялось).
Таким образом, я получаю позицию в картах Google.
После этого он также работает в моем приложении (независимо от того, было ли мое приложение запущено позже или уже запущено).
Если я отключу Wi-Fi или выключу позицию, она больше не работает, даже если я включу их снова.

Закрытие карт Google в любое время, даже до открытия моего приложения, не имеет значения (но иногда мне приходится открывать карты Google более одного раза).
Мне кажется, что карты Google устанавливают что-то, что сохраняется даже после закрытия карт и что нужно геолокатору.

Изменить/исправление:
Еще сложнее, процедура с гугл картами работала со всеми аргументами для "желаемой точности", но при переключении вайфая было 2 категории:

  • LocationAccuracy.best и LocationAccuracy.high все еще работали, но стали медленнее
  • LocationAccuracy.medium, LocationAccuracy.lower и LocationAccuracy.lowest больше не разрешались, также с этими аргументами символ местоположения в строке состояния никогда не отображается.

После перезагрузки местоположение устройства больше не определяется. Поэтому мне нужно повторить получение местоположения с помощью карт Google, а затем оно снова работает, как описано.

(Что-то, вероятно, неважное, не связанное, после новой установки приложения диалог разрешений выглядит по-другому, не имеет флажка «Больше не спрашивать», а только при первом показе диалога, после этого всегда тот же диалог с флажком)

Та же проблема, Android 10, OnePlus 7 Pro.

Вышеописанный трюк с гугл картами у меня не сработал, но как-то через какое-то время локация начала определяться без моих действий. я просто читал ранее открытую страницу в браузере, затем снова переключился на свое приложение и увидел диалоговое окно, в котором мне было указано местоположение - диалоговое окно настроено так, чтобы показывать, когда будущее разрешится, поэтому в конце концов оно разрешилось, но это заняло некоторое время. . После этого местоположение определялось нормально при каждой попытке.
Как упоминалось выше, после перезагрузки местоположение больше не определяется.

На симуляторе все работает просто отлично.

После сообщения @SchmadenSchmuki я провел несколько тестов в своем проекте, и вот мой вывод: что-то не так с плагином Google Maps, который влияет на плагин Geolocator. Между ними несовместимость.

Это поток моего приложения, когда я запускаю его в первый раз:

  1. Он показывает заставку
  2. Тем временем приложение подключается к API для извлечения пользовательских данных.
  3. Я использую Geolocator для определения текущего положения пользователя
  4. Приложение закрывает заставку, а затем я показываю карту, показывающую, где находится пользователь.

С этим потоком приложение не работает. Метод «getCurrentPosition()» Geolocator не работает, он никогда не возвращает значение. ПРИМЕЧАНИЕ: методы isLocationServiceEnabled() и getLastKnownPosition() работают нормально.

НО, если я изменю поток на:

  1. Заставка
  2. Подключитесь к API, чтобы получить пользовательские данные
  3. Рендеринг карты со случайным местоположением
  4. Используйте геолокатор, чтобы определить текущее положение пользователя
  5. Переместите камеру карты в текущую позицию

ОНО РАБОТАЕТ!!!!!

Итак, мой вывод заключается в том, что плагин Google Maps каким-то образом занимает «что-то», что блокирует другие плагины для использования службы геолокации. Когда Карты Google визуализируются, это «что-то» освобождается, и тогда все могут работать без проблем.

Если кто-то еще может подтвердить это, мы можем открыть проблему для ребят из Flutter, чтобы увидеть это.

@KnucklesEQ большое спасибо за подробный отчет. Я начну отлаживать эту проблему и потрачу больше времени на воспроизведение и, надеюсь, исправление проблемы. Было бы очень полезно, если бы другие здесь могли проверить, все ли они также используют плагин Google Maps?

Тем не менее, я думаю, что есть несколько проблем (различия между Android 9 и Android 10, iOS иногда требуется много секунд, чтобы вернуть местоположение, используя Geolocator в сочетании с Google Maps), и я начну сосредотачиваться на всех них и посмотреть, смогу ли я улучшить ситуацию. Это займет некоторое время, поэтому, пожалуйста, потерпите меня, пока я делаю все возможное, и постараюсь оставлять здесь обновления о моем прогрессе.

Я не использую плагин Карт. Я заметил, что когда я даю разрешение только во время работы приложения (locationWhenInUse), в следующий раз, когда я спрашиваю, оно не будет отображаться и никогда не разрешается (только для Android, в IOS это никогда не работало с тех пор, как я открыл эту проблему).

Я не использую плагин Google Maps.

Плагин Google Maps также не используется.
(При возникновении проблем я проверил, есть ли у приложения Google Maps проблемы с определением местоположения, а затем я увидел, что получение местоположения повлияло на мое приложение)

подробнее:
проблема возникает, когда выполняются следующие условия

  • я использую диспетчер местоположения (Geolocator().forceAndroidLocationManager = true)
  • я использую точность определения местоположения по умолчанию, то есть LocationAccuracy.best
  • я внутри

я проследил это через код, и что происходит, так это то, что при первых двух условиях выбирается провайдер определения местоположения «gps», и устройство просто не может поймать сигнал gps внутри. Я вышел на балкон, и почти сразу все заработало нормально.

Я не пытался играть с точностью местоположения, чтобы увидеть, как это влияет на выбор провайдера определения местоположения, но я попытался просто заставить провайдера «подключиться к сети» (путем жесткого кодирования). Это работает, но точность полученного местоположения, очевидно, была не очень хорошей - ~ 1080 метров.

@minusminuszero прав, у меня то же самое.
Так что для меня он делает то, что должен, также сразу после перезагрузки, извините за неудобства.
(Я не устанавливаю диспетчер местоположения, поэтому в моем случае это forceAndroidLocationManager = false. Я использую LocationAccuracy.best и предполагаю, что он также будет работать с LocationAccuracy.high, вероятно, не работает для более низкой точности, потому что в этих случаях символ местоположения не отображается в строке состояния, но для этого уже есть проблема.)

Я также испытываю вышеизложенное, с точно такими же шагами для воспроизведения (нахождение внутри, местоположение по умолчанию и т. Д.)

подробнее:
проблема возникает, когда выполняются следующие условия

  • я использую диспетчер местоположения (Geolocator().forceAndroidLocationManager = true)
  • я использую точность определения местоположения по умолчанию, то есть LocationAccuracy.best
  • я внутри

я проследил это через код, и что происходит, так это то, что при первых двух условиях выбирается провайдер определения местоположения «gps», и устройство просто не может поймать сигнал gps внутри. Я вышел на балкон, и почти сразу все заработало нормально.

Я не пытался играть с точностью местоположения, чтобы увидеть, как это влияет на выбор провайдера определения местоположения, но я попытался просто заставить провайдера «подключиться к сети» (путем жесткого кодирования). Это работает, но точность полученного местоположения, очевидно, была не очень хорошей - ~ 1080 метров.

Как вы собирались форсировать «сетевое» местоположение? Этого было бы достаточно для меня с точки зрения решения проблемы, так как это происходит, по крайней мере, в помещении.

Как вы собирались форсировать «сетевое» местоположение? Этого было бы достаточно для меня с точки зрения решения проблемы, так как это происходит, по крайней мере, в помещении.

Я сделал это, жестко запрограммировав значение для поставщика местоположения непосредственно в коде плагина геолокации. Я полагаю, что выбор низкой точности будет иметь тот же эффект, но я не пробовал.

Вероятно, метод должен иметь параметр тайм-аута, нет?

Команда Flutter/Geolocator работает над этой проблемой?

Да, мы

Спасибо @mvanbeusekom!
Вы знаете, в чем источник проблемы?
Вы нашли способ обойти это (или какое-то временное решение)?
(понижение до 4.0.3 не помогло нам)

В симуляторе важно настроить симулятор на выделение местоположения. Это можно сделать с помощью следующих пунктов меню приложения-симулятора: Функции -> Местоположение -> (выберите вариант, отличный от «нет»).

Это решило проблему для меня. Но это очень запутанная ошибка, поскольку она просто терпит неудачу без каких-либо исключений или чего-то еще.

В симуляторе важно настроить симулятор на выделение местоположения. Это можно сделать с помощью следующих пунктов меню приложения-симулятора: Функции -> Местоположение -> (выберите вариант, отличный от «нет»).

Это решило проблему для меня. Но это очень запутанная ошибка, поскольку она просто терпит неудачу без каких-либо исключений или чего-то еще.

Ага, для меня тоже.
Пожалуйста, добавьте тайм-аут в запрос местоположения и создайте исключение в симуляторе, для которого не задано местоположение.

Спасибо :)

У меня такая же проблема на iOS, я также использую плагин Google Maps.
У меня есть приложение, которое использует getLocationStream, но я не получаю диалоговое окно с разрешениями, пока не перейду на вкладку, где у меня есть карта Google.
У меня есть другое приложение, в котором я больше не использовал карты Google, но забыл удалить плагин, и у меня была та же проблема. Я удалил плагин Google Maps, и теперь он работает правильно.

Есть новости по этому поводу?

Привет всем, я усердно работаю над этой проблемой. По сути, мы решили построить геолокатор с нуля и исправить сразу несколько проблем.

Пункты, которые будут включены:

  • Исправить проблемы с разрешениями;
  • Убедитесь, что getCurrentLocation получен в разумные сроки;
  • Добавьте тайм-аут к методам getCurrentLocation и getPositionStream , чтобы, если получение местоположения заняло больше времени, чем ожидалось, запрос прервался, и вы могли перезапустить запрос;
  • Улучшение потенциальных сообщений об ошибках;
  • Переход к федеративной структуре плагинов, чтобы мы были готовы к веб-поддержке;
  • Обновление до плагина Android v2;

Первым шагом, который нужно было сделать, было перенести функции геокодирования и разместить их в собственном плагине (который теперь доступен на pub.dev .

Вторым шагом было создание и модульное тестирование всего необходимого кода Dart, который теперь готов и может быть просмотрен в ветке federated_plugin .

Следующие шаги — добавить реализации для iOS и Android и исправить пример приложения. Это то, над чем я сейчас работаю, надеюсь, я смогу закончить все в ближайшие две недели (пожалуйста, имейте в виду, что мне также нужно сделать это в свободное время ;)).

В любом случае, я хочу поблагодарить всех за терпение и отзывы, пожалуйста, подождите еще немного.

@mvanbeusekom
Это хорошие новости. Я рад, что вы нашли время, чтобы предоставить нам этот плагин.

Вам огромное спасибо!

Жду следующих обновлений.

Спасибо и всего наилучшего

Хороший! Дайте нам знать, когда он будет выпущен, чтобы мы могли протестировать.

В качестве временного обходного пути вы можете проверить статус на устройстве с помощью метода GeolocationStatus checkGeolocationPermissionStatus() . Если местоположение отключено, этот метод возвращает значение «отключено». Тогда вам не нужно вызывать метод getCurrentPosition() .

Пример:

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

Небольшое обновление здесь, сегодня утром я отправил новое обновление в ветку federated_plugin , которое включает полную поддержку iOS, включая пример приложения Flutter.

Мы также начали работу над Android, который поддерживает проверку статуса разрешения, теперь мы будем реализовывать запрос разрешений и обработку служб определения местоположения.

Не стесняйтесь проверить код или даже попытаться интегрировать его в тестовое приложение и запустить на iOS. Обратите внимание, что он включает в себя довольно много критических изменений, которые все будут задокументированы. А пока я просто хотел, чтобы все знали, что есть прогресс, хотя это требует некоторого времени. Еще раз спасибо за ваше терпение.

Небольшое обновление здесь, сегодня утром я отправил новое обновление в ветку federated_plugin , которое включает полную поддержку iOS, включая пример приложения Flutter.

Мы также начали работу над Android, который поддерживает проверку статуса разрешения, теперь мы будем реализовывать запрос разрешений и обработку служб определения местоположения.

Не стесняйтесь проверить код или даже попытаться интегрировать его в тестовое приложение и запустить на iOS. Обратите внимание, что он включает в себя довольно много критических изменений, которые все будут задокументированы. А пока я просто хотел, чтобы все знали, что есть прогресс, хотя это требует некоторого времени. Еще раз спасибо за ваше терпение.

Спасибо за усердную работу над этим. Будете ли вы обновлять пакет геолокатора на pub.dev с этим изменением?

Также это файл для примера, который вы упомянули выше: position_updates_example_widget.dart?

Спасибо за усердную работу над этим. Будете ли вы обновлять пакет геолокатора на pub.dev с этим изменением?

Также это файл для примера, который вы упомянули выше: position_updates_example_widget.dart?

Нет, я пока не буду публиковаться на pub.dev. Это полностью переработанный плагин геолокатора, который пока не поддерживает Android. Как только Android и документация будут готовы, я опубликую их на pub.dev.

Да, этот виджет является частью примера приложения и демонстрирует, как вы можете прослушивать обновления позиции.

Привет,

Спасибо за этот пакет.

Есть ли шанс выполнить все вышеперечисленные задачи для Android на этой неделе?

Есть новости по этому поводу?

Только ожидание отставания местоположения при первом запросе.

Есть новости о том, когда будет выпущена переработанная версия? @mvanbeusekom

@ dalmia007 , у меня еще нет даты, но прогресс есть. Я добавил элементарную поддержку Android в ветке feature/federated_android . Он содержит запрос разрешений, получение последнего известного местоположения, получение текущего местоположения и обновлений местоположения с использованием клиента поставщика объединенного местоположения (часть Сервисов Google Play).

Я все еще работаю над следующим:

Специально для Android:

  • Реализация вышеуказанных функций, когда сервисы Google Play недоступны;
  • Автоматически решать проблемы, когда службы определения местоположения не включены;

Общий:

  • Обновить документацию

Не стесняйтесь проверить это здесь

@mvanbeusekom большое спасибо за обновление! 👍

Привет всем,

Я рад объявить о выпуске (наконец-то) версии 6.0.0-rc.1 , которая должна избавиться от всех этих проблем.

Я был бы очень признателен, если бы вы могли попробовать и дать мне свой отзыв.

Мне жаль это говорить, но он уже дважды вылетал, этого достаточно, чтобы уже вернуться к 4.0.3.

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

Произошло, когда я нажал «Разрешить предоставление» в диалоговом окне, а также когда я нажал «Отказать». Дайте мне знать, если я что-то пропустил.

@Dohmanlechx просто удостоверился, вы получили это в версии 6.0.0-rc.x или в версии 5.3.2?

Я получил это на 6.0.0-rc.1 (среда IDE попросила меня «обновить» до 5.3.2+2 , к вашему сведению)

@Dohmanlechx благодаря вашим отзывам я нашел проблему. По-видимому, в вашем случае геолокатор получает обратную связь от другого плагина (я предполагаю, что вы используете обработчик разрешений для обработки разрешений, поскольку requestCode == 24 совпадает с обработчиком разрешений), который он пытается обработать, что, очевидно, терпит неудачу. В этих случаях геолокатор должен просто игнорировать эти сообщения, поскольку они не принадлежат геолокатору. Я исправлю это сегодня и выпущу новый релиз-кандидат.

Спасибо за ваш отзыв!

О, действительно, мы используем permission_handler . Хорошая находка!

Все заслуги принадлежат вам @Dohmanlechx ;). Благодаря вашим отзывам я смог обнаружить эту ошибку и скоро выпущу новую версию.

@Dohmanlechx Я только что выпустил версию 6.0.0-rc.3, которая должна исправить ошибку, с которой вы столкнулись.

Очень круто, тщательно протестировано на эмуляторе Android, предоставление и отказ, манипулирование местоположением, работало отлично. Отлично работало и на моем реальном Android-устройстве.

Но системный запрос для симулятора iOS вообще не отображается, как вы думаете, он предназначен? Тем не менее, по крайней мере, оно не выйдет из строя, и приложение работает так, как хотелось бы, без какого-либо доступного местоположения. К сожалению, все еще не могу протестировать на своем iPhone из-за проблемы с подключением Xcode, и я не хочу развертывать сборку в TestFlight только для тестирования сейчас. Сообщу, как только проверю на iPhone.

Но пока все хорошо!

Большое спасибо за обширное тестирование @Dohmanlechx , это очень ценно!

Плагин действительно не отображает запрос на обслуживание на iOS, поскольку для этого нет (общедоступного) API. Единственный вариант, который у нас есть, — вручную показать пользователю сообщение, объясняющее, как обновить настройки вручную. У нас есть возможность перенаправить пользователя в приложение «Настройки» (путем вызова методов openAppSettings() или openLocationSettings() ). Я задокументировал это более подробно в файле README.md .

С сожалением сообщаю об этом, но на моем iPhone XS Max с ОС 13.6.1 это работало катастрофически.

В первый раз выбор позиции работал так же, как и в старой версии, возвращал правильную позицию, но все равно занимал 7-8 секунд.

Но со второго раза и далее просто бросало мгновенно. Мне пришлось перейти с Exception err на dynamic err из-за:
_ Необработанное исключение: тип '_TypeError' не является подтипом типа 'Exception' _.

Я получаю их, когда это не удается (после первой выборки):

2020-08-26 14:01:45.670206+0200 Бегун [4565:206487] флаттер: Не удалось получить местоположение: Плохое состояние: Нет элемента
2020-08-26 14:01:45.670416+0200 Runner[4565:206487] флаттер: не удалось получить местоположение: экземпляр «NoLocationFoundException»

( NoLocationFoundException — мой собственный класс)

_Плохое состояние: нет элемента_ , к сожалению, мало что говорит... ниже мой код:

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

Я искренне надеюсь, что вы сможете воспроизвести это на своем iPhone.

@Dohmanlechx , спасибо за обширный отзыв, я думаю, что нашел проблему здесь. Теперь мне нужно найти хороший способ исправить это;)

Короче говоря, метод getCurrentPosition вызывает getPositionStream и берет первый элемент, а затем закрывает поток. Проблема в том, что getPositionStream имеет такой код:

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

Что, как вы можете догадаться, вызывает исключение Bad state: No element при вызове getCurrentPosition во второй раз, потому что он будет вызывать first в уже закрытом потоке. Я буду работать над этим и скоро опубликую нового кандидата.

@Dohmanlechx , вы выдаете, что «Плохое состояние: нет элемента» должно было быть исправлено в версии 6.0.0-rc.4 , которую я только что опубликовал. Мне не удалось воспроизвести проблему, но я смог убедиться, что getCurrentPosition будет использовать новый поток, когда вы вызываете его во второй (и любой последующий) раз.

Я был бы очень признателен, если бы вы попробовали еще раз и дали мне знать, если это сработает.

Я заметил, что вы напрямую используете GeolocatorPlatform.instance.<some_method> , делая это, вы передаете любую логику, которая находится в пакете geolocator , и переходите прямо к реализации по умолчанию, которая находится в geolocator_platform_instance Пакет geolocator нет, но все же лучше не обходить стороной.

Если вы импортируете пакет geolocator, вы сможете напрямую вызывать глобальные методы, например:

import 'package:geolocator/geolocator.dart';

final position = await getCurrentPosition();

Если вы столкнулись с коллизиями или просто хотите добавить префикс к глобальным методам, вы можете добавить псевдоним к импорту, например:

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

final position = await geolocator.getCurrentPosition();

Спасибо, я также изменил код в соответствии с вашими предложениями.

Краш исчез, но, к сожалению, он все еще слишком нестабилен. В 3 из 10 раз это очень быстро (очень хотелось бы, чтобы это было в 10 из 10 раз), но в 7 из 10 раз превышается лимит времени (10 секунд), и функция срабатывает. Вы тестировали на своем iPhone, рассылая спам getCurrentPosition() ? Я тестировал на iPhone XS Max, OS 13.6.1.

_4.0.3_ работает медленно, но стабильно
_6.0.0-rc.4_ работает быстро, но нестабильно

Но не беспокойтесь, это совершенно нормально и абсолютно не катастрофа для нас, тем более, что я написал собственный лимит времени для версии 4.0.3.

@Dohmanlechx рад слышать, что сбой решен, это хоть что-то ;)

Мне действительно интересно, почему вы все еще получаете медленные обновления, поскольку я не могу их воспроизвести. Я создал очень простое демонстрационное приложение, чтобы попробовать его:

основной.дротик:

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

Информация.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>

Поэтому каждый раз, когда я нажимаю кнопку плавающего действия, вызывается getCurrentPosition , и результат добавляется к ListView . Я протестировал это приложение на своем личном iPhone 7, iPhone 6 моей жены и симуляторе (все они работают под управлением последней версии iOS), но я могу спамить кнопку, и местоположение возвращается почти сразу. Я действительно озадачен, почему у вас другой опыт. Может быть, вы можете протестировать этот пример кода и посмотреть, есть ли у вас та же проблема?

Я действительно восхищаюсь вашей настойчивостью. Создал новый проект и воспользовался вашими кодами, чуть не разбил экран айфона, заспамив кнопку, локация возвращалась сразу все время. Потрясающий! Завтра я постараюсь найти время, чтобы устранить неполадки в нашем коде, начиная с запуска getCurrentPosition() непосредственно в виджете, а затем перемещая его все дальше и дальше до его предполагаемого места, чтобы найти виновника. Я подозреваю, что это из-за плагина разрешений, но посмотрим.

Спасибо за отзыв и добрые слова, очень приятно. Я приложил много усилий, чтобы восстановить геолокатор, и именно эта проблема заставила меня решиться на его запуск, поэтому я бы очень хотел, чтобы на этот раз все было хорошо ;)

Пожалуйста, дайте мне знать, как это происходит, и если я могу помочь.

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

Попробовал это прямо в виджете, и каждый раз, когда я нажимал, в консоли регистрировалось местоположение! Так что это определенно наш код. Так что теперь дело за нами, спасибо за все!

Однако это _иногда_ происходит при получении позиции:

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 Я вообще не могу получить позицию, используя новейшую версию 6.0.0+1. Пробовал на симуляторе iOS, API эмулятора Android 29, физический OnePlus 6. Тайм-аут выбрасывается каждый раз.

image

image

Я не знаю, что еще я могу добавить сюда, чтобы помочь вам найти проблему, getCurrentPosition возвращает тайм-аут или просто зависает, если параметр timeLimit не указан. Я пробовал разные точности определения местоположения. У кого-нибудь есть эта проблема?

Версия 5.3.2+2 отлично работает на симуляторе iOS (с указанием пользовательского местоположения), реальном устройстве Android и эмуляторе Android.

@mvanbeusekom , я прочитал все это и обновляюсь до последней версии, чтобы исправить проблему с 10-секундной задержкой.

Может я что-то упускаю, но что-то я уже не умею в новой версии (геокодирование).
Раньше я мог вручную установить положение в центре города (в случае, если пользователь отрицает местоположение), выполнив следующие действия:

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

Теперь кажется, что _placemarkFromAddress_ был изменен на _ locationFromAddress _, поэтому я попытался адаптироваться, сделав следующие изменения в моей формуле:

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

Но я получаю следующую ошибку:

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

Как я могу преобразовать местоположение в положение или, в конечном счете, в случае, если пользователь отрицает местоположение, как я могу теперь установить его положение в центре своего города?

Спасибо.

Я обновился до последней версии, проблема у меня устранена 👍👍👍

Была ли эта страница полезной?
0 / 5 - 0 рейтинги