Skip to content

Commit f3da392

Browse files
michalchudziakmarchinramvalery-lavrikjkaufman
authored
Release 3.10 (#271)
* use latest play services version 21.0.1 (#249) Thanks, I'll test this out and include in the next version * work in Headless JS (#254) Co-authored-by: lavrik acer <valery.lavrik@gmail.com> * Default `maximumAge` to 0 on iOS. (#268) * Example updates (#270) * chore: headless js + example updates * chore: revert ts changes * chore: fix background location timer types * chore: move types package --------- Co-authored-by: Brian Rojas <marchinram@gmail.com> Co-authored-by: valery-lavrik <valery-lavrik@users.noreply.github.com> Co-authored-by: lavrik acer <valery.lavrik@gmail.com> Co-authored-by: Justin Kaufman <57186+jkaufman@users.noreply.github.com>
1 parent 7de1d36 commit f3da392

File tree

16 files changed

+178
-53
lines changed

16 files changed

+178
-53
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Geolocation.setRNConfiguration(
164164
config: {
165165
skipPermissionRequests: boolean;
166166
authorizationLevel?: 'always' | 'whenInUse' | 'auto';
167+
enableBackgroundLocationUpdates?: boolean;
167168
locationProvider?: 'playServices' | 'android' | 'auto';
168169
}
169170
) => void
@@ -173,6 +174,7 @@ Supported options:
173174

174175
* `skipPermissionRequests` (boolean) - Defaults to `false`. If `true`, you must request permissions before using Geolocation APIs.
175176
* `authorizationLevel` (string, iOS-only) - Either `"whenInUse"`, `"always"`, or `"auto"`. Changes whether the user will be asked to give "always" or "when in use" location services permission. Any other value or `auto` will use the default behaviour, where the permission level is based on the contents of your `Info.plist`.
177+
* `enableBackgroundLocationUpdates` (boolean, iOS-only) - When using `skipPermissionRequests`, toggle wether to automatically enableBackgroundLocationUpdates. Defaults to true.
176178
* `locationProvider` (string, Android-only) - Either `"playServices"`, `"android"`, or `"auto"`. Determines wether to use `Google’s Location Services API` or `Android’s Location API`. The `"auto"` mode defaults to `android`, and falls back to Android's Location API if play services aren't available.
177179

178180
---

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ repositories {
133133
dependencies {
134134
//noinspection GradleDynamicVersion
135135
implementation 'com.facebook.react:react-native:+'
136-
implementation 'com.google.android.gms:play-services-location:20.0.0'
136+
implementation 'com.google.android.gms:play-services-location:21.0.1'
137137
}
138138

139139
if (isNewArchitectureEnabled()) {

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

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ public void getCurrentLocationData(ReadableMap options, Callback success, Callba
4949
Activity currentActivity = mReactContext.getCurrentActivity();
5050

5151
if (currentActivity == null) {
52-
error.invoke(PositionError.buildError(PositionError.ACTIVITY_NULL, "mReactContext.getCurrentActivity() returned null but should be non-null in getCurrentLocationData"));
53-
return;
52+
mSingleLocationCallback = createSingleLocationCallback(success, error);
53+
checkLocationSettings(options, mSingleLocationCallback);
54+
return;
5455
}
5556

5657
try {
@@ -59,29 +60,7 @@ public void getCurrentLocationData(ReadableMap options, Callback success, Callba
5960
if (location != null && (SystemClock.currentTimeMillis() - location.getTime()) < locationOptions.maximumAge) {
6061
success.invoke(locationToMap(location));
6162
} else {
62-
mSingleLocationCallback = new LocationCallback() {
63-
@Override
64-
public void onLocationResult(LocationResult locationResult) {
65-
if (locationResult == null) {
66-
emitError(PositionError.POSITION_UNAVAILABLE, "No location provided (FusedLocationProvider/lastLocation).");
67-
return;
68-
}
69-
70-
AndroidLocationManager.LocationOptions locationOptions = AndroidLocationManager.LocationOptions.fromReactMap(options);
71-
Location location = locationResult.getLastLocation();
72-
success.invoke(locationToMap(location));
73-
74-
mFusedLocationClient.removeLocationUpdates(mSingleLocationCallback);
75-
mSingleLocationCallback = null;
76-
}
77-
78-
@Override
79-
public void onLocationAvailability(LocationAvailability locationAvailability) {
80-
if (!locationAvailability.isLocationAvailable()) {
81-
emitError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider/lastLocation).");
82-
}
83-
}
84-
};
63+
mSingleLocationCallback = createSingleLocationCallback(success, error);
8564
checkLocationSettings(options, mSingleLocationCallback);
8665
}
8766
});
@@ -151,4 +130,29 @@ private void requestLocationUpdates(LocationRequest locationRequest, LocationCal
151130
throw e;
152131
}
153132
}
133+
134+
private LocationCallback createSingleLocationCallback(Callback success, Callback error){
135+
return new LocationCallback() {
136+
@Override
137+
public void onLocationResult(LocationResult locationResult) {
138+
if (locationResult == null) {
139+
error.invoke(PositionError.buildError(PositionError.POSITION_UNAVAILABLE, "No location provided (FusedLocationProvider/lastLocation)."));
140+
return;
141+
}
142+
143+
Location location = locationResult.getLastLocation();
144+
success.invoke(locationToMap(location));
145+
146+
mFusedLocationClient.removeLocationUpdates(mSingleLocationCallback);
147+
mSingleLocationCallback = null;
148+
}
149+
150+
@Override
151+
public void onLocationAvailability(LocationAvailability locationAvailability) {
152+
if (!locationAvailability.isLocationAvailable()) {
153+
error.invoke(PositionError.buildError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider/lastLocation)."));
154+
}
155+
}
156+
};
157+
}
154158
}

example/ios/GeolocationExample/Info.plist

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@
3535
</dict>
3636
</dict>
3737
</dict>
38-
<key>NSLocationWhenInUseUsageDescription</key>
39-
<string></string>
4038
<key>UILaunchStoryboardName</key>
4139
<string>LaunchScreen</string>
4240
<key>UIRequiredDeviceCapabilities</key>
@@ -51,5 +49,9 @@
5149
</array>
5250
<key>UIViewControllerBasedStatusBarAppearance</key>
5351
<false/>
52+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
53+
<string>Testing purposes</string>
54+
<key>NSLocationWhenInUseUsageDescription</key>
55+
<string>Testing purposes</string>
5456
</dict>
5557
</plist>

example/ios/Podfile.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ PODS:
562562
- React-jsinspector (0.70.10)
563563
- React-logger (0.70.10):
564564
- glog
565+
- react-native-background-timer (2.4.1):
566+
- React-Core
565567
- react-native-geolocation (3.0.6):
566568
- RCT-Folly (= 2021.07.22.00)
567569
- RCTRequired
@@ -711,6 +713,7 @@ DEPENDENCIES:
711713
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
712714
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
713715
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
716+
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
714717
- react-native-geolocation (from `../..`)
715718
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
716719
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
@@ -782,6 +785,8 @@ EXTERNAL SOURCES:
782785
:path: "../node_modules/react-native/ReactCommon/jsinspector"
783786
React-logger:
784787
:path: "../node_modules/react-native/ReactCommon/logger"
788+
react-native-background-timer:
789+
:path: "../node_modules/react-native-background-timer"
785790
react-native-geolocation:
786791
:path: "../.."
787792
react-native-safe-area-context:
@@ -845,6 +850,7 @@ SPEC CHECKSUMS:
845850
React-jsiexecutor: 1457c7bb2f08f257e6b5ece8b62348da43c4ccf2
846851
React-jsinspector: 2a1985769123b199c195a96f46478b35db139712
847852
React-logger: 7fbdc3576b2ed3834360c8ea3c1c2ec54ac3043a
853+
react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe
848854
react-native-geolocation: a4df6c9ef98f624737b40c9e3d709eec1bff6ea7
849855
react-native-safe-area-context: 0dfc8e3a7d5ff115d100bafe4269d64a2c0a1456
850856
React-perflogger: f86e85eb59151d09e9b44b8931f5c088e4f08bbc

example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@react-navigation/native-stack": "^6.7.0",
1717
"react": "18.1.0",
1818
"react-native": "0.70.10",
19+
"react-native-background-timer": "^2.4.1",
1920
"react-native-safe-area-context": "4.5.1",
2021
"react-native-screens": "3.17.0"
2122
},
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright (c) React Native Community
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
*/
9+
10+
'use strict';
11+
12+
import React, { useEffect, useRef, useState } from 'react';
13+
import { View, Button, AppState } from 'react-native';
14+
import BackgroundTimer from 'react-native-background-timer';
15+
import Geolocation from '@react-native-community/geolocation';
16+
17+
export default function BackgroundLocationUpdates() {
18+
const appState = useRef(AppState.currentState);
19+
const [backgroundListener, setBackgroundListener] = useState(false);
20+
21+
useEffect(() => {
22+
if (!backgroundListener) {
23+
return;
24+
}
25+
26+
const subscription = AppState.addEventListener('change', (nextAppState) => {
27+
if (nextAppState.match(/inactive|background/)) {
28+
BackgroundTimer.runBackgroundTimer(() => {
29+
Geolocation.getCurrentPosition(
30+
(position) => {
31+
console.log(
32+
'getCurrentPosition background',
33+
JSON.stringify(position)
34+
);
35+
},
36+
(error) =>
37+
console.log(
38+
'getCurrentPosition background error',
39+
JSON.stringify(error)
40+
),
41+
{ enableHighAccuracy: true }
42+
);
43+
}, 1000);
44+
45+
console.log('App has come to the foreground!');
46+
} else {
47+
BackgroundTimer.stopBackgroundTimer();
48+
}
49+
50+
appState.current = nextAppState;
51+
});
52+
53+
return () => {
54+
subscription.remove();
55+
};
56+
}, [backgroundListener]);
57+
58+
return (
59+
<View>
60+
<Button
61+
title={`${
62+
backgroundListener ? 'Disable' : 'Enable'
63+
} background location updates`}
64+
onPress={() => setBackgroundListener(!backgroundListener)}
65+
/>
66+
</View>
67+
);
68+
}

example/src/configs/SetConfiguration.tsx

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ export default function SetConfigurationExample() {
4040
const [locationProvider, setLocationProvider] = useState<
4141
'playServices' | 'android' | 'auto'
4242
>('auto');
43+
const [enableBackgroundLocationUpdates, setEnableBackgroundLocationUpdates] =
44+
useState(false);
45+
4346
useEffect(() => {
4447
Geolocation.setRNConfiguration({
4548
skipPermissionRequests,
@@ -60,34 +63,47 @@ export default function SetConfigurationExample() {
6063
/>
6164
</View>
6265
{Platform.OS === 'ios' && (
63-
<View style={styles.row}>
64-
<Text>authorizationLevel</Text>
65-
<View style={styles.segmentControlContainer}>
66-
{authorizationLevelOptions.map((item, index) => (
67-
<TouchableOpacity
68-
key={`segmented-control-${index}`}
69-
onPress={() =>
70-
setAuthorizationLevel(authorizationLevelOptions[index])
71-
}
72-
style={[
73-
styles.segmentedControlButton,
74-
authorizationLevelOptions.indexOf(authorizationLevel) ===
75-
index && styles.segmentedControlButtonActive,
76-
]}
77-
>
78-
<Text
66+
<>
67+
<View style={styles.row}>
68+
<Text>authorizationLevel</Text>
69+
<View style={styles.segmentControlContainer}>
70+
{authorizationLevelOptions.map((item, index) => (
71+
<TouchableOpacity
72+
key={`segmented-control-${index}`}
73+
onPress={() =>
74+
setAuthorizationLevel(authorizationLevelOptions[index])
75+
}
7976
style={[
80-
styles.segmentControlText,
77+
styles.segmentedControlButton,
8178
authorizationLevelOptions.indexOf(authorizationLevel) ===
82-
index && styles.segmentControlTextActive,
79+
index && styles.segmentedControlButtonActive,
8380
]}
8481
>
85-
{item}
86-
</Text>
87-
</TouchableOpacity>
88-
))}
82+
<Text
83+
style={[
84+
styles.segmentControlText,
85+
authorizationLevelOptions.indexOf(authorizationLevel) ===
86+
index && styles.segmentControlTextActive,
87+
]}
88+
>
89+
{item}
90+
</Text>
91+
</TouchableOpacity>
92+
))}
93+
</View>
8994
</View>
90-
</View>
95+
<View style={styles.row}>
96+
<Text>enableBackgroundLocationUpdates</Text>
97+
<Switch
98+
onValueChange={() =>
99+
setEnableBackgroundLocationUpdates(
100+
!enableBackgroundLocationUpdates
101+
)
102+
}
103+
value={enableBackgroundLocationUpdates}
104+
/>
105+
</View>
106+
</>
91107
)}
92108
{Platform.OS === 'android' && (
93109
<View style={styles.row}>

example/src/configs/index.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import RequestAuthorization from './RequestAuthorization';
33
import SetConfiguration from './SetConfiguration';
4+
import BackgroundLocationUpdates from './BackgroundLocationUpdates';
45

56
const configs = [
67
{
@@ -20,6 +21,14 @@ const configs = [
2021
return <RequestAuthorization />;
2122
},
2223
},
24+
{
25+
id: 'backgroundLocationUpdates',
26+
title: 'getCurrentLoaction() in background',
27+
description: 'Test background location updates',
28+
render() {
29+
return <BackgroundLocationUpdates />;
30+
},
31+
},
2332
];
2433

2534
export default configs;

example/src/examples/WatchPosition.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default function WatchPositionExample() {
1818
try {
1919
const watchID = Geolocation.watchPosition(
2020
(position) => {
21+
console.log('watchPosition', JSON.stringify(position));
2122
setPosition(JSON.stringify(position));
2223
},
2324
(error) => Alert.alert('WatchPosition Error', JSON.stringify(error))

0 commit comments

Comments
 (0)