A Flutter plugin for updating location in background.

Last update: May 9, 2022

background_locator pub package

A Flutter plugin for getting location updates even when the app is killed.

demo

Refer to wiki page for install and setup instruction or jump to specific subject with below links:

License

This project is licensed under the MIT License - see the LICENSE file for details

Contributor

Thanks to all who contributed on this plugin to fix bugs and adding new feature, including:

GitHub

https://github.com/rekab-app/background_locator
Comments
  • 1. Issue on Android: Not capture when app is closed, but shows notification

    Hello.

    Testing in Android, plugin works fine, but have an issue: When close app, the notification baloon still shows on device; but stop capturing. There is some extra config to do when close app ?

    Settings:

    BackgroundLocator.registerLocationUpdate(
        (LocationDto locationDto) async {
            print('location in dart: ${locationDto.toString()}');
            final SendPort send = IsolateNameServer.lookupPortByName(_isolateName);
            send?.send(locationDto);
        },
        androidNotificationCallback: notificationCallback() {
            print('Background Location notificationCallback');
        },
        settings: LocationSettings(
            notificationTitle: "Notification title",
            notificationMsg: "Notification text",
            wakeLockTime: 20,
            autoStop: false,
            interval: 600, // 10 minutes interval
        ),
    );
    
    Reviewed by wemersonrv at 2020-04-04 22:27
  • 2. App stops after 5 minutes on Android with the screen turned off

    Hi! First of all, wonderful plugin, thanks to the devs.

    Now there is a problem with my app. I am trying to create an activity tracker (running, bicycle...), and I need a background gps tracking system to track user position and speed in the background.

    The problem is that after exactly 5 minutes with the screen turned off (a person running will keep their phone in their pocket, with the screen turned off), the app stops working and tracking the position. Running it in an Android 10 emulator.

    I have a brand new project with the same code as in the installation guide, plus integrated shared preferences plugin to store data. What I've tried is disabling battery optimizations on stock Android emulator, but still nothing. However the app isn't killed when the screen isn't turned off. The notification (although not permanent/uncancellable, this may be the cause) is present. The app works fine on iOS even with the screen turned off.

    I am really lost and don't have any idea on what to do since nobody else seems having this problem. I am thinking to send regular notifications every 4 minutes to wake up the phone, but I don't know if the app may be allowed on the play store/app store, and don't know if it would work since there is already the default notification which is updated every 2 seconds.

    I've tried running adb logcat to see if the system is going into some battery optimization sleep mode, but not even a hint:

    11-30 03:04:31.841  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:31.903 22510 23088 I flutter : SendPort
    11-30 03:04:31.903 22510 22669 I flutter : on receive isolate data
    11-30 03:04:31.903 22510 22669 I flutter : LocationDto{latitude: 37.4219983, longitude: -122.084, accuracy: 20.0, altitude: 5.0, speed: 0.0, speedAccuracy: 0.0, heading: 0.0, time: 1606701915000.0, isMocked: false}
    11-30 03:04:31.904 22510 22669 I flutter : Instance of 'SharedPreferences'
    11-30 03:04:31.904 22510 22669 I flutter : position saved to prefs
    11-30 03:04:31.905 22510 22669 I flutter : updated notification
    11-30 03:04:32.844  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:32.844  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:33.848  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:33.848  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:33.910 22510 23088 I flutter : SendPort
    11-30 03:04:33.911 22510 22669 I flutter : on receive isolate data
    11-30 03:04:33.911 22510 22669 I flutter : LocationDto{latitude: 37.4219983, longitude: -122.084, accuracy: 20.0, altitude: 5.0, speed: 0.0, speedAccuracy: 0.0, heading: 0.0, time: 1606701917000.0, isMocked: false}
    11-30 03:04:33.911 22510 22669 I flutter : Instance of 'SharedPreferences'
    11-30 03:04:33.911 22510 22669 I flutter : position saved to prefs
    11-30 03:04:33.912 22510 22669 I flutter : updated notification
    --- THE APP HAS BEEN KILLED BY NOW ---
    11-30 03:04:34.853  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:34.853  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:35.238  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:35.238  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:35.247  2257  2257 W View    : requestLayout() improperly called by com.android.keyguard.AlphaOptimizedLinearLayout{43d94cf V.E...... ......ID 7,0-48,61 #7f0a041c app:id/wifi_group} during layout: running second layout pass
    11-30 03:04:35.857  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:35.857  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:36.860  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:36.860  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:37.863  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:37.863  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:38.868  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:38.868  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:39.868  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    11-30 03:04:39.869  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    11-30 03:04:40.870  1750  2445 E GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    

    Also, this is what the adb shell dumpsys activity services (to show running services) looks like (including only results where the app name com.skuu.test_gps is mentioned):

    [email protected] ~ % adb shell dumpsys activity services
    ACTIVITY MANAGER SERVICES (dumpsys activity services)
      User 0 active services:
      ...
      * ServiceRecord{f8bc66c u0 com.skuu.test_gps/rekab.app.background_locator.IsolateHolderService}
        intent={act=START cmp=com.skuu.test_gps/rekab.app.background_locator.IsolateHolderService}
        packageName=com.skuu.test_gps
        processName=com.skuu.test_gps
        permission=android.permission.FOREGROUND_SERVICE
        baseDir=/data/app/com.skuu.test_gps-PSh_UuDdM8JXBTFISzogVA==/base.apk
        dataDir=/data/user/0/com.skuu.test_gps
        app=ProcessRecord{273e00f 22510:com.skuu.test_gps/u0a136}
        isForeground=true foregroundId=1 foregroundNoti=Notification(channel=app.rekab/locator_plugin pri=1 contentView=null vibrate=null sound=null defaults=0x0 flags=0x6a color=0xff9e9e9e vis=PRIVATE)
        createTime=-2m24s858ms startingBgTimeout=--
        lastActivity=-659ms restartTime=-2m24s857ms createdFromFg=true
        startRequested=true delayedStop=false stopIfKilled=false callStart=true lastStartId=69
    
      * ServiceRecord{ae77366 u0 com.google.android.gms/com.google.android.location.internal.GoogleLocationManagerService}
        intent={act=com.google.android.location.internal.GoogleLocationManagerService.START pkg=com.google.android.gms}
        packageName=com.google.android.gms
        processName=com.google.android.gms.persistent
        baseDir=/data/app/com.google.android.gms-VMmaef8awA98_Pupd2d0Xw==/base.apk
        dataDir=/data/user/0/com.google.android.gms
        app=ProcessRecord{2379889 12582:com.google.android.gms.persistent/u0a97}
        createTime=-2h34m56s969ms startingBgTimeout=--
        lastActivity=-2m24s149ms restartTime=-2h34m56s969ms createdFromFg=true
        startRequested=true delayedStop=false stopIfKilled=false callStart=true lastStartId=3
        Bindings:
        * IntentBindRecord{a1fb84a CREATE}:
          intent={act=com.google.android.location.internal.GoogleLocationManagerService.START pkg=com.google.android.gms}
          [email protected]
          requested=true received=true hasBound=true doRebind=false
          * Client AppBindRecord{28f30d8 ProcessRecord{273e00f 22510:com.skuu.test_gps/u0a136}}
            Per-process Connections:
              ConnectionRecord{9b9a6be u0 CR WACT com.google.android.gms/com.google.android.location.internal.GoogleLocationManagerService:@214d979}
        All Connections:
          ConnectionRecord{9b9a6be u0 CR WACT com.google.android.gms/com.google.android.location.internal.GoogleLocationManagerService:@214d979}
    
      Connection bindings to services:
      * ConnectionRecord{9b9a6be u0 CR WACT com.google.android.gms/com.google.android.location.internal.GoogleLocationManagerService:@214d979}
        binding=AppBindRecord{28f30d8 com.google.android.gms/com.google.android.location.internal.GoogleLocationManagerService:com.skuu.test_gps}
        [email protected] flags=0x81
    
    Active foreground apps - user 0:
      #0: com.skuu.test_gps
        mNumActive=1 mAppOnTop=false mShownWhileTop=true mShownWhileScreenOn=true
        mStartTime=-2m24s682ms mStartVisibleTime=-2m24s682ms
    [email protected] ~ % 
    

    Thank you.

    Reviewed by Ivaskuu at 2020-11-29 23:09
  • 3. [iOS] Doesn't work on app killed

    I downloaded the project and tested it against the provided example app. I installed it in a real iOS device and started it. Started getting a few sparse location, went to background and the project didn't show any notification but still got a few updates. As soon as you kill the app it stops.

    Other info: Had to get some work done according to the iOS migration guide to get it to work with XCode 11

    Tested with iPhone XR - 13.4.1

    Reviewed by martofeld at 2020-05-02 15:11
  • 4. iOS other plugins in callback fail?

    The code provided here: https://github.com/rekab-app/background_locator/wiki/Use-other-plugins-in-callback

    I'm trying to link in a background locator using cloud_firestore. The app uses firestore in many other locations.

    On iOS only, after initPlatformState (BackgroundLocator.initialize in specific), my future firestore queries get hung in Waiting connection state.

    There are no visible errors otherwise and the code works fine on Android.

    Reviewed by shaunramsey at 2020-10-19 15:38
  • 5. unRegisterLocationUpdate don't stop the Isolate

    Hi I have some issue with the plugins not stopping the Isolate, I'm creating a new file with a new name every time in a specific directory before launching the plugins and the plugins retrieve this file by listing every files in this directory (I store the date and a string in the name to not creating a special db for this), the file is stored in static File _currentFile; at the top of the class to not list the directory every callback. When its finished I stop the plugin using

    BackgroundLocator.unRegisterLocationUpdate();
    IsolateNameServer.removePortNameMapping(_isolateName);
    

    I copy the file and delete it in the directory. When I recreate another file and re-launch the plugin it will see that _currentFile is not null and write to it even though its not the file I want.

    I tried the example and its the same, by clicking stop I still see the plugin's thread running in VScode

    Reviewed by RomanJos at 2020-04-06 13:50
  • 6. iOS 14+ crash on app startup when location set to 'Always Allow'

    Using release 1.6.3

    When changing iOS permissions from 'Allow only while using App to 'Always allow' when prompted, the iOS app crashes on startup.

    At first, the app launches fine with no issues for a few hours after setting the location permissions to 'Always allow'. Thereafter the app seems to crash consistently on app startup.

    Note: Setting the location permissions back to 'Only while using the app' removes the crash and the app then functions fine again.

    Here are some error logs:

    Fatal Exception: NSInternalInconsistencyException
    Sending a message before the FlutterEngine has been run.
    Fatal Exception: NSInternalInconsistencyException
    0  CoreFoundation                 0x1a7dd9754 __exceptionPreprocess
    1  libobjc.A.dylib                0x1bc8a07a8 objc_exception_throw
    2  CoreFoundation                 0x1a7cdb3f8 -[CFPrefsSearchListSource addManagedSourceForIdentifier:user:]
    3  Foundation                     0x1a90af714 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
    4  Flutter                        0x10288115c (Missing)
    5  background_locator             0x10268b8fc (Missing)
    6  background_locator             0x10268c864 (Missing)
    7  background_locator             0x10268c638 (Missing)
    8  background_locator             0x10268ba50 (Missing)
    9  Flutter                        0x10288d15c (Missing)
    10 Runner                         0x100e97674 AppDelegate.application(_:didFinishLaunchingWithOptions:) + 24 (AppDelegate.swift:24)
    11 Runner                         0x100e977a8 @objc AppDelegate.application(_:didFinishLaunchingWithOptions:) (<compiler-generated>)
    12 UIKitCore                      0x1aa7c37a8 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:]
    13 UIKitCore                      0x1aa7c523c -[UIApplication _callInitializationDelegatesWithActions:forCanvas:payload:fromOriginatingProcess:]
    14 UIKitCore                      0x1aa7cb388 -[UIApplication _runWithMainScene:transitionContext:completion:]
    15 UIKitCore                      0x1a9e1ec98 -[_UISceneLifecycleMultiplexer completeApplicationLaunchWithFBSScene:transitionContext:]
    16 UIKitCore                      0x1aa387f58 _UIScenePerformActionsWithLifecycleActionMask
    17 UIKitCore                      0x1a9e1f830 __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke
    18 UIKitCore                      0x1a9e1f238 -[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:]
    19 UIKitCore                      0x1a9e1f640 -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]
    20 UIKitCore                      0x1a9e1ee7c -[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:]
    21 UIKitCore                      0x1a9e273c0 __186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke
    22 UIKitCore                      0x1aa295970 +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:actions:completion:]
    23 UIKitCore                      0x1aa3a0d68 _UISceneSettingsDiffActionPerformChangesWithTransitionContext
    24 UIKitCore                      0x1a9e270b8 -[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]
    25 UIKitCore                      0x1a9c4efa0 __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke
    26 UIKitCore                      0x1a9c4d920 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:]
    27 UIKitCore                      0x1a9c4ebc8 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:]
    28 UIKitCore                      0x1aa7c9528 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:]
    29 UIKitCore                      0x1aa2befd0 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:]
    30 FrontBoardServices             0x1b736b5d8 -[FBSScene _callOutQueue_agent_didCreateWithTransitionContext:completion:]
    31 FrontBoardServices             0x1b7396d44 __94-[FBSWorkspaceScenesClient createWithSceneID:groupID:parameters:transitionContext:completion:]_block_invoke.200
    32 FrontBoardServices             0x1b737a6a4 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]
    33 FrontBoardServices             0x1b7396a0c __94-[FBSWorkspaceScenesClient createWithSceneID:groupID:parameters:transitionContext:completion:]_block_invoke
    34 libdispatch.dylib              0x1a79c681c _dispatch_client_callout
    35 libdispatch.dylib              0x1a79ca30c _dispatch_block_invoke_direct
    36 FrontBoardServices             0x1b73befa0 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__
    37 FrontBoardServices             0x1b73bec30 -[FBSSerialQueue _targetQueue_performNextIfPossible]
    38 FrontBoardServices             0x1b73bf184 -[FBSSerialQueue _performNextFromRunLoopSource]
    39 CoreFoundation                 0x1a7d539e8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
    40 CoreFoundation                 0x1a7d538e4 __CFRunLoopDoSource0
    41 CoreFoundation                 0x1a7d52be8 __CFRunLoopDoSources0
    42 CoreFoundation                 0x1a7d4cbc8 __CFRunLoopRun
    43 CoreFoundation                 0x1a7d4c360 CFRunLoopRunSpecific
    44 GraphicsServices               0x1bf38a734 GSEventRunModal
    45 UIKitCore                      0x1aa7c7584 -[UIApplication _run]
    46 UIKitCore                      0x1aa7ccdf4 UIApplicationMain
    47 Runner                         0x100e97a70 main + 15 (AppDelegate.swift:15)
    48 libdyld.dylib                  0x1a7a08cf8 start
    
    
    Reviewed by Wian-TMC at 2021-07-01 06:43
  • 7. How can I use plugin inside callback?

    I want to call api on location change. I want to attach JWT_TOKEN which is stored in shared preferences. I am facing.

    E/flutter (10000): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method getAll on channel plugins.flutter.io/shared_preferences)

    Reviewed by vimalmistry at 2020-04-09 18:16
  • 8. fix Exception occurred during the initialization of the flutter

    i have same problem as #237

    iOS devices. background_locator: 1.6.0+1-beta flutter: 2.2.1

    sometimes, app crash when launched.

    2021-06-09 08:19:21.006065+0900 Runner[33423:232150] *** Assertion failure in -[FlutterEngine sendOnChannel:message:binaryReply:], FlutterEngine.mm:799
    2021-06-09 08:19:21.034245+0900 Runner[33423:232150] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Sending a message before the FlutterEngine has been run.'
    *** First throw call stack:
    (
    	0   CoreFoundation                      0x00007fff20420af6 __exceptionPreprocess + 242
    	1   libobjc.A.dylib                     0x00007fff20177e78 objc_exception_throw + 48
    	2   CoreFoundation                      0x00007fff2042091f +[NSException raise:format:] + 0
    	3   Foundation                          0x00007fff2077056a -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
    	4   Flutter                             0x000000010a196246 -[FlutterEngine sendOnChannel:message:binaryReply:] + 544
    	5   background_locator                  0x000000010a0df5dc -[BackgroundLocatorPlugin sendLocationEvent:] + 316
    	6   background_locator                  0x000000010a0df290 -[BackgroundLocatorPlugin prepareLocationMap:] + 128
    	7   background_locator                  0x000000010a0df360 -[BackgroundLocatorPlugin locationManager:didUpdateLocations:] + 160
    	8   CoreLocation                        0x00007fff234082eb CLClientStopVehicleHeadingUpdates + 79384
    	9   CoreLocation                        0x00007fff234074ff CLClientStopVehicleHeadingUpdates + 75820
    	10  CoreLocation                        0x00007fff233ef909 CLClientInvalidate + 1479
    	11  CoreFoundation                      0x00007fff2038f120 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    	12  CoreFoundation                      0x00007fff2038e534 __CFRunLoopDoBlocks + 434
    	13  CoreFoundation                      0x00007fff20388f44 __CFRunLoopRun + 899
    	14  CoreFoundation                      0x00007fff203886d6 CFRunLoopRunSpecific + 567
    	15  GraphicsServices                    0x00007fff2bededb3 GSEventRunModal + 139
    	16  UIKitCore                           0x00007fff24690e0b -[UIApplication _run] + 912
    	17  UIKitCore                           0x00007fff24695cbc UIApplicationMain + 101
    	18  Runner                              0x0000000108be7feb main + 75
    	19  libdyld.dylib                       0x00007fff202593e9 start + 1
    	20  ???                                 0x0000000000000001 0x0 + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Sending a message before the FlutterEngine has been run.'
    terminating with uncaught exception of type NSException
    

    I think it happened because the plugin was calling FlutterMethodChannel during the initialization of the flutter engine.

    FlutterEngine.mm#L798-L799

    so, I changed to ignore that exception.

    Reviewed by gomazaba at 2021-06-09 02:34
  • 9. [Question] Is it possible to access variables in callbacks?

    I have been trying to implement this plugin in my app and so far it's very helpful. But I'm trying to make a geofence solution with it and that's where the problems arise.

    So far it looks like both initCallback and callback can access other static variables. But after background locator is registered it can't read the variable's updated value.

    example:

    static int number = 0
    static string uid
    ...
    static _initCallback(Map<dynamic, dynamic> params) async {
       _uid = params["uid"];
      print(number) //will always print 0
     }
    
    static _callback(LocationDto locationDto) {
      final SendPort sendPort = IsolateNameServer.lookupPortByName(_isolateName);
      sendPort?.send(locationDto);
      print(number); //will also always print 0
    }
    
    BackgroundLocator.registerLocationUpdate(
      _callback,
      initCallback: _initCallback,
      initDataCallback: {"uid": _user.id},
      disposeCallback: _disposeCallback,
      settings: settings.LocationSettings(
          accuracy: settings.LocationAccuracy.HIGH,
          notificationTitle: "Ride Partner",
          notificationMsg: "Running in Background. Searching for orders",
          wakeLockTime: 1,
          autoStop: false,
          distanceFilter: 0.1,
         interval: 5
      ),
    );
    
    number = 1;
    

    Also, like how uid is initiated via initDataCallback, every time I need to register a variable do I need to unregister the service then reregister again or is there a more elegant way of registering a variable?

    Reviewed by DebkanchanSamadder at 2020-07-11 10:04
  • 10. Pluggin still run in background aven if app is closed

    Hello,

    I managed to make the package to work. However, when I close the app on android (not just put in background), the location tracking is still active, draining the battery. How to automatically stop the tracking in this case?

    Reviewed by Sly2024 at 2019-12-24 09:55
  • 11. Firestore stream is not listen with background locator

    Firestore stream has not listened with this plugin.

    Full Code

    import UIKit
    import Flutter
    import GoogleMaps
    import background_locator
    import cloud_firestore
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        let filename = Bundle.main.infoDictionary?["GOOGLE_MAPS_API_KEY"] as! String
        GMSServices.provideAPIKey(filename)
        GeneratedPluginRegistrant.register(with: self)
        BackgroundLocatorPlugin.setPluginRegistrantCallback(registerPlugins)
         registerOtherPlugins()
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    
        func registerOtherPlugins() {
            if !hasPlugin("io.flutter.plugins.firebase.cloudfirestore") {
                FLTFirebaseFirestorePlugin
                    .register(with: registrar(forPlugin: "io.flutter.plugins.firebase.cloudfirestore") as! FlutterPluginRegistrar)
            }
        }
    }
    
    func registerPlugins(registry: FlutterPluginRegistry) -> () {
        if (!registry.hasPlugin("BackgroundLocatorPlugin")) {
            GeneratedPluginRegistrant.register(with: registry)
        }
    }
    
    

    Splash Screen

      @override
      void initState() {
        super.initState();
        _bls.registerPort();
        _bls.initPlatformState().then((value) {});
    

    Home Page

      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
          _bls.startLocationService(); // starting
          locationSubscription = _bls.port.listen(backgroundLocPort); // listen is working
        sixSubscription = _connectivityService.connectionStream.listen(connectionStream); // listen is working
          oneSubscription = db.getUser(driverUid).listen(getUser); //listen not working (any firestore stream not listen)
    
    

    Background Locator Service

    class BackgroundLocationService {
      static const String _isolateName = "LocatorIsolate";
      ReceivePort port = ReceivePort();
    
      Future<void> initPlatformState() async {
        await BackgroundLocator.initialize();
      }
    
      void registerPort() async {
        PermissionStatus permission = await LocationPermissions().requestPermissions(permissionLevel: LocationPermissionLevel.locationAlways);
        if (permission == PermissionStatus.granted) {
          IsolateNameServer.registerPortWithName(port.sendPort, LocationServiceRepository.isolateName);
        } else {
          repeat();
        }
      }
    
      void repeat() {
        registerPort();
      }
    
      static void callback(LocationDto locationDto) async {
        final SendPort send = IsolateNameServer.lookupPortByName(_isolateName);
        send?.send(locationDto);
      }
    
      void startLocationService() {
        Map<String, dynamic> data = {'countInit': 1};
        BackgroundLocator.registerLocationUpdate(LocationCallbackHandler.callback,
            initCallback: LocationCallbackHandler.initCallback,
            initDataCallback: data,
            disposeCallback: LocationCallbackHandler.disposeCallback,
            autoStop: false,
            iosSettings: IOSSettings(accuracy: LocationAccuracy.NAVIGATION, distanceFilter: 0),
            androidSettings: AndroidSettings(
                accuracy: LocationAccuracy.NAVIGATION,
                interval: 1,
                distanceFilter: 0,
                androidNotificationSettings: AndroidNotificationSettings(
                    notificationChannelName: 'Location tracking',
                    notificationTitle: 'OrelGo Driver Location Tracking',
                    notificationMsg: 'Track location in background',
                    notificationBigMsg:
                        'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.',
                    notificationIcon: '',
                    notificationIconColor: Palette.defaultColor,
                    notificationTapCallback: LocationCallbackHandler.notificationCallback)));
      }
    
      void stopLocationService() {
        BackgroundLocator.unRegisterLocationUpdate();
      }
    }
    
    Reviewed by bhanuka96 at 2020-11-27 07:28
  • 12. Execution failed for task ':background_locator:compileDebugKotlin' after Upgrading to Flutter 3.0.0

    Was working fine before. But started facing this issue after upgrading to Flutter 3.0.0.

    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (25, 1): Class 'BackgroundLocatorPlugin' is not abstract and does not implement abstract member public abstract fun onNewIntent(p0: Intent): Boolean defined in io.flutter.plugin.common.PluginRegistry.NewIntentListener
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (215, 43): Type mismatch: inferred type is Map<Any, Any>? but Map<Any, Any> was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (215, 48): Type mismatch: inferred type is Map<Any, Any>? but Map<Any, Any> was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (224, 43): Type mismatch: inferred type is Map<Any, Any>? but Map<Any, Any> was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (224, 48): Type mismatch: inferred type is Map<Any, Any>? but Map<Any, Any> was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (243, 43): Type mismatch: inferred type is Map<Any, Any>? but Map<Any, Any> was expected
    
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (243, 48): Type mismatch: inferred type is Map<Any, Any>? but Map<Any, Any> was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (266, 5): 'onNewIntent' overrides nothing
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/BackgroundLocatorPlugin.kt: (275, 35): Type mismatch: inferred type is BinaryMessenger? but BinaryMessenger was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderExtension.kt: (42, 27): Type mismatch: inferred type is BinaryMessenger? but BinaryMessenger was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/IsolateHolderService.kt: (269, 35): Type mismatch: inferred type is BinaryMessenger? but BinaryMessenger was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/pluggables/DisposePluggable.kt: (17, 51): Type mismatch: inferred type is BinaryMessenger? but BinaryMessenger was expected
    e: /opt/homebrew/Caskroom/flutter/2.2.3/flutter/.pub-cache/hosted/pub.dartlang.org/background_locator-1.6.12/android/src/main/kotlin/rekab/app/background_locator/pluggables/InitPluggable.kt: (22, 55): Type mismatch: inferred type is BinaryMessenger? but BinaryMessenger was expected
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':background_locator:compileDebugKotlin'.
    > A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
       > Compilation error. See log for more details
    
    * Try:
    > Run with --stacktrace option to get the stack trace.
    > Run with --info or --debug option to get more log output.
    > Run with --scan to get full insights.
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 18s
    Exception: Gradle task assembleDebug failed with exit code 1
    Exited
    
    Reviewed by sultan18kh at 2022-05-18 10:05
  • 13. I've been facing issues with the execution of the example provided in this repository.

    I'm trying to track location in the background using flutter and to do so I'm using the background_locator plugin. I've declared a class variable of File type to save the log in the background. The global variable is built at the very beginning of the class.

    Issue: While invoking the callback method, the global variable built is becoming null. So though I could see the location log in my console, I couldn't write it to the file as the object is null.

    Tries:

    1. I've tried with the exact example provided in their documentation.
    2. I've declared it as non static property and tried to access with the class object.
    3. Tried it out declaring it as static property as well.
    4. Tried building file object with the same path every time needed but it is throwing following issue. No implementation found for method getApplicationDocumentsDirectory on channel plugins.flutter.io/path_provider

    Here is my complete source code for reference.

    import 'dart:async';
    import 'dart:ffi';
    import 'dart:io';
    import 'dart:isolate';
    import 'dart:math';
    import 'dart:ui';
    
    import 'package:background_locator/background_locator.dart';
    import 'package:background_locator/location_dto.dart';
    import 'package:background_locator/settings/android_settings.dart';
    import 'package:background_locator/settings/ios_settings.dart';
    import 'package:background_locator/settings/locator_settings.dart';
    import 'package:flutter/material.dart';
    import 'package:location_permissions/location_permissions.dart';
    import 'package:path_provider/path_provider.dart';
    import 'package:permission_handler/permission_handler.dart' as ph;
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      ReceivePort port = ReceivePort();
    
      String logStr = '';
      bool isRunning = false;
      LocationDto? lastLocation;
    
      bool permissionsGranted = false;
    
      static const String isolateName = 'LocatorIsolate';
    
      static int _count = -1;
    
      static File? finalFile;
    
      void requestPermission() async {
        var storageStatus = await ph.Permission.storage.status;
    
        if (!storageStatus.isGranted) {
          await ph.Permission.storage.request();
        }
    
        if (storageStatus.isGranted) {
          permissionsGranted = true;
          setPrerequisites();
        }
    
        setState(() {});
      }
    
      static Future<void> init(Map<dynamic, dynamic> params) async {
        //TODO change logs
        print("***********Init callback handler");
        if (params.containsKey('countInit')) {
          dynamic tmpCount = params['countInit'];
          if (tmpCount is double) {
            _count = tmpCount.toInt();
          } else if (tmpCount is String) {
            _count = int.parse(tmpCount);
          } else if (tmpCount is int) {
            _count = tmpCount;
          } else {
            _count = -2;
          }
        } else {
          _count = 0;
        }
        print("$_count");
        await setLogLabel("start");
        final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
        send?.send(null);
      }
    
      static Future<void> disposeLocationService() async {
        await setLogLabel("end");
        final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
        send?.send(null);
      }
    
      static Future<void> callback(LocationDto locationDto) async {
        await setLogPosition(_count, locationDto);
        final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
        send?.send(locationDto);
        _count++;
      }
    
      static Future<void> setLogLabel(String label) async {
        final date = DateTime.now();
        await _MyAppState().writeToLogFile(
            '------------\n$label: ${formatDateLog(date)}\n------------\n');
      }
    
      static Future<void> setLogPosition(int count, LocationDto data) async {
        final date = DateTime.now();
        await _MyAppState().writeToLogFile(
            '$count : ${formatDateLog(date)} --> ${formatLog(data)} --- isMocked: ${data.isMocked}\n');
      }
    
      static double dp(double val, int places) {
        num mod = pow(10.0, places);
        return ((val * mod).round().toDouble() / mod);
      }
    
      static String formatDateLog(DateTime date) {
        return date.hour.toString() +
            ":" +
            date.minute.toString() +
            ":" +
            date.second.toString();
      }
    
      static String formatLog(LocationDto locationDto) {
        return dp(locationDto.latitude, 4).toString() +
            " " +
            dp(locationDto.longitude, 4).toString();
      }
    
      @override
      void initState() {
        super.initState();
    
        if (permissionsGranted) {
          setPrerequisites();
        } else {
          requestPermission();
        }
      }
    
      void setPrerequisites() async {
        finalFile = await _getTempLogFile();
    
        if (IsolateNameServer.lookupPortByName(isolateName) != null) {
          IsolateNameServer.removePortNameMapping(isolateName);
        }
    
        IsolateNameServer.registerPortWithName(port.sendPort, isolateName);
    
        port.listen(
          (dynamic data) async {
            await updateUI(data);
          },
        );
        initPlatformState();
    
        setState(() {});
      }
    
      Future<void> updateUI(LocationDto data) async {
        final log = await readLogFile();
    
        await _updateNotificationText(data);
    
        setState(() {
          if (data != null) {
            lastLocation = data;
          }
          logStr = log;
        });
      }
    
      Future<void> _updateNotificationText(LocationDto data) async {
        if (data == null) {
          return;
        }
    
        await BackgroundLocator.updateNotificationText(
            title: "new location received",
            msg: "${DateTime.now()}",
            bigMsg: "${data.latitude}, ${data.longitude}");
      }
    
      Future<void> initPlatformState() async {
        print('Initializing...');
        await BackgroundLocator.initialize();
        logStr = await readLogFile();
        print('Initialization done');
        final _isRunning = await BackgroundLocator.isServiceRunning();
        setState(() {
          isRunning = _isRunning;
        });
        print('Running ${isRunning.toString()}');
      }
    
      @override
      Widget build(BuildContext context) {
        final start = SizedBox(
          width: double.maxFinite,
          child: ElevatedButton(
            child: const Text('Start'),
            onPressed: () {
              _onStart();
            },
          ),
        );
        final stop = SizedBox(
          width: double.maxFinite,
          child: ElevatedButton(
            child: Text('Stop'),
            onPressed: () {
              onStop();
            },
          ),
        );
        final clear = SizedBox(
          width: double.maxFinite,
          child: ElevatedButton(
            child: Text('Clear Log'),
            onPressed: () {
              clearLogFile();
              setState(() {
                logStr = '';
              });
            },
          ),
        );
        String msgStatus = "-";
        if (isRunning != null) {
          if (isRunning) {
            msgStatus = 'Is running';
          } else {
            msgStatus = 'Is not running';
          }
        }
        final status = Text("Status: $msgStatus");
    
        final log = Text(
          logStr,
        );
    
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('Flutter background Locator'),
            ),
            body: Container(
              width: double.maxFinite,
              padding: const EdgeInsets.all(22),
              child: SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[start, stop, clear, status, log],
                ),
              ),
            ),
          ),
        );
      }
    
      void onStop() async {
        await BackgroundLocator.unRegisterLocationUpdate();
        final _isRunning = await BackgroundLocator.isServiceRunning();
        setState(() {
          isRunning = _isRunning;
        });
      }
    
      void _onStart() async {
        if (await _checkLocationPermission()) {
          await _startLocator();
          final _isRunning = await BackgroundLocator.isServiceRunning();
    
          setState(() {
            isRunning = _isRunning;
            lastLocation = null;
          });
        } else {
          // show error
        }
      }
    
      static Future<void> initCallback(Map<dynamic, dynamic> params) async {
        await init(params);
      }
    
      static Future<void> disposeCallback() async {
        await disposeLocationService();
      }
    
      Future<void> locationServicecallback(LocationDto locationDto) async {
        await callback(locationDto);
      }
    
      static Future<void> notificationCallback() async {
        print('***notificationCallback');
      }
    
      Future<void> writeToLogFile(String log) async {
        await finalFile!.writeAsString(log, mode: FileMode.append);
      }
    
      Future<String> readLogFile() async {
        return finalFile!.readAsString();
      }
    
      static Future<File?> _getTempLogFile() async {
        File file =
            File('${(await getApplicationDocumentsDirectory()).path}/log.txt');
    
        if (file.existsSync()) {
          return file;
        } else {
          file = await file.create(recursive: true);
        }
        return file;
      }
    
      Future<void> clearLogFile() async {
        await finalFile!.writeAsString('');
      }
    
      Future<bool> _checkLocationPermission() async {
        final access = await LocationPermissions().checkPermissionStatus();
        switch (access) {
          case PermissionStatus.unknown:
          case PermissionStatus.denied:
          case PermissionStatus.restricted:
            final permission = await LocationPermissions().requestPermissions(
              permissionLevel: LocationPermissionLevel.locationAlways,
            );
            if (permission == PermissionStatus.granted) {
              return true;
            } else {
              return false;
            }
          case PermissionStatus.granted:
            return true;
          default:
            return false;
        }
      }
    
      Future<void> _startLocator() async {
        Map<String, dynamic> data = {'countInit': 1};
        return await BackgroundLocator.registerLocationUpdate(
          callback,
          initCallback: initCallback,
          initDataCallback: data,
          disposeCallback: disposeCallback,
          iosSettings: const IOSSettings(
              accuracy: LocationAccuracy.NAVIGATION, distanceFilter: 0),
          autoStop: false,
          androidSettings: const AndroidSettings(
            accuracy: LocationAccuracy.NAVIGATION,
            interval: 5,
            distanceFilter: 0,
            client: LocationClient.google,
            androidNotificationSettings: AndroidNotificationSettings(
              notificationChannelName: 'Location tracking',
              notificationTitle: 'Start Location Tracking',
              notificationMsg: 'Track location in background',
              notificationBigMsg:
                  'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.',
              notificationIconColor: Colors.grey,
              notificationTapCallback: notificationCallback,
            ),
          ),
        );
      }
    }
    

    Any help or working example would be highly helpful, thanks in advance.

    Reviewed by Panda-Srujan at 2022-05-15 12:16
  • 14. Build fails after upgrade to flutter 3.0

    Hello,

    just wanted to let you know that there seems an issue with the latest flutter release 3.0 and this plugin.

    After upgrading my flutter the build of my app using background_locator 1.6.12 gives following errors:

    background_locator\android\src\main\kotlin\rekab\app\background_locator\BackgroundLocatorPlugin.kt: (25, 1): Class 'BackgroundLocatorPlugin' is not abstract and does not implement abstract member public abstract fun onNewIntent(p0: Intent): Boolean defined in io.flutter.plugin.common.PluginRegistry.NewIntentListener
    
    background_locator\android\src\main\kotlin\rekab\app\background_locator\pluggables\InitPluggable.kt: (22, 55): Type mismatch: inferred type is BinaryMessenger? but BinaryMessenger was expected
    

    Best regards Thomas

    Reviewed by stingrayx at 2022-05-12 06:55
  • 15. check all pluggables is initialized

    Maybe fix https://github.com/rekabhq/background_locator/issues/264

    Sometimes it seems that locationUpdated is called before initCallback is called and initCallback is not called. In my environment, with this fix, initCallback is now called.

    Thanks.

    Reviewed by azihsoyn at 2022-05-07 12:29

Related

Lazybit UI I'll keep on updating this section
Lazybit UI  I'll keep on updating this section

Lazybit UI I'll keep on updating this section. Getting Started This project is created Just to design UI in flutter from many sources like dribbble, u

Jun 6, 2020
Background upload plugin for flutter
Background upload plugin for flutter

Flutter Uploader A plugin for creating and managing upload tasks. Supports iOS and Android. This plugin is based on WorkManager in Android and NSURLSe

May 19, 2022
A Flutter plugin which allows you to execute code in the background on Android and iOS.

Flutter Workmanager Flutter WorkManager is a wrapper around Android's WorkManager, iOS' performFetchWithCompletionHandler and iOS BGAppRefreshTask, ef

May 25, 2022
A Flutter project for schedule background task example
A Flutter project for schedule background task example

Flutter Schedule Background Task A Flutter project for schedule background task example. Getting Started This project is an example to create & execut

May 8, 2022
Automatically generate profile picture with random first name and background color. But you can still provide pictures if you have them. As the default color, based on the name of the first letter. :fire: :fire: :fire:
Automatically generate profile picture with random first name and background color. But you can still provide pictures if you have them. As the default color, based on the name of the first letter. :fire: :fire: :fire:

FLUTTER PROFILE PICTURE Automatically generate profile picture with random first name and background color. But you can still provide pictures if you

May 3, 2022
dos downloader app is developed for downloading video. You can download video from YouTube and Facebook. You can also play video on background

dosdownloader Dos downloader app is developed for downloading video. You can download video from YouTube and Facebook. You can also play video on back

Dec 8, 2021
App de teste que executa uma função de fibonacci em background utilizando compute.

app_isolate_compute A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you star

Jan 7, 2022
Aplicativo de teste que roda em background timer atual utilizando Isolate.

# isolate_app A new Flutter project. ## Getting Started This project is a starting point for a Flutter application. A few resources to get you sta

Jan 7, 2022
User onboarding library with smooth animation of objects and background colors
User onboarding library with smooth animation of objects and background colors

SlidingTutorial Cleveroad introduces Sliding Tutorial Library for Flutter Hey guys, hope you haven’t started developing a tutorial for your Flutter ap

Apr 12, 2022
Schedule & run Dart code in the background on both Android & iOS

flt_worker The flt_worker plugin allows you to schedule and execute Dart-written background tasks in a dedicated isolate, by utilizing the WorkManager

Dec 28, 2021
A simple flutter app that fetches weather data from openweathermap.org depending on your location or city you specify.
A simple flutter app that fetches weather data from openweathermap.org depending on your location or city you specify.

Clima ☁ My Goal The objective of this project is to learn about asynchronous programming in Dart. I'll be looking at how to carry out time consuming t

Sep 28, 2021
Apr 7, 2022
Venda is a location-based business platform
Venda is a location-based business platform

Venda (vendaround.com) Venda is a location-based business platform that enables people to discover businesses around them. With Venda, you can sell or

Nov 11, 2021
Note the place to remember it's name and descriptions along with google map location.
Note the place to remember it's name and descriptions along with google map location.

Note the Place Note the place to remember it's name and descriptions along with map location. View in Web Click here for web view Note: for bettter lo

May 5, 2022
A Funtioning basic Clock UI APP with extra functionalities such as displaying thecurrent time location being used and checking time for other timezones simultaneosly.

clock_UI A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if this

Dec 28, 2021
Simple project that consumes the World Time APi and displays the time for the chosen location.
Simple project that consumes the World Time APi and displays the time for the chosen location.

World Time App Simple project that consumes the World Time APi and displays the time for the chosen location. Web Api WorldTime Technologies Flutter A

Jan 20, 2022
App that shows your current location weather and forecast
App that shows your current location weather and forecast

Weather APP Platform: Flutter. A project that shows you the weather and the forecast for the next five days in your current location. Uses openweather

Dec 13, 2021
Declaratively switch child widgets based on the current `Router` location.

Features Declaratively switch child widgets based on the current Router location. class SideBar extends StatelessWidget { Widget build(_){ re

Jan 24, 2022
Jan 20, 2022