transistorsoft / react-native-background-geolocation

Sophisticated, battery-conscious background-geolocation with motion-detection
http://shop.transistorsoft.com/pages/react-native-background-geolocation
MIT License
2.66k stars 426 forks source link

Location permission manual request not always works #2201

Open Crysp opened 2 weeks ago

Crysp commented 2 weeks ago

Option disableLocationAuthorizationAlert doesn't work as expected. Permission is requested at app startup.

Your Environment

Standalone component to reproduce

import React, { useCallback, useEffect, useState } from 'react';
import { Button } from 'react-native';
import RNBG from 'react-native-background-geolocation';

export const BugReportExample = () => {
  const [enabled, setEnabled] = useState(false);
  const onStart = useCallback(() => {
    RNBG.start(state => {
      setEnabled(state.enabled);
    });
  }, []);
  const onStop = useCallback(() => {
    RNBG.stop(state => {
      setEnabled(state.enabled);
    });
  }, []);

  useEffect(() => {
    RNBG.ready({
      reset: true,
      stopOnTerminate: false,
      disableLocationAuthorizationAlert: true,
      locationAuthorizationRequest: 'Any',
    }).then(state => {
      setEnabled(state.enabled);
    });
  }, []);

  return (
    <Button
      title={enabled ? 'Stop' : 'Start'}
      onPress={enabled ? onStop : onStart}
    />
  );
};

Expected Behavior

If some requirement is missed (for proper plug-in work) and I tell that I manually controlling requests (disableLocationAuthorizationAlert: true), there should be some warning or error during plug-in preparation (inside ready).

Actual Behavior

If location permission is missed (for "permanent" mode), plug-in will request it at app startup.

Steps to Reproduce

  1. Plug-in works in "permanent" mode (launches in background)
  2. Revoke all app permissions
  3. Launch the app
  4. Location permission appears at app startup

Context

I want to request location permission my own no matter the plug-in state is

Debug logs

Logs ``` PASTE_YOUR_LOGS_HERE ```
christocracy commented 2 weeks ago

disableLocationAuthorizationAlert

This option doesn’t do what you think it does. Read about it in the api docs.

if you do not want the plug-in to request permission, don’t tell it to .start(). Calling .start() always requests permission.

listen to .onProviderChange event to learn about changes in permission.

Crysp commented 2 weeks ago

No, you probably didn't understand me. Permission request at start is ok and pretty transparent.

Steps:

  1. Call start
  2. Grant necessary permission
  3. Plug-in works in "permanent" mode
  4. Terminate the app
  5. Revoke permission
  6. Launch the app
  7. Permission request appears at app startup (without any actions)
christocracy commented 2 weeks ago

The plugin's State.enabled is persisted throughout app restarts / device reboots.

Therefore, before calling .ready(config), you must analyze the current state of permissions using .getProviderState().

var providerState = await BackgroundGeolocation.getProviderState();

if (!providerState.enabled) {
  // If you find location-services is disabled, you must tell the plugin to .stop(), 
  // which sets State.enabled -> false
  BackgoundGeolocation.stop();
}
.
.
.
BackgroundGeolocation.ready(config)
Crysp commented 2 weeks ago

It doesn't work as you write. Request still appears at app startup

import React, { useCallback, useEffect, useState } from 'react';
import { Button } from 'react-native';
import RNBG from 'react-native-background-geolocation';

export const BugReportExample = () => {
  const [enabled, setEnabled] = useState(false);
  const onStart = useCallback(() => {
    RNBG.start(state => {
      setEnabled(state.enabled);
    });
  }, []);
  const onStop = useCallback(() => {
    RNBG.stop(state => {
      setEnabled(state.enabled);
    });
  }, []);

  useEffect(() => {
    RNBG.getProviderState().then(async providerState => {
      if (providerState.enabled) {
        await RNBG.stop();
      }

      RNBG.ready({
        reset: true,
        stopOnTerminate: false,
        disableLocationAuthorizationAlert: true,
        locationAuthorizationRequest: 'Any',
      }).then(state => {
        setEnabled(state.enabled);
      });
    });
  }, []);

  return (
    <Button
      title={enabled ? 'Stop' : 'Start'}
      onPress={enabled ? onStop : onStart}
    />
  );
};
christocracy commented 2 weeks ago

It doesn't work as you write

That’s not how I wrote it.

The plug-in API is asynchronous. You need to await the call to .getProviderState() within an async function, guaranteeing it executes before calling .ready.

Crysp commented 2 weeks ago

I'm calling ready inside getProviderState promise resolve callback. So I think code is identical

christocracy commented 2 weeks ago

Compare your logic:

if (providerState.enabled)

with mine:

if (!providerState.enabled) {

if NOT enabled. If location-services are disabled, then .stop().

Crysp commented 2 weeks ago

Ah, thx. But permission still requesting πŸ€·β€β™‚οΈ

Crysp commented 2 weeks ago

Provider state resolves to

{
  "accuracyAuthorization": 0,
  "enabled": false,
  "gps": true,
  "network": true,
  "status": 0
}

I think there is some logic in native code that requests permission

christocracy commented 2 weeks ago

The plugin only requests permission if the plugin is State.enabled.

Are you observing the plugin logs in $ adb logcat? See Wiki "Debugging".

Crysp commented 2 weeks ago

iOS Logs at the app startup with "unexpected" permission request

[Info, common]: Using Mapbox Common SDK v24.6.1(562d5cb0e)
[Info, maps-core]: Using Mapbox Core Maps SDK v11.6.1(dae86f79c0)
[TSBackgroundFetch load]: (
)
[TSBGAppRefreshSubscriber load]: {
    TSLocationManager = "<TSBGAppRefreshSubscriber identifier=TSLocationManager, executed=0, enabled=1>";
}
10.25.0 - [FirebaseInstallations][I-FIS002000] -[FIRInstallationsIDController createGetInstallationItemPromise], appName: __FIRAPP_DEFAULT
10.25.0 - [FirebaseMessaging][I-FCM043000] Info is not found in Keychain. OSStatus: -25300. Keychain query: {
    acct = "com.teemco.meetinger";
    class = genp;
    gena = "com.google.iid";
    "m_Limit" = "m_LimitAll";
    nleg = 1;
    "r_Attributes" = 1;
    "r_Data" = 1;
    svce = "com.google.iid.checkin";
}
10.25.0 - [FirebaseMessaging][I-FCM033009] App reset detected but no valid checkin auth preferences found. Will not delete server token registrations.
10.25.0 - [FirebaseMessaging][I-FCM002000] FIRMessaging library version 10.25.0
10.25.0 - [GULReachability][I-REA902003] Monitoring the network status
10.25.0 - [FirebaseMessaging][I-FCM043000] Info is not found in Keychain. OSStatus: -25300. Keychain query: {
    acct = "com.teemco.meetinger";
    class = genp;
    gena = "com.google.iid-tokens";
    "m_Limit" = "m_LimitAll";
    nleg = 1;
    "r_Attributes" = 1;
    "r_Data" = 1;
    svce = "684149350965:*";
}
10.25.0 - [FirebaseMessaging][I-FCM001000] FIRMessaging Remote Notifications proxy enabled, will swizzle remote notification receiver handlers. If you'd prefer to manually integrate Firebase Messaging, add "FirebaseAppDelegateProxyEnabled" to your Info.plist, and set it to NO. Follow the instructions at:
https://firebase.google.com/docs/cloud-messaging/ios/client#method_swizzling_in_firebase_messaging
to ensure proper integration.
10.25.0 - [GoogleUtilities/AppDelegateSwizzler][I-SWZ001008] Successfully created App Delegate Proxy automatically. To disable the proxy, set the flag GoogleUtilitiesAppDelegateProxyEnabled to NO (Boolean) in the Info.plist
10.25.0 - [FirebaseAnalytics][I-ACS024000] Debug mode is on
10.25.0 - [GULReachability][I-REA902003] Monitoring the network status
10.25.0 - [FirebaseAnalytics][I-ACS023007] Analytics v.10.25.0 started
Running application meetinger ({
    initialProps =     {
        concurrentRoot = 0;
    };
    rootTag = 1;
})
10.25.0 - [FirebaseAnalytics][I-ACS023008] To disable debug logging set the following application argument: -noFIRAnalyticsDebugEnabled (see http://goo.gl/RfcP7r)
10.25.0 - [FirebaseAnalytics][I-ACS023009] Debug logging enabled
10.25.0 - [FirebaseAnalytics][I-ACS023207] To enable verbose logging set the following application argument: -FIRAnalyticsVerboseLoggingEnabled (see http://goo.gl/RfcP7r)
10.25.0 - [GULReachability][I-REA902003] Monitoring the network status
10.25.0 - [FirebaseAnalytics][I-ACS044000] GoogleAppMeasurementIdentitySupport dependency is linked.
10.25.0 - [FirebaseAnalytics][I-ACS044002] The AdSupport Framework is not currently linked. Some features will not function properly. Learn more at http://goo.gl/9vSsPb
10.25.0 - [FirebaseAnalytics][I-ACS031010] Tracking view controller. Class, ID: UIViewController, 7070580397397364186
10.25.0 - [FirebaseCore][I-COR000033] Data Collection flag is not set.
10.25.0 - [GULReachability][I-REA902004] Network status has changed. Code:2, status:Connected
10.25.0 - [GULReachability][I-REA902004] Network status has changed. Code:2, status:Connected
10.25.0 - [GULReachability][I-REA902004] Network status has changed. Code:2, status:Connected
ℹ️-[TSLocationManager init] 
╔═════════════════════════════════════════════
β•‘ TSLocationManager (build 388)
╠══════════════════════════════════════════════
{
    activityRecognitionInterval = 10000;
    activityType = 1;
    authorization =     {
    };
    autoSync = 1;
    autoSyncThreshold = 0;
    batchSync = 0;
    debug = 0;
    desiredAccuracy = "-1";
    desiredOdometerAccuracy = 100;
    didDeviceReboot = 0;
    didLaunchInBackground = 0;
    didRequestUpgradeLocationAuthorization = 0;
    disableAutoSyncOnCellular = 0;
    disableElasticity = 0;
    disableLocationAuthorizationAlert = 1;
    disableMotionActivityUpdates = 0;
    disableStopDetection = 0;
    distanceFilter = 10;
    elasticityMultiplier = 1;
    enableTimestampMeta = 0;
    enabled = 1;
    extras =     {
    };
    geofenceInitialTrig
ℹ️-[GeofenceDAO init] CREATE TABLE IF NOT EXISTS geofences (id INTEGER PRIMARY KEY AUTOINCREMENT, identifier TEXT NOT NULL UNIQUE, latitude DOUBLE NOT NULL, sin_latitude DOUBLE NOT NULL, cos_latitude DOUBLE NOT NULL, longitude DOUBLE NOT NULL, sin_longitude DOUBLE NOT NULL, cos_longitude DOUBLE NOT NULL, radius DOUBLE NOT NULL, notifyOnEntry BOOLEAN NOT NULL DEFAULT 0, notifyOnExit BOOLEAN NOT NULL DEFAULT 0, notifyOnDwell BOOLEAN NOT NULL DEFAULT 0, loiteringDelay DOUBLE NOT NULL DEFAULT 0, extras TEXT, vertices TEXT)
ℹ️-[GeofenceDAO init] CREATE index IF NOT EXISTS identifier ON geofences (identifier);CREATE index IF NOT EXISTS latitude ON geofences (latitude);CREATE index IF NOT EXISTS longitude ON geofences (longitude);CREATE index IF NOT EXISTS sin_latitude ON geofences (sin_latitude);CREATE index IF NOT EXISTS cos_latitude ON geofences (cos_latitude);CREATE index IF NOT EXISTS sin_longitude ON geofences (sin_longitude);CREATE index IF NOT EXISTS cos_longitude ON geofences (cos_longitude);
-[RNFBAppModule setLogLevel:] [Line 254] RNFBSetLogLevel: setting level to 3 from error.
+[RNFBAppModule getCustomDomain:] [Line 239] authDomains:
ℹ️-[TSConfig persist]
πŸ”΅-[TSLocationManager locationManager:didChangeAuthorizationStatus:] status 0
πŸ”΅-[LocationManager locationManager:didChangeAuthorizationStatus:] 0
πŸ”΅-[PolygonGeofencingService locationManager:didChangeAuthorizationStatus:] 0
πŸ”΅-[LocationManager locationManager:didChangeAuthorizationStatus:] 0
πŸ”΅-[BackgroundTaskManager locationManager:didChangeAuthorizationStatus:] 0
πŸ”΅-[LocationManager locationManager:didChangeAuthorizationStatus:] 0
ℹ️+[LocationAuthorization run:onCancel:] status: 0
πŸ”΅+[LocationAuthorization run:onCancel:] Request: requestAnyAuthorization
10.25.0 - [FirebaseMessaging][I-FCM012002] Error in application:didFailToRegisterForRemoteNotificationsWithError: no valid β€œaps-environment” entitlement string found for application
ℹ️-[Logger writeNative:] Application - Resign active - provider: native
nw_socket_handle_socket_event [C4.1.1:1] Socket SO_ERROR 61
nw_endpoint_flow_failed_with_error [C4.1.1 ::1.8097 in_progress socket-flow (satisfied (Path is satisfied), interface: lo0)] already failing, returning
nw_socket_handle_socket_event [C4.1.2:1] Socket SO_ERROR 61
nw_endpoint_flow_failed_with_error [C4.1.2 127.0.0.1:8097 in_progress socket-flow (satisfied (Path is satisfied), interface: lo0)] already failing, returning
nw_endpoint_flow_failed_with_error [C4.1.2 127.0.0.1:8097 cancelled socket-flow ()] already failing, returning
nw_connection_get_connected_socket_block_invoke [C4] Client called nw_connection_get_connected_socket on unconnected nw_connection
TCP Conn 0x10727f330 Failed : error 0:61 [61]
Unbalanced calls start/end for tag 19
Running "meetinger" with {"rootTag":1,"initialProps":{"concurrentRoot":false}}
nw_connection_copy_connected_local_endpoint_block_invoke [C6] Connection has no local endpoint
nw_connection_copy_connected_local_endpoint_block_invoke [C6] Connection has no local endpoint
nw_connection_copy_connected_local_endpoint_block_invoke [C6] Connection has no local endpoint
ℹ️-[TSConfig persist]
ℹ️-[TSLocationManager clearLastOdometerLocation]
πŸ”΄-[TSGeofenceManager stop]
πŸ”΄-[TSGeofenceManager stopMonitoringGeofences]
πŸ”΄-[PolygonGeofencingService stop]
ℹ️-[PolygonGeofencingService persistMonitoredPolygons] {
}
πŸ”΄-[TSLocationManager stopUpdatingLocation]
πŸ”΄-[TSLocationManager stopMonitoringBackgroundFetch] BackgroundFetch: OFF
πŸ”΄-[TSLocationManager stopMonitoringSignificantLocationChanges]
ℹ️-[TSLocationManager on:success:failure:] location
ℹ️-[TSLocationManager on:success:failure:] motionchange
ℹ️-[TSLocationManager on:success:failure:] activitychange
ℹ️-[TSLocationManager on:success:failure:] heartbeat
ℹ️-[TSGeofenceManager onGeofence:]
ℹ️-[TSGeofenceManager onGeofencesChange:]
ℹ️-[TSLocationManager on:success:failure:] http
ℹ️-[TSLocationManager on:success:failure:] providerchange
ℹ️-[TSLocationManager on:success:failure:] schedule
ℹ️-[TSLocationManager on:success:failure:] powersavechange
ℹ️-[TSHttpService onConnectivityChange:]
ℹ️-[TSLocationManager on:success:failure:] enabledchange
ℹ️-[TSHttpService onAuthorization:]
ℹ️-[TSConfig persist]
ℹ️-[TSConfig persist]
πŸ”΅-[TSLocationManager ready]
christocracy commented 2 weeks ago

These logs and your simple reproduction app are helpful. I’ll look into it.