ionic-team / capacitor

Build cross-platform Native Progressive Web Apps for iOS, Android, and the Web ⚡️
https://capacitorjs.com
MIT License
11.31k stars 962 forks source link

bug: Geolocation on Android always returning 'location unavailable' #4962

Closed jonathan-chin closed 2 years ago

jonathan-chin commented 2 years ago

Bug Report

Capacitor Version

💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 3.2.0
  @capacitor/core: 3.2.0
  @capacitor/android: 3.2.0
  @capacitor/ios: 3.2.0

Installed Dependencies:

  @capacitor/cli: 3.0.0
  @capacitor/core: 3.0.0
  @capacitor/android: 3.0.0
  @capacitor/ios: 3.1.2

[error] Xcode is not installed
[success] Android looking great! 👌

Platform(s)

Android 10

Current Behavior

When I try to call Geolocation.getCurrentPosition(), I always get an error: 'location unavailable'. I've tried this with no options and {enableHighAccuracy: true}.

I have the appropriate permissions set and the code works on PWA and iOS. The app has Location permission while in the foreground and Google Maps can get my location fine.

Expected Behavior

Geolocation.getCurrentPosition() should provide the lat/lng of the current position.

Code Reproduction

edit: basic repo set up here: https://github.com/jonathan-chin/capacitor-geocode-android-example clicking on the get currentposition button will return location unavailable when running on a Google Pixel 3A on Android 10 through Android Studio.

it seems to have been an existing issue in the past #2854 but I am still experiencing it.

Ionitron commented 2 years ago

This issue may need more information before it can be addressed. In particular, it will need a reliable Code Reproduction that demonstrates the issue.

Please see the Contributing Guide for how to create a Code Reproduction.

Thanks! Ionitron 💙

jonathan-chin commented 2 years ago

@jcesarmobile @Ionitron just updated with a bare minimum repo.

exomc commented 2 years ago

I've been using this plugin without any problems for weeks while developing my app. I've just updated all packages to the latest versions and now I am also experiencing this issue. Goes straight to error after giving the app permission. No error code or anything just 'location unavailable'

Ionic 6.17.0 Android Studio to Artic Fox | 2020.3.1 Patch 1

I'm getting the same thing on the emulator (with play store) as well as on my device. Web is fine.

Android build now generated the following warnings, not sure if they are relevant:

AGPBI: {"kind":"warning","text":"Using flatDirs should be avoided because it doesn't support any meta-data formats.\nCurrently detected usages:\n- repository flatDir used in: project ':app', project ':capacitor-cordova-android-plugins'","sources":[{}]} AGPBI: {"kind":"warning","text":"Please remove usages of jcenter() Maven repository from your build scripts and migrate your build to other Maven repositories.\nThis repository is deprecated and it will be shut down in the future.\nSee http://developer.android.com/r/tools/jcenter-end-of-service for more information.\nCurrently detected usages in: root project 'android', project ':app', project ':capacitor-android', ...","sources":[{}]}

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0. Use '--warning-mode all' to show the individual deprecation warnings.

jonathan-chin commented 2 years ago

I updated the repo a second time to implement @ionic-native geolocation. this gives me a lat/lng while the capacitor implementation still returns 'location unavailable'.

exomc commented 2 years ago

Having gone into Tools > SDK Tools in Android Studio and ticking the box for Google Play services in the SDK Tools tab, it works in the emulator now. Setting the location doesn't work, but at least do get a position.

Still can't get it to work on my Android device which is logged in to Play Store.

Seems to be some disconnect between Play Services and Capacitor / Android Studio.

exomc commented 2 years ago

Native Geolocation works fine so am sticking with that!

marcoagsa commented 2 years ago

I have the same problem ! I removed the android platform and added it again and the problem remains

jonathan-chin commented 2 years ago

I'm currently migrating my code to use Ionic Native since I have a tight deadline. I'd love to be able to use 100% Capacitor and am happy to switch back after this gets resolved.

jcesarmobile commented 2 years ago

I can't reproduce on the provided app, but buttons are working and returning locations. Tested on Android 9 and Android 11 devices. What devices are you testing on? Android versions of the devices? Which countries do you live in? The plugin uses com.google.android.gms:play-services-location dependency, play services might not be available in some countries. This should not be relevant, supposedly the Fused Location Provider is now available worldwide.

the cordova plugin uses the WebView location, so it's no different from using

navigator.geolocation.getCurrentPosition((position) => {
  console.log(position.coords.latitude, position.coords.longitude);
});
jonathan-chin commented 2 years ago

@jcesarmobile I tested on a physical phone by running it through Android Studio. the phone is: Pixel3a Android 10 buildnumber QQ1A.200105.002 I'm in the US. Google Maps, MapQuest, and some random GPS apps I downloaded all seem to be working fine from the same phone.

I've also run in in the Android simulator: Pixel 4 running Android 11

let me know if you need more info

jcesarmobile commented 2 years ago

Can you open Geolocation.java class on the capacitor-geolocation module and search for location unavailable?. There should be 2 occurrences. Change the first one to location null (or any other message) and run again. Won't really help much, but just curious if you are getting location unavailable or a null location, which Google says can happen sometimes, but rarely.

bildonia commented 2 years ago

I'm seeing this issue on a Pixel 5 and Galaxy Tab A both running Android 11.

jonathan-chin commented 2 years ago

it seems I'm getting it here:

                @Override
                public void onLocationAvailability(LocationAvailability availability) {
                    if (!availability.isLocationAvailable()) {
                        resultCallback.error("location YYY");
                        clearLocationUpdates();
                    }
                }
jcesarmobile commented 2 years ago

And what happens if you remove the whole onLocationAvailability function?

jonathan-chin commented 2 years ago

@jcesarmobile removing the function makes it work. I got lat/lng, altitude, speed, etc.

jcesarmobile commented 2 years ago

🤔 that's really weird, why would onLocationAvailability fire and say it's not available but return a location if you ignore it?

jonathan-chin commented 2 years ago

@jcesarmobile so I went off of this: https://www.titanwolf.org/Network/q/f51ad29a-0a3e-42ca-a991-e460331ef8e3/y

if I push the app via Android studio (with onLocationAvailability still in), then reset my phone, I get results. if I spam the button, I will sometimes get location unavailable, but only like 1/30 times and the following key press works just fine (and when I say spam, I mean spam).

however, when I background the app and come back to it, I get location unavalable. BUT if I call the ionic native version once, I get results from capacitor for the next 4-5 keypresses. I can do this reliably.

jcesarmobile commented 2 years ago

Yeah, I also saw that thread, but looked like a device bug.

I still can't reproduce, even backgrounding the app. And sadly removing the onLocationAvailability method is not a good solution as it makes getCurrentPosition hang when the location is disabled by the user as it's not able to detect that it's disabled but the onLocationResult doesn't get called neither.

Can you replace the whole sendLocation method with

@SuppressWarnings("MissingPermission")
public void sendLocation(
        boolean enableHighAccuracy,
        int timeout,
        final boolean getCurrentPosition,
        final LocationResultCallback resultCallback
    ) {
      fusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
      LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
      boolean networkEnabled = false;

      try {
        networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
      } catch (Exception ex) {}
      int lowPriority = networkEnabled ? LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY : LocationRequest.PRIORITY_LOW_POWER;
      int priority = enableHighAccuracy ? LocationRequest.PRIORITY_HIGH_ACCURACY : lowPriority;
      fusedLocationClient.getCurrentLocation(priority, null).addOnCompleteListener(new OnCompleteListener<Location>() {
        @Override
        public void onComplete(@NonNull Task<Location> location) {
          if (location.getResult() != null) {
            resultCallback.success(location.getResult());
          } else {
            resultCallback.error("no location");
          }
        }
      });
}
jonathan-chin commented 2 years ago

I'm getting 4 compile errors:

cannot find symbol class OnCompleteListener caused by this line: fusedLocationClient.getCurrentLocation(priority, null).addOnCompleteListener(new OnCompleteListener() {

cannot find symbol class Task caused by this line: public void onComplete(@NonNull Task location) {

cannot find symbol class NonNull also caused by this line: public void onComplete(@NonNull Task location) {

method does not override or implement a method from a supertype caused by this line: @Override

jcesarmobile commented 2 years ago

You might need to manually add this imports (sometimes Android Studio doesn't add them by default)

import androidx.annotation.NonNull;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;

or putting the cursor over the unrecognized symbol and pressing alt+Intro can also import it

jonathan-chin commented 2 years ago

@jcesarmobile sorry, I don't use Android Studio much; I have barely coded in Java in the last 15 years.

the new function seems to work well. I have not gotten a location unavailable ever during the 30 seconds I spammed the button.

this may be a fix! what is different?

stevebrowndotco commented 2 years ago

I can confirm that within the last week or so this plugin is reporting "location unavailable" on android. I am somewhat reassured that this seems to be very recent for others here. Could this plugin be depending on something that is broken elsewhere?

stevebrowndotco commented 2 years ago

I can confirm that implementing this change to Geolocation.java fixes it for me

Although effectively this is a change in node_modules , so only a temporary solution.. (for now I am using patch-package)

jcesarmobile commented 2 years ago

Don't worry, Android Studio can be annoying sometimes. Thanks for testing!

It uses a new method for getting a single location (at the moment the plugin starts tracking location and stops it when it get the first result). It was introduced in play-services-location 17.1.0 and is supposed to handle this kind of errors/problems better. On the other hand, it doesn't allow to configure the timeout, which could be considered a breaking change in the plugin, so we don't know when we would be able to do a new release with the fix. I've created https://github.com/ionic-team/capacitor-plugins/issues/571 for tracking the code change.

TarasZakus commented 2 years ago

Hi guys, I've also faced the same issue. For some reason the availability.isLocationAvailable() is false. As a temporary solution, I removed the onLocationAvailability(LocationAvailability availability) method. Also there is a discussion on StackOverflow regarding the issue.

jonathan-chin commented 2 years ago

@jcesarmobile thanks so much. for the time being, I'll be using the ionic native implementation.

please let me know if there are other ways I can help. tag me for any testing, etc.

jcesarmobile commented 2 years ago

Since the problem seems recent it might be some problem with the old library version. Can you restore the plugin code to the old one so the issue can be reproduced again and then update the google play services version to latest available like in this PR I've sent to your sample app? Just in case the problem is not present on latest version.

jonathan-chin commented 2 years ago

I believe I did this right (revert plugin code, add to variables.gradle) however, I am getting location unavailable again.

with everything reverted, if I click on the ionic native implementation, the capacitor implementation will work for a few presses, then goes back to location unavailable loop

jcesarmobile commented 2 years ago

yeah, I wasn't sure that would fix the issue, just wanted to check if could be related to the plugin using an older version than latest, but looks like it's unrelated. Since we are doing a major release we will bump the default version anyway despite it doesn't fix anything, but it's always good to be up to date.

yang-shen-wen commented 2 years ago

It's a Google Play Service bug. I factory reset my phone, the problem is not happening.(Google Play Service v19.5.30) Then update Google play Service to newest version (v21.30.16), the problem happened.

jcesarmobile commented 2 years ago

Looks like they removed the faulty version, on all my devices latest version is 21.26.21

JDiApice commented 2 years ago

I am still showing 21.30.16 on my Samsung Galaxy s21 Ultra with the last update 8/23/21. There is not any pending updates for Google Play Services within the Google Play Store. My Samsung Galaxy S9 is showing 21.24.18 which is the device that did not have any issues.

jcesarmobile commented 2 years ago

Yeah, they have removed that version from play store, but if it's already installed you have to manually uninstall it or wait for a newer version with the fix, it doesn't downgrade to the latest stable version automatically.

jcesarmobile commented 2 years ago

I'm closing the issue since it's a google services problem. You can keep track of the sendLocation change (that should fix this issue) on https://github.com/ionic-team/capacitor-plugins/issues/571

jcesarmobile commented 2 years ago

looks like Google didn't remove 21.30.16 from play store as I just got it on my device

AppskySpencer commented 2 years ago

My Google Play Services version is 21.33.12 and I am still having the issue.

jcesarmobile commented 2 years ago

I've reported this issue on google issue tracker https://issuetracker.google.com/issues/198176818

luisdalopez56 commented 2 years ago

I have been testing on an android 7 and using native ionic Location accuracy I have been able to change the precision to the user and this way it works, but the problem comes with Android 11, there is no way to make it work

Chamiyalt commented 2 years ago

I have been tesing on GalaxyA32 (Android 11) the Geolocation plugin await Geolocation.getCurrentPosition(); is retuned {"message":"location unavailable"} but it had been worked fine in 3 weeks ago. please give any solution asap. lot of users waiting for a fix.

ignaciomarti commented 2 years ago

Same issue... Temporarily solved by commenting out these lines in Geolocation.java

if (!availability.isLocationAvailable()) { call.error("location unavailable"); clearLocationUpdates(); }

jcesarmobile commented 2 years ago

@capacitor/geolocation 1.1.0 is out with a fix

KevinKelchen commented 2 years ago

Awesome! 😀

Are there plans to release an update to Capacitor v2 with the same fix? I see someone has an open PR for it: https://github.com/ionic-team/capacitor/pull/4992 . Thought it might be worth asking since some of us have yet to upgrade to v3 and given the level of severity of the issue. 🙂

For now I've manually made the changes in https://github.com/ionic-team/capacitor/pull/4992 to node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/Geolocation.java and used patch-package so we can hotfix our app. We can then remove the patch if the fix lands in Capacitor v2 or when the day comes that we upgrade to v3.

Thanks so much!

FahmiChaar commented 2 years ago

@KevinKelchen how you use patch-package ? when i run npx patch-package @capacitor/core the output is ⁉️ There don't appear to be any changes. and patches folder did not created

KevinKelchen commented 2 years ago

@KevinKelchen how you use patch-package ? when i run npx patch-package @capacitor/core the output is ⁉️ There don't appear to be any changes. and patches folder did not created

It’s not @capacitor/core that’s being patched but rather @capacitor/android. Try changing the package name. 🙂

FahmiChaar commented 2 years ago

@KevinKelchen how you use patch-package ? when i run npx patch-package @capacitor/core the output is ⁉️ There don't appear to be any changes. and patches folder did not created

It’s not @capacitor/core that’s being patched but rather @capacitor/android. Try changing the package name. 🙂

thank you so much, it work now

mtpultz commented 2 years ago

We followed these steps to patch (Thanks @KevinKelchen) and had to add an optional step 6 to have it run in Ionic AppFlow:

  1. Access @capacitor/android and update Geolocation.java using this PRs changes (https://github.com/ionic-team/capacitor/pull/4992/files)
  2. Run npx patch-package @capacitor/android
  3. Update package.json with "postinstall": "patch-package"
  4. npm install patch-package so dependency exists when npm install is run during Ionic AppFlow
  5. Commit the patch file and changes to package.json
  6. (Optional) If you get an error like "cannot run in wd [...]" add a .npmrc with unsafe-perm = true when using Ionic AppFlow since we can't use a non-root user
jcesarmobile commented 2 years ago

We have released @capacitor/android 2.5.0 with the fix, but please, update to capacitor 3 as soon as possible, it's not that hard and most fixes won't be backported to capacitor 2.

08-15at commented 2 years ago

JFYI: looks like Google has updated Play-Services. Version 21.33.13 seems to work with the old code....

jcesarmobile commented 2 years ago

not working for me with that version

08-15at commented 2 years ago

strange... seems as there could be some underlying Google code changes somewhere else: some customers reported, that it started working again after an automatic Android update on Sep. 3. However it remained broken for others. So I asked some of those customers with a working device to send me their Play-Services version-info, it was still 21.30.16, but my app started working again on their devices after an Android update on Sep. 3. without changes on my side. On my devices and the simulator I could see a Play-Service version released on Sep. 3 in the Web PlayStore, but Play-Store let me only install the Aug. 28 version where it would fail on my devices. I uploaded a workaround in place for my app Sept. 5, and I could update to your code, so no issue for me. However today I got 21.33.13 from the PlayStore and I tried my (unpatched) app version and the previous failing Ionic Capacitor - Core Plugins Demo and it worked.