Skip to content

Commit 768a769

Browse files
authored
fix: crash on app start when permission is denied (#304)
* fix: crash on app start when permission is denied * fix: callbacks invoked multiple times
1 parent d7487cf commit 768a769

File tree

2 files changed

+51
-24
lines changed

2 files changed

+51
-24
lines changed

android/src/main/java/com/reactnativecommunity/geolocation/GeolocationModule.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.android.gms.common.GoogleApiAvailability;
2424

2525
import java.util.ArrayList;
26+
import java.util.Arrays;
2627
import java.util.Objects;
2728

2829
public class GeolocationModule extends ReactContextBaseJavaModule {
@@ -120,7 +121,7 @@ public void getCurrentPosition(
120121

121122
requestAuthorization(args -> mLocationManager.getCurrentLocationData(options, success, error), error);
122123
} catch (SecurityException e) {
123-
throwLocationPermissionMissing(e);
124+
emitLocationPermissionMissing(e);
124125
}
125126
}
126127

@@ -139,10 +140,10 @@ public void startObserving(ReadableMap options) {
139140
}
140141

141142
requestAuthorization(args -> mLocationManager.startObserving(options), args -> {
142-
throw new SecurityException(args.toString());
143+
emitLocationPermissionMissing(new SecurityException(Arrays.toString(args)));
143144
});
144145
} catch (SecurityException e) {
145-
throwLocationPermissionMissing(e);
146+
emitLocationPermissionMissing(e);
146147
}
147148
}
148149

@@ -159,11 +160,13 @@ public void stopObserving() {
159160
/**
160161
* Provides a clearer exception message than the default one.
161162
*/
162-
private static void throwLocationPermissionMissing(SecurityException e) {
163-
throw new SecurityException(
164-
"Looks like the app doesn't have the permission to access location.\n" +
165-
"Add the following line to your app's AndroidManifest.xml:\n" +
166-
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />", e);
163+
private void emitLocationPermissionMissing(SecurityException e) {
164+
String message =
165+
"Looks like the app doesn't have the permission to access location.\n" +
166+
"Add the following line to your app's AndroidManifest.xml:\n" +
167+
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n" +
168+
e.getMessage();
169+
mLocationManager.emitError(PositionError.PERMISSION_DENIED, message);
167170
}
168171

169172
private static class Configuration {

android/src/main/java/com/reactnativecommunity/geolocation/PlayServicesLocationManager.java

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
import android.annotation.SuppressLint;
44
import android.app.Activity;
55
import android.location.Location;
6-
import android.os.Build;
76
import android.os.Looper;
87
import android.util.Log;
98
import android.content.Context;
109
import android.location.LocationManager;
1110

12-
import androidx.annotation.RequiresApi;
11+
import androidx.annotation.NonNull;
1312

1413
import com.facebook.react.bridge.Callback;
1514
import com.facebook.react.bridge.ReactApplicationContext;
1615
import com.facebook.react.bridge.ReadableMap;
16+
import com.facebook.react.bridge.WritableMap;
1717
import com.facebook.react.common.SystemClock;
1818
import com.facebook.react.modules.core.DeviceEventManagerModule;
1919
import com.google.android.gms.location.FusedLocationProviderClient;
@@ -23,13 +23,7 @@
2323
import com.google.android.gms.location.LocationResult;
2424
import com.google.android.gms.location.LocationServices;
2525
import com.google.android.gms.location.LocationSettingsRequest;
26-
import com.google.android.gms.location.LocationSettingsResponse;
27-
import com.google.android.gms.location.Priority;
2826
import com.google.android.gms.location.SettingsClient;
29-
import com.google.android.gms.tasks.OnSuccessListener;
30-
31-
import java.util.function.Consumer;
32-
import java.util.function.Function;
3327

3428
@SuppressLint("MissingPermission")
3529
public class PlayServicesLocationManager extends BaseLocationManager {
@@ -157,28 +151,58 @@ private boolean isAnyProviderAvailable() {
157151
return locationManager != null && (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
158152
}
159153

160-
private LocationCallback createSingleLocationCallback(Callback success, Callback error){
154+
private LocationCallback createSingleLocationCallback(Callback success, Callback error) {
155+
final CallbackHolder callbackHolder = new CallbackHolder(success, error);
156+
161157
return new LocationCallback() {
162158
@Override
163-
public void onLocationResult(LocationResult locationResult) {
164-
if (locationResult == null) {
165-
error.invoke(PositionError.buildError(PositionError.POSITION_UNAVAILABLE, "No location provided (FusedLocationProvider/lastLocation)."));
159+
public void onLocationResult(@NonNull LocationResult locationResult) {
160+
Location location = locationResult.getLastLocation();
161+
162+
if (location == null) {
163+
callbackHolder.error(PositionError.buildError(PositionError.POSITION_UNAVAILABLE, "No location provided (FusedLocationProvider/lastLocation)."));
166164
return;
167165
}
168166

169-
Location location = locationResult.getLastLocation();
170-
success.invoke(locationToMap(location));
167+
callbackHolder.success(location);
171168

172169
mFusedLocationClient.removeLocationUpdates(mSingleLocationCallback);
173170
mSingleLocationCallback = null;
174171
}
175172

176173
@Override
177-
public void onLocationAvailability(LocationAvailability locationAvailability) {
174+
public void onLocationAvailability(@NonNull LocationAvailability locationAvailability) {
178175
if (!locationAvailability.isLocationAvailable()) {
179-
error.invoke(PositionError.buildError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider/lastLocation)."));
176+
callbackHolder.error(PositionError.buildError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider/lastLocation)."));
180177
}
181178
}
182179
};
183180
}
181+
182+
private static class CallbackHolder {
183+
Callback success;
184+
Callback error;
185+
public CallbackHolder(Callback success, Callback error) {
186+
this.success = success;
187+
this.error = error;
188+
}
189+
190+
public void error(WritableMap cause) {
191+
if (this.error == null) {
192+
Log.e(this.getClass().getSimpleName(), "tried to invoke null error callback -> " + cause.toString());
193+
return;
194+
}
195+
this.error.invoke(cause);
196+
this.error = null;
197+
}
198+
199+
public void success(Location location) {
200+
if (this.success == null) {
201+
Log.e(this.getClass().getSimpleName(), "tried to invoke null success callback");
202+
return;
203+
}
204+
this.success.invoke(locationToMap(location));
205+
this.success = null;
206+
}
207+
}
184208
}

0 commit comments

Comments
 (0)