react-native-background-geolocation 5.5.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RNBackgroundGeolocation.podspec +1 -1
- package/android/src/main/java/com/transistorsoft/rnbackgroundgeolocation/RNBackgroundGeolocationModule.java +18 -4
- package/ios/RNBackgroundGeolocation/RNBackgroundGeolocation.mm +6 -3
- package/package.json +9 -6
- package/src/NativeModule.js +5 -2
- package/src/index.js +50 -3
- package/src/native/specs/NativeBackgroundGeolocation.ts +1 -1
- package/src/specs/NativeRNBackgroundGeolocation.js +1 -1
- package/tests/request-permission.test.js +78 -0
- package/tests-types/api-surface.ts +33 -0
- /package/tests/{enums-bridge-test.js → enums-bridge.test.js} +0 -0
|
@@ -26,7 +26,7 @@ Pod::Spec.new do |s|
|
|
|
26
26
|
s.source_files = 'ios/RNBackgroundGeolocation/*.{h,m,mm}'
|
|
27
27
|
s.preserve_paths = 'docs', 'CHANGELOG.md', 'LICENSE', 'package.json', 'RNBackgroundGeolocation.ios.js'
|
|
28
28
|
|
|
29
|
-
tslm_version = ENV['TSLOCATIONMANAGER_VERSION'] || '~> 4.
|
|
29
|
+
tslm_version = ENV['TSLOCATIONMANAGER_VERSION'] || '~> 4.6.0'
|
|
30
30
|
s.dependency 'TSLocationManager', tslm_version
|
|
31
31
|
|
|
32
32
|
s.libraries = 'sqlite3', 'z', 'stdc++'
|
|
@@ -4,6 +4,8 @@ import com.transistorsoft.rnbackgroundgeolocation.NativeRNBackgroundGeolocationS
|
|
|
4
4
|
|
|
5
5
|
import android.Manifest;
|
|
6
6
|
import android.app.Activity;
|
|
7
|
+
|
|
8
|
+
import androidx.annotation.Nullable;
|
|
7
9
|
import android.content.Context;
|
|
8
10
|
import android.content.Intent;
|
|
9
11
|
import android.os.Build;
|
|
@@ -990,15 +992,27 @@ public class RNBackgroundGeolocationModule
|
|
|
990
992
|
}
|
|
991
993
|
|
|
992
994
|
@ReactMethod
|
|
993
|
-
public void requestPermission(final Promise response) {
|
|
994
|
-
|
|
995
|
+
public void requestPermission(@Nullable final String permission, final Promise response) {
|
|
996
|
+
TSRequestPermissionCallback callback = new TSRequestPermissionCallback() {
|
|
995
997
|
@Override public void onSuccess(int status) {
|
|
996
998
|
response.resolve(status);
|
|
997
999
|
}
|
|
998
1000
|
@Override public void onFailure(int status) {
|
|
999
|
-
|
|
1001
|
+
// The error code carries the bare AuthorizationStatus — the JavaScript
|
|
1002
|
+
// layer normalizes the rejection to that value (cross-platform contract).
|
|
1003
|
+
response.reject(String.valueOf(status), String.valueOf(status));
|
|
1000
1004
|
}
|
|
1001
|
-
}
|
|
1005
|
+
};
|
|
1006
|
+
// (WO-007) permission ∈ "location" | "motion" | null (null = everything).
|
|
1007
|
+
// Null MUST route to the historical no-argument overload here in the bridge:
|
|
1008
|
+
// the string overload's own null-guard exists only in tslocationmanager >=
|
|
1009
|
+
// the WO-007 release — against an older AAR, handing it null would NPE inside
|
|
1010
|
+
// the adapter and crash every legacy requestPermission() call.
|
|
1011
|
+
if (permission == null) {
|
|
1012
|
+
getAdapter().requestPermission(callback);
|
|
1013
|
+
} else {
|
|
1014
|
+
getAdapter().requestPermission(permission, callback);
|
|
1015
|
+
}
|
|
1002
1016
|
}
|
|
1003
1017
|
|
|
1004
1018
|
@ReactMethod
|
|
@@ -658,12 +658,15 @@ RCT_EXPORT_METHOD(getProviderState:(RCTPromiseResolveBlock)resolve reject:(RCTPr
|
|
|
658
658
|
resolve([event toDictionary]);
|
|
659
659
|
}
|
|
660
660
|
|
|
661
|
-
RCT_EXPORT_METHOD(requestPermission:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
661
|
+
RCT_EXPORT_METHOD(requestPermission:(NSString * _Nullable)permission resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
662
662
|
{
|
|
663
|
-
|
|
663
|
+
// (WO-007) permission ∈ @"location" | @"motion" | nil (nil = everything).
|
|
664
|
+
[locationManager requestPermission:permission success:^(NSNumber *status) {
|
|
664
665
|
resolve(status);
|
|
665
666
|
} failure:^(NSNumber *status) {
|
|
666
|
-
|
|
667
|
+
// The error code carries the bare AuthorizationStatus — the JavaScript layer
|
|
668
|
+
// normalizes the rejection to that value (cross-platform contract).
|
|
669
|
+
reject([status stringValue], [status stringValue], nil);
|
|
667
670
|
}];
|
|
668
671
|
}
|
|
669
672
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
"
|
|
4
|
-
"version": "5.5.0",
|
|
2
|
+
"name": "react-native-background-geolocation",
|
|
3
|
+
"version": "5.6.0",
|
|
5
4
|
"description": "The most sophisticated cross-platform background location-tracking & geofencing module with battery-conscious motion-detection intelligence",
|
|
6
5
|
"scripts": {
|
|
7
6
|
"build": "yarn run build:expo",
|
|
8
|
-
"test": "
|
|
7
|
+
"test": "jest && tsc -p tests-types --noEmit",
|
|
9
8
|
"build:expo": "rimraf expo/plugin/build && tsc --build ./expo/plugin",
|
|
10
9
|
"docs": "node ./scripts/generate-docs.mjs",
|
|
11
10
|
"docs:publish": "./scripts/publish-docs.sh",
|
|
@@ -21,7 +20,7 @@
|
|
|
21
20
|
"ios": {
|
|
22
21
|
"swiftModuleName": "RNBackgroundGeolocation",
|
|
23
22
|
"packageName": "RNBackgroundGeolocation"
|
|
24
|
-
}
|
|
23
|
+
}
|
|
25
24
|
},
|
|
26
25
|
"main": "src/index.js",
|
|
27
26
|
"repository": {
|
|
@@ -41,7 +40,7 @@
|
|
|
41
40
|
],
|
|
42
41
|
"dependencies": {
|
|
43
42
|
"@babel/runtime": "^7.26.0",
|
|
44
|
-
"@transistorsoft/background-geolocation-types": "^5.
|
|
43
|
+
"@transistorsoft/background-geolocation-types": "^5.3.2",
|
|
45
44
|
"tslib": "^2.6.3"
|
|
46
45
|
},
|
|
47
46
|
"author": "Chris Scott <chris@transistorsoft.com>",
|
|
@@ -51,10 +50,14 @@
|
|
|
51
50
|
},
|
|
52
51
|
"homepage": "https://www.transistorsoft.com/shop/products/react-native-background-geolocation",
|
|
53
52
|
"devDependencies": {
|
|
53
|
+
"@babel/core": "^8.0.1",
|
|
54
|
+
"@babel/preset-env": "^8.0.2",
|
|
54
55
|
"@expo/config-plugins": "^4.1.0",
|
|
55
56
|
"@types/node": "^18.11.5",
|
|
57
|
+
"babel-jest": "^30.5.0",
|
|
56
58
|
"chalk": "^4.1.0",
|
|
57
59
|
"fs-extra": "^9.1.0",
|
|
60
|
+
"jest": "^30.5.0",
|
|
58
61
|
"path": "^0.12.7",
|
|
59
62
|
"rimraf": "^5.0.0",
|
|
60
63
|
"typescript": "^5.6.0"
|
package/src/NativeModule.js
CHANGED
|
@@ -170,8 +170,11 @@ export default class NativeModule {
|
|
|
170
170
|
return RNBackgroundGeolocation.configure(validateConfig(config));
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
static requestPermission() {
|
|
174
|
-
|
|
173
|
+
static requestPermission(permission) {
|
|
174
|
+
// (WO-007) permission ∈ 'location' | 'motion' | null (null = everything, the
|
|
175
|
+
// historical behaviour). Always pass the argument explicitly — both the
|
|
176
|
+
// TurboModule spec and the old-architecture bridge expect it.
|
|
177
|
+
return RNBackgroundGeolocation.requestPermission((typeof permission === 'string') ? permission : null);
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
static requestTemporaryFullAccuracy(purpose) {
|
package/src/index.js
CHANGED
|
@@ -24,9 +24,47 @@ import {
|
|
|
24
24
|
HttpMethod,
|
|
25
25
|
TriggerActivity,
|
|
26
26
|
ActivityType,
|
|
27
|
-
Event
|
|
27
|
+
Event,
|
|
28
|
+
Permission,
|
|
29
|
+
MotionActivityType,
|
|
30
|
+
TrackingMode,
|
|
31
|
+
LogLevelName,
|
|
32
|
+
GeofenceAction,
|
|
33
|
+
LocationError,
|
|
34
|
+
LocationFilterReason,
|
|
35
|
+
SQLQueryOrder
|
|
28
36
|
} from '@transistorsoft/background-geolocation-types';
|
|
29
37
|
|
|
38
|
+
// (WO-007) Named RUNTIME exports — every const-enum value the shared types package
|
|
39
|
+
// exports. index.d.ts has always re-exported the types package, but these objects
|
|
40
|
+
// only existed (partially) as statics on the default export — named value imports
|
|
41
|
+
// like `import { AuthorizationStatus }` were undefined at runtime. The jest parity
|
|
42
|
+
// test asserts this list stays complete against the installed types package.
|
|
43
|
+
export {
|
|
44
|
+
LogLevel,
|
|
45
|
+
DesiredAccuracy,
|
|
46
|
+
PersistMode,
|
|
47
|
+
AuthorizationStatus,
|
|
48
|
+
AccuracyAuthorization,
|
|
49
|
+
LocationRequest,
|
|
50
|
+
AuthorizationStrategy,
|
|
51
|
+
LocationFilterPolicy,
|
|
52
|
+
KalmanProfile,
|
|
53
|
+
NotificationPriority,
|
|
54
|
+
HttpMethod,
|
|
55
|
+
TriggerActivity,
|
|
56
|
+
ActivityType,
|
|
57
|
+
Event,
|
|
58
|
+
Permission,
|
|
59
|
+
MotionActivityType,
|
|
60
|
+
TrackingMode,
|
|
61
|
+
LogLevelName,
|
|
62
|
+
GeofenceAction,
|
|
63
|
+
LocationError,
|
|
64
|
+
LocationFilterReason,
|
|
65
|
+
SQLQueryOrder
|
|
66
|
+
};
|
|
67
|
+
|
|
30
68
|
// Build a lookup table of allowed event names (runtime)
|
|
31
69
|
const VALID_EVENT_NAMES = new Set(Object.values(Event));
|
|
32
70
|
|
|
@@ -160,6 +198,10 @@ export default class BackgroundGeolocation {
|
|
|
160
198
|
return AuthorizationStatus;
|
|
161
199
|
}
|
|
162
200
|
|
|
201
|
+
static get Permission() {
|
|
202
|
+
return Permission;
|
|
203
|
+
}
|
|
204
|
+
|
|
163
205
|
static get AccuracyAuthorization() {
|
|
164
206
|
return AccuracyAuthorization;
|
|
165
207
|
}
|
|
@@ -226,8 +268,13 @@ export default class BackgroundGeolocation {
|
|
|
226
268
|
return NativeModule.configure(config);
|
|
227
269
|
}
|
|
228
270
|
|
|
229
|
-
static requestPermission() {
|
|
230
|
-
return NativeModule.requestPermission()
|
|
271
|
+
static requestPermission(permission) {
|
|
272
|
+
return NativeModule.requestPermission(permission).catch((error) => {
|
|
273
|
+
// (WO-007) Cross-platform contract: reject with the bare AuthorizationStatus
|
|
274
|
+
// value (the natives carry it in the error code).
|
|
275
|
+
const status = parseInt(error.code, 10);
|
|
276
|
+
return Promise.reject(Number.isNaN(status) ? error : status);
|
|
277
|
+
});
|
|
231
278
|
}
|
|
232
279
|
|
|
233
280
|
static requestTemporaryFullAccuracy(purpose) {
|
|
@@ -31,7 +31,7 @@ export interface Spec extends TurboModule {
|
|
|
31
31
|
getDeviceInfo(): Promise<Object>;
|
|
32
32
|
isPowerSaveMode(): Promise<boolean>;
|
|
33
33
|
isIgnoringBatteryOptimizations(): Promise<boolean>;
|
|
34
|
-
requestPermission(): Promise<number>;
|
|
34
|
+
requestPermission(permission: string | null): Promise<number>;
|
|
35
35
|
requestTemporaryFullAccuracy(purpose: string): Promise<number>;
|
|
36
36
|
|
|
37
37
|
// Transistor token helpers
|
|
@@ -90,7 +90,7 @@ export interface Spec extends TurboModule {
|
|
|
90
90
|
+showSettings: (args: Object) => Promise<boolean>;
|
|
91
91
|
|
|
92
92
|
+getProviderState: () => Promise<Object>;
|
|
93
|
-
+requestPermission: () => Promise<Int32>;
|
|
93
|
+
+requestPermission: (permission: ?string) => Promise<Int32>;
|
|
94
94
|
+requestTemporaryFullAccuracy: (purpose: string) => Promise<Int32>;
|
|
95
95
|
|
|
96
96
|
// Required by NativeEventEmitter
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// (WO-007) JS-side marshaling for the per-permission requestPermission API: does the
|
|
2
|
+
// JavaScript layer forward the Permission selector to the native bridge boundary, and
|
|
3
|
+
// normalize native rejections to the bare AuthorizationStatus value the cross-platform
|
|
4
|
+
// contract documents? The native module is a jest spy standing in for the bridge.
|
|
5
|
+
|
|
6
|
+
const { NativeModules } = require('react-native'); // mapped to mocks/react-native.js via jest config
|
|
7
|
+
const BG = require('../src/index.js').default;
|
|
8
|
+
const { Permission, AuthorizationStatus } = require('../src/index.js');
|
|
9
|
+
|
|
10
|
+
const native = NativeModules.RNBackgroundGeolocation;
|
|
11
|
+
|
|
12
|
+
describe('named runtime exports (WO-007 regression)', () => {
|
|
13
|
+
// index.d.ts has always promised `export *` of the shared types package, but the
|
|
14
|
+
// runtime module exported only the default class — named VALUE imports were
|
|
15
|
+
// silently undefined (field: "Cannot read property 'Location' of undefined").
|
|
16
|
+
test('Permission and AuthorizationStatus are real values, importable by name', () => {
|
|
17
|
+
expect(Permission).toBeDefined();
|
|
18
|
+
expect(Permission.Location).toBe('location');
|
|
19
|
+
expect(Permission.Motion).toBe('motion');
|
|
20
|
+
expect(AuthorizationStatus).toBeDefined();
|
|
21
|
+
expect(AuthorizationStatus.DeniedAlways).toBe(5);
|
|
22
|
+
// The class statics remain, unchanged.
|
|
23
|
+
expect(BG.Permission).toBe(Permission);
|
|
24
|
+
expect(BG.AuthorizationStatus).toBe(AuthorizationStatus);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Drift-proof: EVERY runtime value the types package exports must be re-exported
|
|
28
|
+
// by name from this module — a hardcoded list rots (the first fix missed 7 of 22).
|
|
29
|
+
test('every types-package runtime export is re-exported by name', () => {
|
|
30
|
+
const typesPkg = require('@transistorsoft/background-geolocation-types');
|
|
31
|
+
const sdk = require('../src/index.js');
|
|
32
|
+
const runtimeKeys = Object.keys(typesPkg).filter((k) => k !== 'default' && k !== '__esModule');
|
|
33
|
+
expect(runtimeKeys.length).toBeGreaterThan(0);
|
|
34
|
+
for (const key of runtimeKeys) {
|
|
35
|
+
expect(sdk[key]).toBe(typesPkg[key]);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('requestPermission — JS -> native bridge marshaling (WO-007)', () => {
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
jest.restoreAllMocks();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('forwards the permission selector to the native module', async () => {
|
|
46
|
+
const request = jest.spyOn(native, 'requestPermission').mockResolvedValue(3);
|
|
47
|
+
|
|
48
|
+
await expect(BG.requestPermission('location')).resolves.toBe(3);
|
|
49
|
+
expect(request).toHaveBeenLastCalledWith('location');
|
|
50
|
+
|
|
51
|
+
await expect(BG.requestPermission('motion')).resolves.toBe(3);
|
|
52
|
+
expect(request).toHaveBeenLastCalledWith('motion');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('the no-argument form passes an explicit null (both bridge architectures expect the slot)', async () => {
|
|
56
|
+
const request = jest.spyOn(native, 'requestPermission').mockResolvedValue(4);
|
|
57
|
+
|
|
58
|
+
await expect(BG.requestPermission()).resolves.toBe(4);
|
|
59
|
+
expect(request).toHaveBeenLastCalledWith(null);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('normalizes a native rejection to the bare AuthorizationStatus carried in the error code', async () => {
|
|
63
|
+
// Both natives reject with code = String(status).
|
|
64
|
+
const error = new Error('5');
|
|
65
|
+
error.code = '5';
|
|
66
|
+
jest.spyOn(native, 'requestPermission').mockRejectedValue(error);
|
|
67
|
+
|
|
68
|
+
await expect(BG.requestPermission('motion')).rejects.toBe(5); // DeniedAlways
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('passes an unparseable native error through unchanged', async () => {
|
|
72
|
+
const error = new Error('bridge exploded');
|
|
73
|
+
error.code = 'E_UNEXPECTED';
|
|
74
|
+
jest.spyOn(native, 'requestPermission').mockRejectedValue(error);
|
|
75
|
+
|
|
76
|
+
await expect(BG.requestPermission()).rejects.toBe(error);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Type-surface assertions — compile-only, no runtime. (WO-007)
|
|
2
|
+
//
|
|
3
|
+
// Verifies the per-permission requestPermission API against the published
|
|
4
|
+
// @transistorsoft/background-geolocation-types surface this package re-exports.
|
|
5
|
+
import BackgroundGeolocation, {
|
|
6
|
+
Permission,
|
|
7
|
+
AuthorizationStatus,
|
|
8
|
+
} from "react-native-background-geolocation";
|
|
9
|
+
|
|
10
|
+
async function requestPermissionSurface(): Promise<void> {
|
|
11
|
+
// A-form: no argument — everything the configuration requires.
|
|
12
|
+
const all: AuthorizationStatus = await BackgroundGeolocation.requestPermission();
|
|
13
|
+
|
|
14
|
+
// B-form: location only.
|
|
15
|
+
const location: AuthorizationStatus =
|
|
16
|
+
await BackgroundGeolocation.requestPermission(Permission.Location);
|
|
17
|
+
|
|
18
|
+
// C-form: motion only; DeniedAlways is the Android permanent-denial status.
|
|
19
|
+
try {
|
|
20
|
+
const motion: AuthorizationStatus =
|
|
21
|
+
await BackgroundGeolocation.requestPermission(Permission.Motion);
|
|
22
|
+
void motion;
|
|
23
|
+
} catch (status) {
|
|
24
|
+
if (status === AuthorizationStatus.DeniedAlways) {
|
|
25
|
+
// Only the app-settings screen can restore the motion permission now.
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void all;
|
|
30
|
+
void location;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void requestPermissionSurface;
|
|
File without changes
|