├── ios
├── Assets
│ └── .gitkeep
├── Classes
│ ├── pluggables
│ │ ├── InitPluggable.h
│ │ ├── DisposePluggable.h
│ │ ├── Pluggable.h
│ │ ├── DisposePluggable.m
│ │ └── InitPluggable.m
│ ├── BackgroundLocatorPlugin.h
│ ├── Utils
│ │ ├── Util.h
│ │ └── Util.m
│ ├── Preferences
│ │ ├── PreferencesManager.h
│ │ └── PreferencesManager.m
│ ├── Helpers
│ │ ├── MethodCallHelper.h
│ │ └── MethodCallHelper.m
│ ├── Globals.h
│ ├── Globals.m
│ └── BackgroundLocatorPlugin.m
├── background_locator_2.podspec
└── .gitignore
├── res
└── values
│ └── strings_en.arb
├── android
├── settings.gradle
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ └── yukams
│ │ └── app
│ │ └── background_locator_2
│ │ ├── provider
│ │ ├── LocationRequestOptions.kt
│ │ ├── LocationUpdateListener.kt
│ │ ├── LocationClient.kt
│ │ ├── BLLocationProvider.kt
│ │ ├── GoogleLocationProviderClient.kt
│ │ ├── LocationParserUtil.kt
│ │ └── AndroidLocationProviderClient.kt
│ │ ├── pluggables
│ │ ├── Pluggable.kt
│ │ ├── DisposePluggable.kt
│ │ └── InitPluggable.kt
│ │ ├── BootBroadcastReceiver.kt
│ │ ├── IsolateHolderExtension.kt
│ │ ├── Keys.kt
│ │ ├── PreferencesManager.kt
│ │ ├── IsolateHolderService.kt
│ │ └── BackgroundLocatorPlugin.kt
├── .gitignore
├── gradle.properties
├── .settings
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.buildship.core.prefs
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── .project
└── build.gradle
├── demo.gif
├── example
├── ios
│ ├── Runner
│ │ ├── Runner-Bridging-Header.h
│ │ ├── Assets.xcassets
│ │ │ ├── LaunchImage.imageset
│ │ │ │ ├── LaunchImage.png
│ │ │ │ ├── LaunchImage@2x.png
│ │ │ │ ├── LaunchImage@3x.png
│ │ │ │ ├── README.md
│ │ │ │ └── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ ├── Icon-App-20x20@1x.png
│ │ │ │ ├── Icon-App-20x20@2x.png
│ │ │ │ ├── Icon-App-20x20@3x.png
│ │ │ │ ├── Icon-App-29x29@1x.png
│ │ │ │ ├── Icon-App-29x29@2x.png
│ │ │ │ ├── Icon-App-29x29@3x.png
│ │ │ │ ├── Icon-App-40x40@1x.png
│ │ │ │ ├── Icon-App-40x40@2x.png
│ │ │ │ ├── Icon-App-40x40@3x.png
│ │ │ │ ├── Icon-App-60x60@2x.png
│ │ │ │ ├── Icon-App-60x60@3x.png
│ │ │ │ ├── Icon-App-76x76@1x.png
│ │ │ │ ├── Icon-App-76x76@2x.png
│ │ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ │ └── Contents.json
│ │ ├── AppDelegate.swift
│ │ ├── Base.lproj
│ │ │ ├── Main.storyboard
│ │ │ └── LaunchScreen.storyboard
│ │ └── Info.plist
│ ├── Flutter
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── AppFrameworkInfo.plist
│ ├── Runner.xcodeproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── WorkspaceSettings.xcsettings
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── .gitignore
│ └── Podfile
├── android
│ ├── gradle.properties
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_location.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_location.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_location.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_location.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ │ └── ic_location.png
│ │ │ │ │ ├── drawable
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── drawable-v21
│ │ │ │ │ │ └── launch_background.xml
│ │ │ │ │ ├── values
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── values-night
│ │ │ │ │ │ └── styles.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── rekab
│ │ │ │ │ │ └── app
│ │ │ │ │ │ └── background_locator_example
│ │ │ │ │ │ ├── MainActivity.kt
│ │ │ │ │ │ └── Application.kt
│ │ │ │ └── AndroidManifest.xml
│ │ │ ├── debug
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── profile
│ │ │ │ └── AndroidManifest.xml
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── .gitignore
│ ├── build.gradle
│ └── settings.gradle
├── README.md
├── lib
│ ├── file_manager.dart
│ ├── location_callback_handler.dart
│ ├── location_service_repository.dart
│ └── main.dart
├── test
│ └── widget_test.dart
├── .gitignore
├── .metadata
└── pubspec.yaml
├── .metadata
├── test
└── background_locator_test.dart
├── lib
├── auto_stop_handler.dart
├── settings
│ ├── locator_settings.dart
│ ├── ios_settings.dart
│ └── android_settings.dart
├── location_dto.dart
├── callback_dispatcher.dart
├── utils
│ └── settings_util.dart
├── background_locator.dart
└── keys.dart
├── .github
├── workflows
│ ├── build_pr.yml
│ └── build.yml
└── no-response.yml
├── pubspec.yaml
├── LICENSE
├── .gitignore
├── README.md
└── CHANGELOG.md
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/values/strings_en.arb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'background_locator_2'
2 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/demo.gif
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | android.enableR8=true
5 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-hdpi/ic_location.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-mdpi/ic_location.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-xhdpi/ic_location.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-xxhdpi/ic_location.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/android/app/src/main/res/mipmap-xxxhdpi/ic_location.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/android/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=23
3 | org.eclipse.jdt.core.compiler.compliance=23
4 | org.eclipse.jdt.core.compiler.source=23
5 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angebagui/background_locator_fixed/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/LocationRequestOptions.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | class LocationRequestOptions(val interval: Long, val accuracy: Int, val distanceFilter: Float)
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/rekab/app/background_locator_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_example
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity : FlutterActivity()
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
6 |
7 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
6 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/LocationUpdateListener.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | import java.util.HashMap
4 |
5 | interface LocationUpdateListener {
6 | fun onLocationUpdated(location: HashMap?)
7 | }
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/LocationClient.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | enum class LocationClient(val value: Int) {
4 | Google(0), Android(1);
5 |
6 | companion object {
7 | fun fromInt(value: Int) = values().firstOrNull { it.value == value }
8 | }
9 | }
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/BLLocationProvider.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | interface BLLocationProvider {
4 | var listener: LocationUpdateListener?
5 |
6 | fun removeLocationUpdates()
7 |
8 | fun requestLocationUpdates(request: LocationRequestOptions)
9 | }
10 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 2d2a1ffec95cc70a3218872a2cd3f8de4933c42f
8 | channel: stable
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/ios/Classes/pluggables/InitPluggable.h:
--------------------------------------------------------------------------------
1 | //
2 | // InitPluggable.h
3 | // background_locator_2
4 | //
5 | // Created by Mehdok on 6/7/21.
6 | //
7 |
8 | #import
9 | #import "Pluggable.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface InitPluggable : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/ios/Classes/pluggables/DisposePluggable.h:
--------------------------------------------------------------------------------
1 | //
2 | // DisposePluggable.h
3 | // background_locator_2
4 | //
5 | // Created by Mehdok on 6/7/21.
6 | //
7 |
8 | #import
9 | #import "Pluggable.h"
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface DisposePluggable : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/pluggables/Pluggable.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.pluggables
2 |
3 | import android.content.Context
4 |
5 | interface Pluggable {
6 | fun setCallback(context: Context, callbackHandle: Long)
7 | fun onServiceStart(context: Context) { /*optional*/ }
8 | fun onServiceDispose(context: Context) {/*optional*/ }
9 | }
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Classes/pluggables/Pluggable.h:
--------------------------------------------------------------------------------
1 | //
2 | // Pluggable.h
3 | // Pods
4 | //
5 | // Created by Mehdok on 6/6/21.
6 | //
7 |
8 | #ifndef Pluggable_h
9 | #define Pluggable_h
10 |
11 | @protocol Pluggable
12 | - (void) setCallback:(int64_t) callbackHandle;
13 | - (void) onServiceStart: (NSDictionary*)initialDataDictionary;
14 | - (void) onServiceDispose;
15 | @end
16 |
17 | #endif /* Pluggable_h */
18 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Classes/BackgroundLocatorPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "MethodCallHelper.h"
4 |
5 | @interface BackgroundLocatorPlugin : NSObject
6 |
7 | + (BackgroundLocatorPlugin*_Nullable) getInstance;
8 | - (void)invokeMethod:(NSString*_Nonnull)method arguments:(id _Nullable)arguments;
9 |
10 | @end
11 |
--------------------------------------------------------------------------------
/test/background_locator_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 | import 'package:flutter_test/flutter_test.dart';
3 |
4 | void main() {
5 | const MethodChannel channel = MethodChannel('background_locator_2');
6 |
7 | setUp(() {
8 | channel.setMockMethodCallHandler((MethodCall methodCall) async {
9 | return '42';
10 | });
11 | });
12 |
13 | tearDown(() {
14 | channel.setMockMethodCallHandler(null);
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/ios/Classes/Utils/Util.h:
--------------------------------------------------------------------------------
1 | //
2 | // Util.h
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/28/20.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface Util : NSObject
14 |
15 | + (CLLocationAccuracy) getAccuracy:(long)key;
16 | + (NSDictionary*) getLocationMap:(CLLocation *)location;
17 |
18 | @end
19 |
20 | NS_ASSUME_NONNULL_END
21 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/BootBroadcastReceiver.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 |
7 | class BootBroadcastReceiver : BroadcastReceiver() {
8 | override fun onReceive(context: Context, intent: Intent) {
9 | if (intent.action == "android.intent.action.BOOT_COMPLETED") {
10 | BackgroundLocatorPlugin.registerAfterBoot(context)
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # background_locator_example
2 |
3 | Demonstrates how to use the background_locator_2 plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/lib/auto_stop_handler.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'background_locator.dart';
4 |
5 | class AutoStopHandler extends WidgetsBindingObserver {
6 | @override
7 | Future didChangeAppLifecycleState(AppLifecycleState state) async {
8 | switch (state) {
9 | case AppLifecycleState.inactive:
10 | case AppLifecycleState.paused:
11 | case AppLifecycleState.detached:
12 | await BackgroundLocator.unRegisterLocationUpdate();
13 | break;
14 | case AppLifecycleState.resumed:
15 | break;
16 | default:
17 | await BackgroundLocator.unRegisterLocationUpdate();
18 | break;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.github/workflows/build_pr.yml:
--------------------------------------------------------------------------------
1 | name: build_pr
2 |
3 | on:
4 | pull_request:
5 | branches: [ master ]
6 |
7 | jobs:
8 | build:
9 |
10 | runs-on: macos-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-java@v1
15 | with:
16 | java-version: '12.x'
17 | - uses: subosito/flutter-action@v1
18 | with:
19 | channel: 'stable'
20 |
21 | - name: Install dependencies
22 | run: flutter pub get
23 | - name: Build debug akp
24 | run: |
25 | cd example
26 | flutter build apk --debug
27 | - name: Build debug ios app
28 | run: |
29 | cd example
30 | flutter build ios --debug --no-codesign
31 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/android/.settings/org.eclipse.buildship.core.prefs:
--------------------------------------------------------------------------------
1 | arguments=--init-script /var/folders/qz/zhs0y0r13254_d3042b46tn80000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/qz/zhs0y0r13254_d3042b46tn80000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle
2 | auto.sync=false
3 | build.scans.enabled=false
4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
5 | connection.project.dir=
6 | eclipse.preferences.version=1
7 | gradle.user.home=
8 | java.home=/opt/homebrew/Cellar/openjdk/23.0.1/libexec/openjdk.jdk/Contents/Home
9 | jvm.arguments=
10 | offline.mode=false
11 | override.workspace.settings=true
12 | show.console.view=true
13 | show.executions.view=true
14 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | tags:
7 | - '*'
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: macos-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - uses: actions/setup-java@v1
17 | with:
18 | java-version: '12.x'
19 | - uses: subosito/flutter-action@v1
20 | with:
21 | channel: 'stable'
22 |
23 | - name: Install dependencies
24 | run: flutter pub get
25 | - name: Build debug akp
26 | run: |
27 | cd example
28 | flutter build apk --debug
29 | - name: Build debug ios app
30 | run: |
31 | cd example
32 | flutter build ios --debug --no-codesign
33 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.7.20'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:4.1.3'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | tasks.register("clean", Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/.github/no-response.yml:
--------------------------------------------------------------------------------
1 | # Configuration for probot-no-response - https://github.com/probot/no-response
2 |
3 | # Number of days of inactivity before an Issue is closed for lack of response
4 | daysUntilClose: 14
5 | # Label requiring a response
6 | responseRequiredLabel: more-information-needed
7 | # Comment to post when closing an Issue for lack of response. Set to `false` to disable
8 | closeComment: >
9 | This issue has been automatically closed because there has been no response
10 | to our request for more information from the original author. With only the
11 | information that is currently in the issue, we don't have enough information
12 | to take action. Please reach out if you have or find the answers we need so
13 | that we can investigate further.
14 |
--------------------------------------------------------------------------------
/ios/background_locator_2.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
3 | #
4 | Pod::Spec.new do |s|
5 | s.name = 'background_locator_2'
6 | s.version = '0.0.1'
7 | s.summary = 'A Flutter plugin for getting location updates even when the app is killed.'
8 | s.description = <<-DESC
9 | A new Flutter plugin.
10 | DESC
11 | s.homepage = 'https://github.com/rekab-app/background_locator'
12 | s.license = { :file => '../LICENSE' }
13 | s.author = { 'REKAB' => 'mehdok@gmail.com' }
14 | s.source = { :path => '.' }
15 | s.source_files = 'Classes/**/*'
16 | s.public_header_files = 'Classes/**/*.h'
17 | s.dependency 'Flutter'
18 |
19 | s.ios.deployment_target = '8.0'
20 | end
21 |
--------------------------------------------------------------------------------
/lib/settings/locator_settings.dart:
--------------------------------------------------------------------------------
1 | class LocationAccuracy {
2 | const LocationAccuracy._internal(this.value);
3 |
4 | final int value;
5 |
6 | static const POWERSAVE = LocationAccuracy._internal(0);
7 | static const LOW = LocationAccuracy._internal(1);
8 | static const BALANCED = LocationAccuracy._internal(2);
9 | static const HIGH = LocationAccuracy._internal(3);
10 | static const NAVIGATION = LocationAccuracy._internal(4);
11 | }
12 |
13 | class LocatorSettings {
14 | final LocationAccuracy accuracy;
15 | final double distanceFilter;
16 |
17 | /// [accuracy] The accuracy of location, Default is max accuracy NAVIGATION.
18 | ///
19 | /// [distanceFilter] distance in meter to trigger location update, Default is 0 meter.
20 | const LocatorSettings({required this.accuracy, required this.distanceFilter});
21 | }
22 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: background_locator_2
2 | description: A Flutter plugin to request the location even if the app is killed. Sending the location to a dart function in background, also provide a meter filter
3 | version: 2.10.2
4 | homepage: https://github.com/angebagui/background_locator_fixed/
5 | issue_tracker: https://github.com/angebagui/background_locator_fixed/issues
6 | platforms:
7 | android:
8 | ios:
9 |
10 |
11 | environment:
12 | sdk: '>=3.3.3 <4.0.0'
13 | flutter: ">=1.12.0"
14 | dependencies:
15 | flutter:
16 | sdk: flutter
17 |
18 | dev_dependencies:
19 | flutter_test:
20 | sdk: flutter
21 |
22 | flutter:
23 | plugin:
24 | platforms:
25 | android:
26 | package: yukams.app.background_locator_2
27 | pluginClass: BackgroundLocatorPlugin
28 | ios:
29 | pluginClass: BackgroundLocatorPlugin
30 |
--------------------------------------------------------------------------------
/ios/Classes/Preferences/PreferencesManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // PreferencesManager.h
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/28/20.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface PreferencesManager : NSObject
13 |
14 | + (int64_t)getCallbackDispatcherHandle;
15 | + (void)setCallbackDispatcherHandle:(int64_t)handle;
16 | + (int64_t)getCallbackHandle:(NSString *)key;
17 | + (void)setCallbackHandle:(int64_t)handle key:(NSString *)key;
18 | + (void)saveDistanceFilter:(double) distance;
19 | + (double)getDistanceFilter;
20 | + (void)setObservingRegion:(BOOL) observing;
21 | + (BOOL)isObservingRegion;
22 | + (void)setServiceRunning:(BOOL) running;
23 | + (BOOL)isServiceRunning;
24 | + (void)setStopWithTerminate:(BOOL) terminate;
25 | + (BOOL)isStopWithTerminate;
26 |
27 | @end
28 |
29 | NS_ASSUME_NONNULL_END
30 |
--------------------------------------------------------------------------------
/ios/Classes/pluggables/DisposePluggable.m:
--------------------------------------------------------------------------------
1 | //
2 | // DisposePluggable.m
3 | // background_locator_2
4 | //
5 | // Created by Mehdok on 6/7/21.
6 | //
7 |
8 | #import "DisposePluggable.h"
9 | #import "PreferencesManager.h"
10 | #import "Globals.h"
11 | #import "BackgroundLocatorPlugin.h"
12 |
13 | @implementation DisposePluggable
14 |
15 | - (void)onServiceDispose {
16 | NSDictionary *map = @{
17 | kArgDisposeCallback : @([PreferencesManager getCallbackHandle:kDisposeCallbackKey])
18 | };
19 | [[BackgroundLocatorPlugin getInstance] invokeMethod:kBCMDispose arguments:map];
20 | }
21 |
22 | - (void)onServiceStart:(NSDictionary *)initialDataDictionary {
23 | // nop
24 | }
25 |
26 | - (void)setCallback:(int64_t)callbackHandle {
27 | [PreferencesManager setCallbackHandle:callbackHandle key:kDisposeCallbackKey];
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/example/lib/file_manager.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:path_provider/path_provider.dart';
4 |
5 | class FileManager {
6 | static Future writeToLogFile(String log) async {
7 | final file = await _getTempLogFile();
8 | await file.writeAsString(log, mode: FileMode.append);
9 | }
10 |
11 | static Future readLogFile() async {
12 | final file = await _getTempLogFile();
13 | return file.readAsString();
14 | }
15 |
16 | static Future _getTempLogFile() async {
17 | final directory = await getTemporaryDirectory();
18 | final file = File('${directory.path}/log.txt');
19 | if (!await file.exists()) {
20 | await file.writeAsString('');
21 | }
22 | return file;
23 | }
24 |
25 | static Future clearLogFile() async {
26 | final file = await _getTempLogFile();
27 | await file.writeAsString('');
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | plugins {
21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
22 | id "com.android.application" version "8.3.2" apply false
23 | id "org.jetbrains.kotlin.android" version "1.9.23" apply false
24 | }
25 | include ":app"
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/rekab/app/background_locator_example/Application.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_example
2 |
3 | import io.flutter.app.FlutterApplication
4 | import io.flutter.plugin.common.PluginRegistry
5 | import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
6 | import io.flutter.plugins.pathprovider.PathProviderPlugin
7 | import io.flutter.view.FlutterMain
8 | import yukams.app.background_locator_2.IsolateHolderService
9 |
10 | //class Application : FlutterApplication(), PluginRegistrantCallback {
11 | // override fun onCreate() {
12 | // super.onCreate()
13 | // IsolateHolderService.setPluginRegistrant(this)
14 | // FlutterMain.startInitialization(this)
15 | // }
16 | //
17 | // override fun registerWith(registry: PluginRegistry?) {
18 | // if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
19 | // PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider"))
20 | // }
21 | // }
22 | //}
23 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:background_locator_2_example/main.dart';
9 | import 'package:flutter/material.dart';
10 | import 'package:flutter_test/flutter_test.dart';
11 |
12 | void main() {
13 | testWidgets('Verify Platform version', (WidgetTester tester) async {
14 | // Build our app and trigger a frame.
15 | await tester.pumpWidget(MyApp());
16 |
17 | // Verify that platform version is retrieved.
18 | expect(
19 | find.byWidgetPredicate(
20 | (Widget widget) =>
21 | widget is Text && widget.data!.startsWith('Running on:'),
22 | ),
23 | findsOneWidget,
24 | );
25 | });
26 | }
27 |
--------------------------------------------------------------------------------
/ios/Classes/Helpers/MethodCallHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // MethodCallHelper.h
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/28/20.
6 | //
7 |
8 | #import
9 | #import
10 |
11 | @protocol MethodCallHelperDelegate
12 | - (void) startLocatorService:(int64_t) callbackDispatcher;
13 | - (void)registerLocator:(int64_t)callback
14 | initCallback:(int64_t)initCallback
15 | initialDataDictionary:(NSDictionary *_Nullable)initialDataDictionary
16 | disposeCallback:(int64_t)disposeCallback
17 | settings:(NSDictionary *_Nonnull)settings;
18 | - (void) removeLocator;
19 | - (BOOL) isServiceRunning;
20 | - (void) setServiceRunning:(BOOL)value;
21 |
22 | @end
23 |
24 | NS_ASSUME_NONNULL_BEGIN
25 |
26 | @interface MethodCallHelper : NSObject
27 |
28 | - (void)handleMethodCall:(FlutterMethodCall *)call
29 | result:(FlutterResult)result
30 | delegate:(id )delegate;
31 |
32 | @end
33 |
34 | NS_ASSUME_NONNULL_END
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2020 REKAB
2 | Copyright 2022 Yukams
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/android/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | background_locator_2-android
4 | Project android__ created by Buildship.
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.buildship.core.gradleprojectbuilder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.buildship.core.gradleprojectnature
22 |
23 |
24 |
25 | 1735409714122
26 |
27 | 30
28 |
29 | org.eclipse.core.resources.regexFilterMatcher
30 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import background_locator_2
2 | import Flutter
3 | import path_provider_ios
4 | import UIKit
5 |
6 | func registerPlugins(registry: FlutterPluginRegistry) {
7 | GeneratedPluginRegistrant.register(with: registry)
8 | }
9 |
10 | @UIApplicationMain
11 | @objc class AppDelegate: FlutterAppDelegate {
12 | override func application(
13 | _ application: UIApplication,
14 | didFinishLaunchingWithOptions launchOptions: [UIApplication
15 | .LaunchOptionsKey: Any]?
16 | ) -> Bool {
17 | GeneratedPluginRegistrant.register(with: self)
18 | BackgroundLocatorPlugin.setPluginRegistrantCallback(registerPlugins)
19 |
20 | registerOtherPlugins()
21 |
22 | return super
23 | .application(application,
24 | didFinishLaunchingWithOptions: launchOptions)
25 | }
26 |
27 | func registerOtherPlugins() {
28 | if !hasPlugin("io.flutter.plugins.pathprovider") {
29 | FLTPathProviderPlugin
30 | .register(with: registrar(forPlugin: "io.flutter.plugins.pathprovider")!)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/example/lib/location_callback_handler.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:background_locator_2/location_dto.dart';
4 |
5 | import 'location_service_repository.dart';
6 |
7 | @pragma('vm:entry-point')
8 | class LocationCallbackHandler {
9 | @pragma('vm:entry-point')
10 | static Future initCallback(Map params) async {
11 | LocationServiceRepository myLocationCallbackRepository =
12 | LocationServiceRepository();
13 | await myLocationCallbackRepository.init(params);
14 | }
15 |
16 | @pragma('vm:entry-point')
17 | static Future disposeCallback() async {
18 | LocationServiceRepository myLocationCallbackRepository =
19 | LocationServiceRepository();
20 | await myLocationCallbackRepository.dispose();
21 | }
22 |
23 | @pragma('vm:entry-point')
24 | static Future callback(LocationDto locationDto) async {
25 | LocationServiceRepository myLocationCallbackRepository =
26 | LocationServiceRepository();
27 | await myLocationCallbackRepository.callback(locationDto);
28 | }
29 |
30 | @pragma('vm:entry-point')
31 | static Future notificationCallback() async {
32 | print('***notificationCallback');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ios/Classes/pluggables/InitPluggable.m:
--------------------------------------------------------------------------------
1 | //
2 | // InitPluggable.m
3 | // background_locator_2
4 | //
5 | // Created by Mehdok on 6/7/21.
6 | //
7 |
8 | #import "InitPluggable.h"
9 | #import "PreferencesManager.h"
10 | #import "Globals.h"
11 | #import "BackgroundLocatorPlugin.h"
12 |
13 | @implementation InitPluggable {
14 | BOOL isInitCallbackCalled;
15 | }
16 |
17 | - (instancetype)init {
18 | self = [super init];
19 | if (self) {
20 | isInitCallbackCalled = NO;
21 | }
22 | return self;
23 | }
24 |
25 | - (void)onServiceDispose {
26 | isInitCallbackCalled = NO;
27 | }
28 |
29 | - (void)onServiceStart:(NSDictionary*) initialDataDictionary {
30 | if (!isInitCallbackCalled) {
31 | NSDictionary *map = @{
32 | kArgInitCallback : @([PreferencesManager getCallbackHandle:kInitCallbackKey]),
33 | kArgInitDataCallback: initialDataDictionary
34 | };
35 | [[BackgroundLocatorPlugin getInstance] invokeMethod:kBCMInit arguments:map];
36 | }
37 | isInitCallbackCalled = YES;
38 | }
39 |
40 | - (void)setCallback:(int64_t)callbackHandle {
41 | [PreferencesManager setCallbackHandle:callbackHandle key:kInitCallbackKey];
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/lib/settings/ios_settings.dart:
--------------------------------------------------------------------------------
1 | import 'package:background_locator_2/keys.dart';
2 |
3 | import 'locator_settings.dart';
4 |
5 | class IOSSettings extends LocatorSettings {
6 | /// [accuracy] The accuracy of location, Default is max accuracy NAVIGATION.
7 | ///
8 | /// [distanceFilter] distance in meter to trigger location update, Default is 0 meter.
9 | ///
10 | /// [showsBackgroundLocationIndicator] The background location usage indicator is a blue bar or a blue pill in the status bar on iOS. Default is false.
11 | ///
12 | /// [stopWithTerminate] stops the location usage when the app is on background
13 |
14 | final bool showsBackgroundLocationIndicator;
15 | final bool stopWithTerminate;
16 |
17 | const IOSSettings({
18 | LocationAccuracy accuracy = LocationAccuracy.NAVIGATION,
19 | double distanceFilter = 0,
20 | this.showsBackgroundLocationIndicator = false,
21 | this.stopWithTerminate = false,
22 | }) : super(accuracy: accuracy, distanceFilter: distanceFilter); //minutes
23 |
24 | Map toMap() {
25 | return {
26 | Keys.SETTINGS_ACCURACY: accuracy.value,
27 | Keys.SETTINGS_DISTANCE_FILTER: distanceFilter,
28 | Keys.SETTINGS_IOS_SHOWS_BACKGROUND_LOCATION_INDICATOR:
29 | showsBackgroundLocationIndicator,
30 | Keys.SETTINGS_IOS_STOP_WITH_TERMINATE: stopWithTerminate,
31 | };
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/pluggables/DisposePluggable.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.pluggables
2 |
3 | import android.content.Context
4 | import android.os.Handler
5 | import io.flutter.plugin.common.MethodChannel
6 | import yukams.app.background_locator_2.IsolateHolderService
7 | import yukams.app.background_locator_2.Keys
8 | import yukams.app.background_locator_2.PreferencesManager
9 |
10 | class DisposePluggable : Pluggable {
11 | override fun setCallback(context: Context, callbackHandle: Long) {
12 | PreferencesManager.setCallbackHandle(context, Keys.DISPOSE_CALLBACK_HANDLE_KEY, callbackHandle)
13 | }
14 |
15 | override fun onServiceDispose(context: Context) {
16 | (PreferencesManager.getCallbackHandle(context, Keys.DISPOSE_CALLBACK_HANDLE_KEY))?.let { disposeCallback ->
17 | IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger ->
18 | val backgroundChannel = MethodChannel(binaryMessenger, Keys.BACKGROUND_CHANNEL_ID)
19 | Handler(context.mainLooper)
20 | .post {
21 | backgroundChannel.invokeMethod(
22 | Keys.BCM_DISPOSE,
23 | hashMapOf(Keys.ARG_DISPOSE_CALLBACK to disposeCallback)
24 | )
25 | }
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/ios/Classes/Utils/Util.m:
--------------------------------------------------------------------------------
1 | //
2 | // Util.m
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/28/20.
6 | //
7 |
8 | #import "Util.h"
9 | #import "GLobals.h"
10 |
11 | @implementation Util
12 |
13 | + (CLLocationAccuracy) getAccuracy:(long)key {
14 | switch (key) {
15 | case 0:
16 | return kCLLocationAccuracyKilometer;
17 | case 1:
18 | return kCLLocationAccuracyHundredMeters;
19 | case 2:
20 | return kCLLocationAccuracyNearestTenMeters;
21 | case 3:
22 | return kCLLocationAccuracyBest;
23 | case 4:
24 | return kCLLocationAccuracyBestForNavigation;
25 | default:
26 | return kCLLocationAccuracyBestForNavigation;
27 | }
28 | }
29 |
30 | + (NSDictionary *)getLocationMap:(CLLocation *)location {
31 | NSTimeInterval timeInSeconds = [location.timestamp timeIntervalSince1970];
32 | return @{
33 | kArgLatitude: @(location.coordinate.latitude),
34 | kArgLongitude: @(location.coordinate.longitude),
35 | kArgAccuracy: @(location.horizontalAccuracy),
36 | kArgAltitude: @(location.altitude),
37 | kArgSpeed: @(location.speed),
38 | kArgSpeedAccuracy: @(0.0),
39 | kArgHeading: @(location.course),
40 | kArgTime: @(((double) timeInSeconds) * 1000.0) // in milliseconds since the epoch
41 | };
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '11.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group = 'yukams.app.background_locator_2'
2 | version = '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | ext.kotlin_version = '1.8.22'
6 | repositories {
7 | google()
8 | mavenCentral()
9 | }
10 |
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:8.1.2'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | }
15 | }
16 |
17 | rootProject.allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | }
22 | }
23 |
24 | apply plugin: 'com.android.library'
25 | apply plugin: 'kotlin-android'
26 |
27 | android {
28 | namespace = "yukams.app.background_locator_2"
29 | compileSdk = 35
30 |
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_11
33 | targetCompatibility JavaVersion.VERSION_11
34 | }
35 |
36 | kotlinOptions {
37 | jvmTarget = JavaVersion.VERSION_11
38 | }
39 |
40 | sourceSets {
41 | main.java.srcDirs += 'src/main/kotlin'
42 | }
43 | defaultConfig {
44 | minSdk = 23
45 | targetSdkVersion = 35
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | }
48 | lintOptions {
49 | disable 'InvalidPackage'
50 | }
51 | }
52 |
53 | dependencies {
54 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
55 | implementation "com.google.android.gms:play-services-location:21.0.1"
56 | implementation 'com.google.code.gson:gson:2.8.6'
57 | implementation 'com.google.android.material:material:1.0.0'
58 | }
59 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/GoogleLocationProviderClient.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import com.google.android.gms.location.*
6 |
7 | class GoogleLocationProviderClient(context: Context, override var listener: LocationUpdateListener?) : BLLocationProvider {
8 | private val client: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
9 | private val locationCallback = LocationListener(listener)
10 |
11 | override fun removeLocationUpdates() {
12 | client.removeLocationUpdates(locationCallback)
13 | }
14 |
15 | @SuppressLint("MissingPermission")
16 | override fun requestLocationUpdates(request: LocationRequestOptions) {
17 | client.requestLocationUpdates(getLocationRequest(request), locationCallback, null)
18 | }
19 |
20 | private fun getLocationRequest(request: LocationRequestOptions): LocationRequest {
21 | val locationRequest = LocationRequest.create()
22 |
23 | locationRequest.interval = request.interval
24 | locationRequest.fastestInterval = request.interval
25 | locationRequest.maxWaitTime = request.interval
26 | locationRequest.priority = request.accuracy
27 | locationRequest.smallestDisplacement = request.distanceFilter
28 |
29 | return locationRequest
30 | }
31 | }
32 |
33 | private class LocationListener(val listener: LocationUpdateListener?) : LocationCallback() {
34 | override fun onLocationResult(location: LocationResult) {
35 | listener?.onLocationUpdated(LocationParserUtil.getLocationMapFromLocation(location))
36 | }
37 | }
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 | lib/main_widget_test.dart
31 | coverage
32 | # Android related
33 | **/android/**/gradle-wrapper.jar
34 | **/android/.gradle
35 | **/android/captures/
36 | **/android/gradlew
37 | **/android/gradlew.bat
38 | **/android/local.properties
39 | **/android/**/GeneratedPluginRegistrant.java
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/ServiceDefinitions.json
65 | **/ios/Runner/GeneratedPluginRegistrant.*
66 | **/ios/.symlinks
67 |
68 | # Exceptions to above rules.
69 | !**/ios/**/default.mode1v3
70 | !**/ios/**/default.mode2v3
71 | !**/ios/**/default.pbxuser
72 | !**/ios/**/default.perspectivev3
73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
74 | ios/Frameworks/
75 | .flutter-plugins-dependencies
76 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # The .vscode folder contains launch configuration and tasks you configure in
20 | # VS Code which you may wish to be included in version control, so this line
21 | # is commented out by default.
22 | .vscode/
23 |
24 | # Flutter/Dart/Pub related
25 | **/doc/api/
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | build/
33 |
34 | # Android related
35 | **/android/**/gradle-wrapper.jar
36 | **/android/.gradle
37 | **/android/captures/
38 | **/android/gradlew
39 | **/android/gradlew.bat
40 | **/android/local.properties
41 | **/android/**/GeneratedPluginRegistrant.java
42 |
43 | # iOS/XCode related
44 | **/ios/**/*.mode1v3
45 | **/ios/**/*.mode2v3
46 | **/ios/**/*.moved-aside
47 | **/ios/**/*.pbxuser
48 | **/ios/**/*.perspectivev3
49 | **/ios/**/*sync/
50 | **/ios/**/.sconsign.dblite
51 | **/ios/**/.tags*
52 | **/ios/**/.vagrant/
53 | **/ios/**/DerivedData/
54 | **/ios/**/Icon?
55 | **/ios/**/Pods/
56 | **/ios/**/.symlinks/
57 | **/ios/**/profile
58 | **/ios/**/xcuserdata
59 | **/ios/.generated/
60 | **/ios/Flutter/App.framework
61 | **/ios/Flutter/Flutter.framework
62 | **/ios/Flutter/Flutter.podspec
63 | **/ios/Flutter/Generated.xcconfig
64 | **/ios/Flutter/ephemeral
65 | **/ios/Flutter/app.flx
66 | **/ios/Flutter/app.zip
67 | **/ios/Flutter/flutter_assets/
68 | **/ios/Flutter/flutter_export_environment.sh
69 | **/ios/ServiceDefinitions.json
70 | **/ios/Runner/GeneratedPluginRegistrant.*
71 |
72 | # Exceptions to above rules.
73 | !**/ios/**/default.mode1v3
74 | !**/ios/**/default.mode2v3
75 | !**/ios/**/default.pbxuser
76 | !**/ios/**/default.perspectivev3
--------------------------------------------------------------------------------
/example/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled.
5 |
6 | version:
7 | revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
8 | channel: master
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
17 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
18 | - platform: android
19 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
20 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
21 | - platform: ios
22 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
23 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
24 | - platform: linux
25 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
26 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
27 | - platform: macos
28 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
29 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
30 | - platform: web
31 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
32 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
33 | - platform: windows
34 | create_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
35 | base_revision: 6c3a0e4d21da2478a58d8b00fbabfa29ef0df045
36 |
37 | # User provided section
38 |
39 | # List of Local paths (relative to this file) that should be
40 | # ignored by the migrate tool.
41 | #
42 | # Files that are not part of the templates will be ignored by default.
43 | unmanaged_files:
44 | - 'lib/main.dart'
45 | - 'ios/Runner.xcodeproj/project.pbxproj'
46 |
--------------------------------------------------------------------------------
/lib/location_dto.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io' show Platform;
2 |
3 | import 'keys.dart';
4 |
5 | class LocationDto {
6 | final double latitude;
7 | final double longitude;
8 | final double accuracy;
9 | final double altitude;
10 | final double speed;
11 | final double speedAccuracy;
12 | final double heading;
13 | final double time;
14 | final bool isMocked;
15 | final String provider;
16 |
17 | LocationDto._(
18 | this.latitude,
19 | this.longitude,
20 | this.accuracy,
21 | this.altitude,
22 | this.speed,
23 | this.speedAccuracy,
24 | this.heading,
25 | this.time,
26 | this.isMocked,
27 | this.provider,
28 | );
29 |
30 | factory LocationDto.fromJson(Map json) {
31 | bool isLocationMocked =
32 | Platform.isAndroid ? json[Keys.ARG_IS_MOCKED] : false;
33 | return LocationDto._(
34 | json[Keys.ARG_LATITUDE],
35 | json[Keys.ARG_LONGITUDE],
36 | json[Keys.ARG_ACCURACY],
37 | json[Keys.ARG_ALTITUDE],
38 | json[Keys.ARG_SPEED],
39 | json[Keys.ARG_SPEED_ACCURACY],
40 | json[Keys.ARG_HEADING],
41 | json[Keys.ARG_TIME],
42 | isLocationMocked,
43 | json[Keys.ARG_PROVIDER] ?? '',
44 | );
45 | }
46 |
47 | Map toJson() {
48 | return {
49 | Keys.ARG_LATITUDE: this.latitude,
50 | Keys.ARG_LONGITUDE: this.longitude,
51 | Keys.ARG_ACCURACY: this.accuracy,
52 | Keys.ARG_ALTITUDE: this.altitude,
53 | Keys.ARG_SPEED: this.speed,
54 | Keys.ARG_SPEED_ACCURACY: this.speedAccuracy,
55 | Keys.ARG_HEADING: this.heading,
56 | Keys.ARG_TIME: this.time,
57 | Keys.ARG_IS_MOCKED: this.isMocked,
58 | Keys.ARG_PROVIDER: this.provider,
59 | };
60 | }
61 |
62 | @override
63 | String toString() {
64 | return 'LocationDto{latitude: $latitude, longitude: $longitude, accuracy: $accuracy, altitude: $altitude, speed: $speed, speedAccuracy: $speedAccuracy, heading: $heading, time: $time, isMocked: $isMocked, provider: $provider}';
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This package is a V2 of the background_locator package, fixing it and making it work for the newest versions of Flutter. Please read the wiki in order to make this plugin work with flutter 3.x.
2 |
3 | # background_locator_2 ! [](https://pub.dartlang.org/packages/background_locator_2)  
4 |
5 | A Flutter plugin for getting location updates even when the app is killed.
6 |
7 | 
8 |
9 | Refer to [wiki](https://github.com/Yukams/background_locator_fixed/wiki) page for install and setup instruction or jump to specific subject with below links:
10 |
11 | * [Installation](https://github.com/Yukams/background_locator_fixed/wiki/Installation)
12 | * [Setup](https://github.com/Yukams/background_locator_fixed/wiki/Setup)
13 | * [How to use](https://github.com/Yukams/background_locator_fixed/wiki/How-to-use)
14 | * [Use other plugins in callback](https://github.com/Yukams/background_locator_fixed/wiki/Use-other-plugins-in-callback)
15 | * [Stop on app terminate](https://github.com/Yukams/background_locator_fixed/wiki/Stop-on-app-terminate)
16 | * [LocationSettings options](https://github.com/Yukams/background_locator_fixed/wiki/LocationSettings-options)
17 | * [Restart service on device reboot (Android only)](https://github.com/Yukams/background_locator_fixed/wiki/Restart-service-on-device-reboot)
18 |
19 | ## License
20 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
21 |
22 | ## Contributor
23 | Thanks to all who contributed on this plugin to fix bugs and adding new feature, including:
24 | * [Rekab](https://github.com/rekabhq) (creator of V1)
25 | * [Gerardo Ibarra](https://github.com/gpibarra)
26 | * [RomanJos](https://github.com/RomanJos)
27 | * [Marcelo Henrique Neppel](https://github.com/marceloneppel)
28 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/pluggables/InitPluggable.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.pluggables
2 |
3 | import android.content.Context
4 | import android.os.Handler
5 | import io.flutter.plugin.common.MethodChannel
6 | import yukams.app.background_locator_2.IsolateHolderService
7 | import yukams.app.background_locator_2.Keys
8 | import yukams.app.background_locator_2.PreferencesManager
9 |
10 | class InitPluggable : Pluggable {
11 | private var isInitCallbackCalled = false
12 |
13 | override fun setCallback(context: Context, callbackHandle: Long) {
14 | PreferencesManager.setCallbackHandle(context, Keys.INIT_CALLBACK_HANDLE_KEY, callbackHandle)
15 |
16 | }
17 |
18 | override fun onServiceStart(context: Context) {
19 | if (!isInitCallbackCalled) {
20 | (PreferencesManager.getCallbackHandle(context, Keys.INIT_CALLBACK_HANDLE_KEY))?.let { initCallback ->
21 | IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger ->
22 | val initialDataMap = PreferencesManager.getDataCallback(context, Keys.INIT_DATA_CALLBACK_KEY)
23 | val backgroundChannel = MethodChannel(binaryMessenger, Keys.BACKGROUND_CHANNEL_ID)
24 | Handler(context.mainLooper)
25 | .post {
26 | backgroundChannel.invokeMethod(
27 | Keys.BCM_INIT,
28 | hashMapOf(
29 | Keys.ARG_INIT_CALLBACK to initCallback,
30 | Keys.ARG_INIT_DATA_CALLBACK to initialDataMap
31 | )
32 | )
33 | }
34 | }
35 | }
36 | isInitCallbackCalled = true
37 | }
38 | }
39 |
40 | override fun onServiceDispose(context: Context) {
41 | isInitCallbackCalled = false
42 | }
43 |
44 | fun setInitData(context: Context, data: Map<*, *>) {
45 | PreferencesManager.setDataCallback(context, Keys.INIT_DATA_CALLBACK_KEY, data)
46 | }
47 | }
--------------------------------------------------------------------------------
/lib/callback_dispatcher.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui';
2 |
3 | import 'package:flutter/services.dart';
4 | import 'package:flutter/widgets.dart';
5 |
6 | import 'keys.dart';
7 | import 'location_dto.dart';
8 |
9 | @pragma('vm:entry-point')
10 | void callbackDispatcher() {
11 | const MethodChannel _backgroundChannel =
12 | MethodChannel(Keys.BACKGROUND_CHANNEL_ID);
13 | WidgetsFlutterBinding.ensureInitialized();
14 |
15 | _backgroundChannel.setMethodCallHandler((MethodCall call) async {
16 | if (Keys.BCM_SEND_LOCATION == call.method) {
17 | final Map args = call.arguments;
18 | final Function? callback = PluginUtilities.getCallbackFromHandle(
19 | CallbackHandle.fromRawHandle(args[Keys.ARG_CALLBACK]))!;
20 | final LocationDto location =
21 | LocationDto.fromJson(args[Keys.ARG_LOCATION]);
22 | if (callback != null) {
23 | callback(location);
24 | }
25 | } else if (Keys.BCM_NOTIFICATION_CLICK == call.method) {
26 | final Map args = call.arguments;
27 | final Function? notificationCallback =
28 | PluginUtilities.getCallbackFromHandle(CallbackHandle.fromRawHandle(
29 | args[Keys.ARG_NOTIFICATION_CALLBACK]));
30 | if (notificationCallback != null) {
31 | notificationCallback();
32 | }
33 | } else if (Keys.BCM_INIT == call.method) {
34 | final Map args = call.arguments;
35 | final Function? initCallback = PluginUtilities.getCallbackFromHandle(
36 | CallbackHandle.fromRawHandle(args[Keys.ARG_INIT_CALLBACK]));
37 | Map? data = args[Keys.ARG_INIT_DATA_CALLBACK];
38 | if (initCallback != null) {
39 | initCallback(data);
40 | }
41 | } else if (Keys.BCM_DISPOSE == call.method) {
42 | final Map args = call.arguments;
43 | final Function? disposeCallback = PluginUtilities.getCallbackFromHandle(
44 | CallbackHandle.fromRawHandle(args[Keys.ARG_DISPOSE_CALLBACK]));
45 | if (disposeCallback != null) {
46 | disposeCallback();
47 | }
48 | }
49 | });
50 | _backgroundChannel.invokeMethod(Keys.METHOD_SERVICE_INITIALIZED);
51 | }
52 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | example
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | NSLocationAlwaysAndWhenInUseUsageDescription
28 | Location service needed.
29 | NSLocationAlwaysUsageDescription
30 | Location service needed.
31 | NSLocationWhenInUseUsageDescription
32 | Location service needed.
33 | UIBackgroundModes
34 |
35 | location
36 |
37 | UILaunchStoryboardName
38 | LaunchScreen
39 | UIMainStoryboardFile
40 | Main
41 | UISupportedInterfaceOrientations
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationLandscapeLeft
45 | UIInterfaceOrientationLandscapeRight
46 |
47 | UISupportedInterfaceOrientations~ipad
48 |
49 | UIInterfaceOrientationPortrait
50 | UIInterfaceOrientationPortraitUpsideDown
51 | UIInterfaceOrientationLandscapeLeft
52 | UIInterfaceOrientationLandscapeRight
53 |
54 | UIViewControllerBasedStatusBarAppearance
55 |
56 | CADisableMinimumFrameDurationOnPhone
57 |
58 | UIApplicationSupportsIndirectInputEvents
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: background_locator_2_example
2 | description: Demonstrates how to use the background_locator_2 plugin.
3 | publish_to: 'none'
4 |
5 | environment:
6 | sdk: '>=3.3.3 <4.0.0'
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 |
12 | # The following adds the Cupertino Icons font to your application.
13 | # Use with the CupertinoIcons class for iOS style icons.
14 | cupertino_icons: ^1.0.2
15 |
16 | dev_dependencies:
17 | flutter_test:
18 | sdk: flutter
19 |
20 | background_locator_2:
21 | path: ../
22 | path_provider: ^2.0.8
23 | permission_handler: ^11.3.1
24 | win32: 5.9.0
25 | #location_permissions: ^4.0.1
26 |
27 | # For information on the generic Dart part of this file, see the
28 | # following page: https://dart.dev/tools/pub/pubspec
29 |
30 | # The following section is specific to Flutter.
31 | flutter:
32 |
33 | # The following line ensures that the Material Icons font is
34 | # included with your application, so that you can use the icons in
35 | # the material Icons class.
36 | uses-material-design: true
37 |
38 | # To add assets to your application, add an assets section, like this:
39 | # assets:
40 | # - images/a_dot_burr.jpeg
41 | # - images/a_dot_ham.jpeg
42 |
43 | # An image asset can refer to one or more resolution-specific "variants", see
44 | # https://flutter.dev/assets-and-images/#resolution-aware.
45 |
46 | # For details regarding adding assets from package dependencies, see
47 | # https://flutter.dev/assets-and-images/#from-packages
48 |
49 | # To add custom fonts to your application, add a fonts section here,
50 | # in this "flutter" section. Each entry in this list should have a
51 | # "family" key with the font family name, and a "fonts" key with a
52 | # list giving the asset and other descriptors for the font. For
53 | # example:
54 | # fonts:
55 | # - family: Schyler
56 | # fonts:
57 | # - asset: fonts/Schyler-Regular.ttf
58 | # - asset: fonts/Schyler-Italic.ttf
59 | # style: italic
60 | # - family: Trajan Pro
61 | # fonts:
62 | # - asset: fonts/TrajanPro.ttf
63 | # - asset: fonts/TrajanPro_Bold.ttf
64 | # weight: 700
65 | #
66 | # For details regarding fonts from package dependencies,
67 | # see https://flutter.dev/custom-fonts/#from-packages
68 |
--------------------------------------------------------------------------------
/ios/Classes/Preferences/PreferencesManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // PreferencesManager.m
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/28/20.
6 | //
7 |
8 | #import "PreferencesManager.h"
9 | #import "Globals.h"
10 |
11 | @implementation PreferencesManager
12 |
13 | + (int64_t)getCallbackDispatcherHandle {
14 | id handle = [[NSUserDefaults standardUserDefaults]
15 | objectForKey: kCallbackDispatcherKey];
16 | if (handle == nil) {
17 | return 0;
18 | }
19 | return [handle longLongValue];
20 | }
21 |
22 | + (void)setCallbackDispatcherHandle:(int64_t)handle {
23 | [[NSUserDefaults standardUserDefaults]
24 | setObject:[NSNumber numberWithLongLong:handle]
25 | forKey:kCallbackDispatcherKey];
26 | }
27 |
28 | + (int64_t)getCallbackHandle:(NSString *)key {
29 | id handle = [[NSUserDefaults standardUserDefaults]
30 | objectForKey: key];
31 | if (handle == nil) {
32 | return 0;
33 | }
34 | return [handle longLongValue];
35 | }
36 |
37 | + (void)setCallbackHandle:(int64_t)handle key:(NSString *)key {
38 | [[NSUserDefaults standardUserDefaults]
39 | setObject:[NSNumber numberWithLongLong:handle]
40 | forKey: key];
41 | }
42 |
43 | + (void)saveDistanceFilter:(double)distance {
44 | [[NSUserDefaults standardUserDefaults] setDouble:distance forKey:kDistanceFilterKey];
45 | }
46 |
47 | + (double)getDistanceFilter {
48 | return [[NSUserDefaults standardUserDefaults] doubleForKey:kDistanceFilterKey];
49 | }
50 |
51 | + (void)setObservingRegion:(BOOL)observing {
52 | [[NSUserDefaults standardUserDefaults] setBool:observing forKey:kPrefObservingRegion];
53 | }
54 |
55 | + (BOOL)isObservingRegion {
56 | return [[NSUserDefaults standardUserDefaults] boolForKey:kPrefObservingRegion];
57 | }
58 |
59 | + (void)setServiceRunning:(BOOL)running {
60 | [[NSUserDefaults standardUserDefaults] setBool:running forKey:kPrefServiceRunning];
61 | }
62 |
63 | + (BOOL)isServiceRunning {
64 | return [[NSUserDefaults standardUserDefaults] boolForKey:kPrefServiceRunning];
65 | }
66 |
67 | + (void)setStopWithTerminate:(BOOL)terminate {
68 | [[NSUserDefaults standardUserDefaults] setBool:terminate forKey:kPrefStopWithTerminate];
69 | }
70 |
71 | + (BOOL)isStopWithTerminate {
72 | return [[NSUserDefaults standardUserDefaults] boolForKey:kPrefStopWithTerminate];
73 | }
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/ios/Classes/Helpers/MethodCallHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // MethodCallHelper.m
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/28/20.
6 | //
7 |
8 | #import "MethodCallHelper.h"
9 | #import "Globals.h"
10 |
11 | @implementation MethodCallHelper
12 |
13 | - (void)handleMethodCall:(FlutterMethodCall *)call
14 | result:(FlutterResult)result
15 | delegate:(id )delegate {
16 | NSDictionary *arguments = call.arguments;
17 | if ([kMethodPluginInitializeService isEqualToString:call.method]) {
18 | int64_t callbackDispatcher = [[arguments objectForKey:kArgCallbackDispatcher] longLongValue];
19 | [delegate startLocatorService:callbackDispatcher];
20 | result(@(YES));
21 | } else if ([kMethodServiceInitialized isEqualToString:call.method]) {
22 | result(nil);
23 | } else if ([kMethodPluginRegisterLocationUpdate isEqualToString:call.method]) {
24 | int64_t callbackHandle = [[arguments objectForKey:kArgCallback] longLongValue];
25 | int64_t initCallbackHandle = [[arguments objectForKey:kArgInitCallback] longLongValue];
26 | NSDictionary *initialDataDictionary = [arguments objectForKey:kArgInitDataCallback];
27 | int64_t disposeCallbackHandle = [[arguments objectForKey:kArgDisposeCallback] longLongValue];
28 | [delegate setServiceRunning:true];
29 | [delegate registerLocator:callbackHandle initCallback:initCallbackHandle initialDataDictionary:initialDataDictionary disposeCallback:disposeCallbackHandle settings:arguments];
30 | result(@(YES));
31 | } else if ([kMethodPluginUnRegisterLocationUpdate isEqualToString:call.method]) {
32 | [delegate removeLocator];
33 | [delegate setServiceRunning:false];
34 | result(@(YES));
35 | } else if ([kMethodPluginIsRegisteredLocationUpdate isEqualToString:call.method]) {
36 | BOOL val = [delegate isServiceRunning];
37 | result(@(val));
38 | }else if ([kMethodPluginIsServiceRunning isEqualToString:call.method]) {
39 | BOOL val = [delegate isServiceRunning];
40 | result(@(val));
41 | } else if([kMethodPluginUpdateNotification isEqualToString:call.method]) {
42 | // updating notification's text is just for android
43 | result(nil);
44 | } else {
45 | result(FlutterMethodNotImplemented);
46 | }
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/example/ios/Runner/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.android.application"
3 | // END: FlutterFire Configuration
4 | id "kotlin-android"
5 | id "dev.flutter.flutter-gradle-plugin"
6 | }
7 |
8 | def localProperties = new Properties()
9 | def localPropertiesFile = rootProject.file('local.properties')
10 | if (localPropertiesFile.exists()) {
11 | localPropertiesFile.withReader('UTF-8') { reader ->
12 | localProperties.load(reader)
13 | }
14 | }
15 |
16 | def flutterRoot = localProperties.getProperty('flutter.sdk')
17 | if (flutterRoot == null) {
18 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
19 | }
20 |
21 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
22 | if (flutterVersionCode == null) {
23 | flutterVersionCode = '1'
24 | }
25 |
26 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
27 | if (flutterVersionName == null) {
28 | flutterVersionName = '1.0'
29 | }
30 |
31 | android {
32 | namespace = "yukams.app.background_locator_example"
33 | compileSdk = flutter.compileSdkVersion
34 | ndkVersion = flutter.ndkVersion
35 |
36 | sourceSets {
37 | main.java.srcDirs += 'src/main/kotlin'
38 | }
39 |
40 | kotlinOptions {
41 | jvmTarget = JavaVersion.VERSION_1_8
42 | }
43 |
44 | compileOptions {
45 | sourceCompatibility = JavaVersion.VERSION_1_8
46 | targetCompatibility = JavaVersion.VERSION_1_8
47 | }
48 |
49 | lintOptions {
50 | disable 'InvalidPackage'
51 | }
52 |
53 | defaultConfig {
54 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
55 | applicationId = "yukams.app.background_locator_example"
56 | minSdk = flutter.minSdkVersion
57 | minSdkVersion = 23
58 | targetSdk = flutter.targetSdkVersion
59 | versionCode = flutter.versionCode
60 | versionName = flutter.versionName
61 | }
62 |
63 | buildTypes {
64 | release {
65 | // TODO: Add your own signing config for the release build.
66 | // Signing with the debug keys for now, so `flutter run --release` works.
67 | signingConfig signingConfigs.debug
68 | }
69 | }
70 | }
71 |
72 | flutter {
73 | source '../..'
74 | }
75 |
76 | dependencies {
77 | testImplementation 'junit:junit:4.12'
78 | androidTestImplementation 'androidx.test:runner:1.3.0'
79 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
80 | }
81 |
--------------------------------------------------------------------------------
/ios/Classes/Globals.h:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.h
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/3/20.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 |
12 | @interface Globals : NSObject
13 |
14 | FOUNDATION_EXPORT NSString *const kCallbackDispatcherKey;
15 | FOUNDATION_EXPORT NSString *const kCallbackKey;
16 | FOUNDATION_EXPORT NSString *const kInitCallbackKey;
17 | FOUNDATION_EXPORT NSString *const kInitDataCallbackKey;
18 | FOUNDATION_EXPORT NSString *const kDisposeCallbackKey;
19 | FOUNDATION_EXPORT NSString *const kDistanceFilterKey;
20 |
21 | FOUNDATION_EXPORT NSString *const kChannelId;
22 | FOUNDATION_EXPORT NSString *const kBackgroundChannelId;
23 |
24 | FOUNDATION_EXPORT NSString *const kMethodServiceInitialized;
25 | FOUNDATION_EXPORT NSString *const kMethodPluginInitializeService;
26 | FOUNDATION_EXPORT NSString *const kMethodPluginRegisterLocationUpdate;
27 | FOUNDATION_EXPORT NSString *const kMethodPluginUnRegisterLocationUpdate;
28 | FOUNDATION_EXPORT NSString *const kMethodPluginIsRegisteredLocationUpdate;
29 | FOUNDATION_EXPORT NSString *const kMethodPluginIsServiceRunning;
30 | FOUNDATION_EXPORT NSString *const kMethodPluginUpdateNotification;
31 |
32 | FOUNDATION_EXPORT NSString *const kArgLatitude;
33 | FOUNDATION_EXPORT NSString *const kArgLongitude;
34 | FOUNDATION_EXPORT NSString *const kArgAccuracy;
35 | FOUNDATION_EXPORT NSString *const kArgAltitude;
36 | FOUNDATION_EXPORT NSString *const kArgSpeed;
37 | FOUNDATION_EXPORT NSString *const kArgSpeedAccuracy;
38 | FOUNDATION_EXPORT NSString *const kArgHeading;
39 | FOUNDATION_EXPORT NSString *const kArgTime;
40 | FOUNDATION_EXPORT NSString *const kArgCallback;
41 | FOUNDATION_EXPORT NSString *const kArgInitCallback;
42 | FOUNDATION_EXPORT NSString *const kArgInitDataCallback;
43 | FOUNDATION_EXPORT NSString *const kArgDisposeCallback;
44 | FOUNDATION_EXPORT NSString *const kArgLocation;
45 | FOUNDATION_EXPORT NSString *const kArgSettings;
46 | FOUNDATION_EXPORT NSString *const kArgCallbackDispatcher;
47 |
48 | FOUNDATION_EXPORT NSString *const kSettingsAccuracy;
49 | FOUNDATION_EXPORT NSString *const kSettingsDistanceFilter;
50 | FOUNDATION_EXPORT NSString *const kSettingsShowsBackgroundLocationIndicator;
51 | FOUNDATION_EXPORT NSString *const kSettingsStopWithTerminate;
52 |
53 | FOUNDATION_EXPORT NSString *const kBCMSendLocation;
54 | FOUNDATION_EXPORT NSString *const kBCMInit;
55 | FOUNDATION_EXPORT NSString *const kBCMDispose;
56 |
57 | FOUNDATION_EXPORT NSString *const kPrefObservingRegion;
58 | FOUNDATION_EXPORT NSString *const kPrefServiceRunning;
59 | FOUNDATION_EXPORT NSString *const kPrefStopWithTerminate;
60 |
61 | @end
62 |
63 | NS_ASSUME_NONNULL_END
64 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/LocationParserUtil.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | import android.location.Location
4 | import android.os.Build
5 | import com.google.android.gms.location.LocationResult
6 | import yukams.app.background_locator_2.Keys
7 | import java.util.HashMap
8 |
9 | class LocationParserUtil {
10 | companion object {
11 | fun getLocationMapFromLocation(location: Location): HashMap {
12 | var speedAccuracy = 0f
13 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
14 | speedAccuracy = location.speedAccuracyMetersPerSecond
15 | }
16 | var isMocked = false
17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
18 | isMocked = location.isFromMockProvider
19 | }
20 |
21 | return hashMapOf(
22 | Keys.ARG_IS_MOCKED to isMocked,
23 | Keys.ARG_LATITUDE to location.latitude,
24 | Keys.ARG_LONGITUDE to location.longitude,
25 | Keys.ARG_ACCURACY to location.accuracy,
26 | Keys.ARG_ALTITUDE to location.altitude,
27 | Keys.ARG_SPEED to location.speed,
28 | Keys.ARG_SPEED_ACCURACY to speedAccuracy,
29 | Keys.ARG_HEADING to location.bearing,
30 | Keys.ARG_TIME to location.time.toDouble(),
31 | Keys.ARG_PROVIDER to location.provider
32 | )
33 | }
34 |
35 | fun getLocationMapFromLocation(location: LocationResult?): HashMap? {
36 | val firstLocation = location?.lastLocation ?: return null
37 |
38 | var speedAccuracy = 0f
39 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
40 | speedAccuracy = firstLocation.speedAccuracyMetersPerSecond
41 | }
42 | var isMocked = false
43 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
44 | isMocked = firstLocation.isFromMockProvider
45 | }
46 |
47 | return hashMapOf(
48 | Keys.ARG_IS_MOCKED to isMocked,
49 | Keys.ARG_LATITUDE to firstLocation.latitude,
50 | Keys.ARG_LONGITUDE to firstLocation.longitude,
51 | Keys.ARG_ACCURACY to firstLocation.accuracy,
52 | Keys.ARG_ALTITUDE to firstLocation.altitude,
53 | Keys.ARG_SPEED to firstLocation.speed,
54 | Keys.ARG_SPEED_ACCURACY to speedAccuracy,
55 | Keys.ARG_HEADING to firstLocation.bearing,
56 | Keys.ARG_TIME to firstLocation.time.toDouble())
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/lib/utils/settings_util.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'dart:ui';
3 |
4 | import 'package:background_locator_2/keys.dart';
5 | import 'package:background_locator_2/location_dto.dart';
6 | import 'package:background_locator_2/settings/android_settings.dart';
7 | import 'package:background_locator_2/settings/ios_settings.dart';
8 |
9 | class SettingsUtil {
10 | static Map getArgumentsMap(
11 | {required void Function(LocationDto) callback,
12 | void Function(Map)? initCallback,
13 | Map? initDataCallback,
14 | void Function()? disposeCallback,
15 | AndroidSettings androidSettings = const AndroidSettings(),
16 | IOSSettings iosSettings = const IOSSettings()}) {
17 | final args = _getCommonArgumentsMap(callback: callback,
18 | initCallback: initCallback,
19 | initDataCallback: initDataCallback,
20 | disposeCallback: disposeCallback);
21 |
22 | if (Platform.isAndroid) {
23 | args.addAll(_getAndroidArgumentsMap(androidSettings));
24 | } else if (Platform.isIOS) {
25 | args.addAll(_getIOSArgumentsMap(iosSettings));
26 | }
27 |
28 | return args;
29 | }
30 |
31 | static Map _getCommonArgumentsMap({
32 | required void Function(LocationDto) callback,
33 | void Function(Map)? initCallback,
34 | Map? initDataCallback,
35 | void Function()? disposeCallback
36 | }) {
37 | final Map args = {
38 | Keys.ARG_CALLBACK:
39 | PluginUtilities.getCallbackHandle(callback)!.toRawHandle(),
40 | };
41 |
42 | if (initCallback != null) {
43 | args[Keys.ARG_INIT_CALLBACK] =
44 | PluginUtilities.getCallbackHandle(initCallback)!.toRawHandle();
45 | }
46 | if (disposeCallback != null) {
47 | args[Keys.ARG_DISPOSE_CALLBACK] =
48 | PluginUtilities.getCallbackHandle(disposeCallback)!.toRawHandle();
49 | }
50 | if (initDataCallback != null ){
51 | args[Keys.ARG_INIT_DATA_CALLBACK] = initDataCallback;
52 |
53 | }
54 |
55 | return args;
56 | }
57 |
58 | static Map _getAndroidArgumentsMap(
59 | AndroidSettings androidSettings) {
60 | final Map args = {
61 | Keys.ARG_SETTINGS: androidSettings.toMap()
62 | };
63 |
64 | if (androidSettings.androidNotificationSettings.notificationTapCallback !=
65 | null) {
66 | args[Keys.ARG_NOTIFICATION_CALLBACK] = PluginUtilities.getCallbackHandle(
67 | androidSettings
68 | .androidNotificationSettings.notificationTapCallback!)!
69 | .toRawHandle();
70 | }
71 |
72 | return args;
73 | }
74 |
75 | static Map _getIOSArgumentsMap(IOSSettings iosSettings) {
76 | return iosSettings.toMap();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/ios/Classes/Globals.m:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.m
3 | // background_locator_2
4 | //
5 | // Created by Mehdi Sohrabi on 6/3/20.
6 | //
7 |
8 | #import "Globals.h"
9 |
10 | @implementation Globals
11 |
12 | NSString *const kCallbackDispatcherKey = @"callback_dispatcher_handle_key";
13 | NSString *const kCallbackKey = @"callback_handle_key";
14 | NSString *const kInitCallbackKey = @"init_callback_handle_key";
15 | NSString *const kInitDataCallbackKey = @"init_data_callback_key";
16 | NSString *const kDisposeCallbackKey = @"dispose_callback_handle_key";
17 | NSString *const kDistanceFilterKey = @"distance_filter_key";
18 | NSString *const kChannelId = @"app.yukams/locator_plugin";
19 | NSString *const kBackgroundChannelId = @"app.yukams/locator_plugin_background";
20 |
21 | NSString *const kMethodServiceInitialized = @"LocatorService.initialized";
22 | NSString *const kMethodPluginInitializeService = @"LocatorPlugin.initializeService";
23 | NSString *const kMethodPluginRegisterLocationUpdate = @"LocatorPlugin.registerLocationUpdate";
24 | NSString *const kMethodPluginUnRegisterLocationUpdate = @"LocatorPlugin.unRegisterLocationUpdate";
25 | NSString *const kMethodPluginIsRegisteredLocationUpdate = @"LocatorPlugin.isRegisterLocationUpdate";
26 | NSString *const kMethodPluginIsServiceRunning = @"LocatorPlugin.isServiceRunning";
27 | NSString *const kMethodPluginUpdateNotification = @"LocatorPlugin.updateNotification";
28 |
29 | NSString *const kArgLatitude = @"latitude";
30 | NSString *const kArgLongitude = @"longitude";
31 | NSString *const kArgAccuracy = @"accuracy";
32 | NSString *const kArgAltitude = @"altitude";
33 | NSString *const kArgSpeed = @"speed";
34 | NSString *const kArgSpeedAccuracy = @"speed_accuracy";
35 | NSString *const kArgHeading = @"heading";
36 | NSString *const kArgTime = @"time";
37 | NSString *const kArgCallback = @"callback";
38 | NSString *const kArgInitCallback = @"initCallback";
39 | NSString *const kArgInitDataCallback = @"initDataCallback";
40 | NSString *const kArgDisposeCallback = @"disposeCallback";
41 | NSString *const kArgLocation = @"location";
42 | NSString *const kArgSettings = @"settings";
43 | NSString *const kArgCallbackDispatcher = @"callbackDispatcher";
44 |
45 | NSString *const kSettingsAccuracy = @"settings_accuracy";
46 | NSString *const kSettingsDistanceFilter = @"settings_distanceFilter";
47 | NSString *const kSettingsShowsBackgroundLocationIndicator = @"settings_ios_showsBackgroundLocationIndicator";
48 | NSString *const kSettingsStopWithTerminate = @"settings_ios_stopWithTerminate";
49 |
50 | NSString *const kBCMSendLocation = @"BCM_SEND_LOCATION";
51 | NSString *const kBCMInit = @"BCM_INIT";
52 | NSString *const kBCMDispose = @"BCM_DISPOSE";
53 |
54 | NSString *const kPrefObservingRegion = @"pref_observingRegion";
55 | NSString *const kPrefServiceRunning = @"pref_serviceRunning";
56 | NSString *const kPrefStopWithTerminate = @"pref_isStopWithTerminate";
57 |
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/example/lib/location_service_repository.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:isolate';
3 | import 'dart:math';
4 | import 'dart:ui';
5 |
6 | import 'package:background_locator_2/location_dto.dart';
7 |
8 | import 'file_manager.dart';
9 |
10 | class LocationServiceRepository {
11 | static LocationServiceRepository _instance = LocationServiceRepository._();
12 |
13 | LocationServiceRepository._();
14 |
15 | factory LocationServiceRepository() {
16 | return _instance;
17 | }
18 |
19 | static const String isolateName = 'LocatorIsolate';
20 |
21 | int _count = -1;
22 |
23 | Future init(Map params) async {
24 | //TODO change logs
25 | print("***********Init callback handler");
26 | if (params.containsKey('countInit')) {
27 | dynamic tmpCount = params['countInit'];
28 | if (tmpCount is double) {
29 | _count = tmpCount.toInt();
30 | } else if (tmpCount is String) {
31 | _count = int.parse(tmpCount);
32 | } else if (tmpCount is int) {
33 | _count = tmpCount;
34 | } else {
35 | _count = -2;
36 | }
37 | } else {
38 | _count = 0;
39 | }
40 | print("$_count");
41 | await setLogLabel("start");
42 | final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
43 | send?.send(null);
44 | }
45 |
46 | Future dispose() async {
47 | print("***********Dispose callback handler");
48 | print("$_count");
49 | await setLogLabel("end");
50 | final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
51 | send?.send(null);
52 | }
53 |
54 | Future callback(LocationDto locationDto) async {
55 | print('$_count location in dart: ${locationDto.toString()}');
56 | await setLogPosition(_count, locationDto);
57 | final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
58 | send?.send(locationDto.toJson());
59 | _count++;
60 |
61 | }
62 |
63 | static Future setLogLabel(String label) async {
64 | final date = DateTime.now();
65 | await FileManager.writeToLogFile(
66 | '------------\n$label: ${formatDateLog(date)}\n------------\n');
67 | }
68 |
69 | static Future setLogPosition(int count, LocationDto data) async {
70 | final date = DateTime.now();
71 | await FileManager.writeToLogFile(
72 | '$count : ${formatDateLog(date)} --> ${formatLog(data)} --- isMocked: ${data.isMocked}\n');
73 | }
74 |
75 | static double dp(double val, int places) {
76 | double mod =(pow(10.0, places)).toDouble();
77 | return ((val * mod).round().toDouble() / mod);
78 | }
79 |
80 | static String formatDateLog(DateTime date) {
81 | return date.hour.toString() +
82 | ":" +
83 | date.minute.toString() +
84 | ":" +
85 | date.second.toString();
86 | }
87 |
88 | static String formatLog(LocationDto locationDto) {
89 | return dp(locationDto.latitude, 4).toString() +
90 | " " +
91 | dp(locationDto.longitude, 4).toString();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lib/background_locator.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:ui';
3 |
4 | import 'package:background_locator_2/settings/android_settings.dart';
5 | import 'package:background_locator_2/settings/ios_settings.dart';
6 | import 'package:background_locator_2/utils/settings_util.dart';
7 | import 'package:flutter/services.dart';
8 | import 'package:flutter/widgets.dart';
9 |
10 | import 'auto_stop_handler.dart';
11 | import 'callback_dispatcher.dart';
12 | import 'keys.dart';
13 | import 'location_dto.dart';
14 |
15 | class BackgroundLocator {
16 | static const MethodChannel _channel = const MethodChannel(Keys.CHANNEL_ID);
17 |
18 | static Future initialize() async {
19 | final CallbackHandle callback =
20 | PluginUtilities.getCallbackHandle(callbackDispatcher)!;
21 | await _channel.invokeMethod(Keys.METHOD_PLUGIN_INITIALIZE_SERVICE,
22 | {Keys.ARG_CALLBACK_DISPATCHER: callback.toRawHandle()});
23 | }
24 |
25 | static WidgetsBinding? get _widgetsBinding => WidgetsBinding.instance;
26 |
27 | static Future registerLocationUpdate(
28 | void Function(LocationDto) callback,
29 | {void Function(Map)? initCallback,
30 | Map initDataCallback = const {},
31 | void Function()? disposeCallback,
32 | bool autoStop = false,
33 | AndroidSettings androidSettings = const AndroidSettings(),
34 | IOSSettings iosSettings = const IOSSettings()}) async {
35 | if (autoStop) {
36 | _widgetsBinding!.addObserver(AutoStopHandler());
37 | }
38 |
39 | final args = SettingsUtil.getArgumentsMap(
40 | callback: callback,
41 | initCallback: initCallback,
42 | initDataCallback: initDataCallback,
43 | disposeCallback: disposeCallback,
44 | androidSettings: androidSettings,
45 | iosSettings: iosSettings);
46 |
47 | await _channel.invokeMethod(
48 | Keys.METHOD_PLUGIN_REGISTER_LOCATION_UPDATE, args);
49 | }
50 |
51 | static Future unRegisterLocationUpdate() async {
52 | await _channel.invokeMethod(Keys.METHOD_PLUGIN_UN_REGISTER_LOCATION_UPDATE);
53 | }
54 |
55 | static Future isRegisterLocationUpdate() async {
56 | return (await _channel
57 | .invokeMethod(Keys.METHOD_PLUGIN_IS_REGISTER_LOCATION_UPDATE))!;
58 | }
59 |
60 | static Future isServiceRunning() async {
61 | return (await _channel
62 | .invokeMethod(Keys.METHOD_PLUGIN_IS_SERVICE_RUNNING))!;
63 | }
64 |
65 | static Future updateNotificationText(
66 | {String? title, String? msg, String? bigMsg}) async {
67 | final Map arg = {};
68 |
69 | if (title != null) {
70 | arg[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] = title;
71 | }
72 |
73 | if (msg != null) {
74 | arg[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] = msg;
75 | }
76 |
77 | if (bigMsg != null) {
78 | arg[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] = bigMsg;
79 | }
80 |
81 | await _channel.invokeMethod(Keys.METHOD_PLUGIN_UPDATE_NOTIFICATION, arg);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-App-20x20@1x.png",
61 | "scale" : "1x"
62 | },
63 | {
64 | "size" : "20x20",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-App-20x20@2x.png",
67 | "scale" : "2x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-App-29x29@1x.png",
73 | "scale" : "1x"
74 | },
75 | {
76 | "size" : "29x29",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-App-29x29@2x.png",
79 | "scale" : "2x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-App-40x40@1x.png",
85 | "scale" : "1x"
86 | },
87 | {
88 | "size" : "40x40",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-40x40@2x.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@1x.png",
97 | "scale" : "1x"
98 | },
99 | {
100 | "size" : "76x76",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-76x76@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "83.5x83.5",
107 | "idiom" : "ipad",
108 | "filename" : "Icon-App-83.5x83.5@2x.png",
109 | "scale" : "2x"
110 | },
111 | {
112 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
26 |
35 |
38 |
42 |
43 |
44 |
45 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
37 |
38 |
39 |
40 |
41 |
42 |
52 |
54 |
60 |
61 |
62 |
63 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/keys.dart:
--------------------------------------------------------------------------------
1 | class Keys {
2 | static const String CHANNEL_ID = 'app.yukams/locator_plugin';
3 | static const String BACKGROUND_CHANNEL_ID =
4 | 'app.yukams/locator_plugin_background';
5 |
6 | static const String METHOD_SERVICE_INITIALIZED = 'LocatorService.initialized';
7 | static const String METHOD_PLUGIN_INITIALIZE_SERVICE =
8 | 'LocatorPlugin.initializeService';
9 | static const String METHOD_PLUGIN_REGISTER_LOCATION_UPDATE =
10 | 'LocatorPlugin.registerLocationUpdate';
11 | static const String METHOD_PLUGIN_UN_REGISTER_LOCATION_UPDATE =
12 | 'LocatorPlugin.unRegisterLocationUpdate';
13 | static const String METHOD_PLUGIN_IS_REGISTER_LOCATION_UPDATE =
14 | 'LocatorPlugin.isRegisterLocationUpdate';
15 | static const String METHOD_PLUGIN_IS_SERVICE_RUNNING =
16 | 'LocatorPlugin.isServiceRunning';
17 | static const String METHOD_PLUGIN_UPDATE_NOTIFICATION =
18 | 'LocatorPlugin.updateNotification';
19 |
20 | static const String ARG_IS_MOCKED = 'is_mocked';
21 | static const String ARG_LATITUDE = 'latitude';
22 | static const String ARG_LONGITUDE = 'longitude';
23 | static const String ARG_ALTITUDE = 'altitude';
24 | static const String ARG_ACCURACY = 'accuracy';
25 | static const String ARG_SPEED = 'speed';
26 | static const String ARG_SPEED_ACCURACY = 'speed_accuracy';
27 | static const String ARG_HEADING = 'heading';
28 | static const String ARG_TIME = 'time';
29 | static const String ARG_PROVIDER = 'provider';
30 | static const String ARG_CALLBACK = 'callback';
31 | static const String ARG_NOTIFICATION_CALLBACK = 'notificationCallback';
32 | static const String ARG_INIT_CALLBACK = 'initCallback';
33 | static const String ARG_INIT_DATA_CALLBACK = 'initDataCallback';
34 | static const String ARG_DISPOSE_CALLBACK = 'disposeCallback';
35 | static const String ARG_LOCATION = 'location';
36 | static const String ARG_SETTINGS = 'settings';
37 | static const String ARG_CALLBACK_DISPATCHER = 'callbackDispatcher';
38 |
39 | static const String SETTINGS_ACCURACY = 'settings_accuracy';
40 | static const String SETTINGS_INTERVAL = 'settings_interval';
41 | static const String SETTINGS_DISTANCE_FILTER = 'settings_distanceFilter';
42 | static const String SETTINGS_AUTO_STOP = 'settings_autoStop';
43 | static const String SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME =
44 | 'settings_android_notificationChannelName';
45 | static const String SETTINGS_ANDROID_NOTIFICATION_TITLE =
46 | 'settings_android_notificationTitle';
47 | static const String SETTINGS_ANDROID_NOTIFICATION_MSG =
48 | 'settings_android_notificationMsg';
49 | static const String SETTINGS_ANDROID_NOTIFICATION_BIG_MSG =
50 | 'settings_android_notificationBigMsg';
51 | static const String SETTINGS_ANDROID_NOTIFICATION_ICON =
52 | 'settings_android_notificationIcon';
53 | static const String SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR =
54 | 'settings_android_notificationIconColor';
55 | static const String SETTINGS_ANDROID_WAKE_LOCK_TIME =
56 | 'settings_android_wakeLockTime';
57 | static const String SETTINGS_ANDROID_LOCATION_CLIENT =
58 | "settings_android_location_client";
59 |
60 | static const String SETTINGS_IOS_SHOWS_BACKGROUND_LOCATION_INDICATOR =
61 | 'settings_ios_showsBackgroundLocationIndicator';
62 | static const String SETTINGS_IOS_STOP_WITH_TERMINATE =
63 | 'settings_ios_stopWithTerminate';
64 |
65 | static const String BCM_SEND_LOCATION = 'BCM_SEND_LOCATION';
66 | static const String BCM_NOTIFICATION_CLICK = 'BCM_NOTIFICATION_CLICK';
67 | static const String BCM_INIT = 'BCM_INIT';
68 | static const String BCM_DISPOSE = 'BCM_DISPOSE';
69 | }
70 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/provider/AndroidLocationProviderClient.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2.provider
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.location.Location
6 | import android.location.LocationListener
7 | import android.location.LocationManager
8 | import androidx.core.content.ContextCompat
9 | import android.os.Bundle
10 |
11 | class AndroidLocationProviderClient(context: Context, override var listener: LocationUpdateListener?) : BLLocationProvider, LocationListener {
12 | private val client: LocationManager? =
13 | ContextCompat.getSystemService(context, LocationManager::class.java)
14 |
15 | private var overrideLocation: Boolean = false
16 | private var timeOfLastLocation: Long = 0L
17 | private var timeBetweenLocation: Long = 0L
18 |
19 | @SuppressLint("MissingPermission")
20 | override fun removeLocationUpdates() {
21 | client?.removeUpdates(this)
22 | }
23 |
24 | @SuppressLint("MissingPermission")
25 | override fun requestLocationUpdates(request: LocationRequestOptions) {
26 | var gpsLocation: Location? = null
27 | var networkLocation: Location? = null
28 | timeBetweenLocation = request.interval
29 | if (client?.isProviderEnabled(LocationManager.GPS_PROVIDER) == true) {
30 | client.requestLocationUpdates(LocationManager.GPS_PROVIDER,
31 | request.interval,
32 | request.distanceFilter,
33 | this)
34 | }
35 | if (client?.isProviderEnabled(LocationManager.NETWORK_PROVIDER) == true) {
36 | client.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
37 | request.interval,
38 | request.distanceFilter,
39 | this)
40 | }
41 | gpsLocation = client?.getLastKnownLocation(LocationManager.GPS_PROVIDER)
42 | networkLocation = client?.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
43 | // return the android device last Location after start request location
44 | if (gpsLocation != null && networkLocation != null) {
45 | if (gpsLocation.time < networkLocation.time) {
46 | onLocationChanged(networkLocation)
47 | } else {
48 | onLocationChanged(gpsLocation)
49 | }
50 | } else if (gpsLocation != null) {
51 | onLocationChanged(gpsLocation)
52 | } else if (networkLocation != null) {
53 | onLocationChanged(networkLocation)
54 | }
55 | }
56 |
57 | override fun onLocationChanged(location: Location) {
58 | overrideLocation = false
59 | //whenever the expected time period is reached invalidate the last known accuracy
60 | // so that we don't just receive better and better accuracy and eventually risk receiving
61 | // only minimal locations
62 | if (location.hasAccuracy()) {
63 | if (!location.accuracy.isNaN() &&
64 | location.accuracy != 0.0f &&
65 | !location.accuracy.isFinite() &&
66 | !location.accuracy.isInfinite()) {
67 | overrideLocation = true
68 | }
69 | }
70 | //ensure that we don't get a lot of events
71 | // or if enabled, only get more accurate events within mTimeBetweenLocationEvents
72 | if (location.time - timeOfLastLocation >= timeBetweenLocation || overrideLocation) {
73 | //be sure to store the time of receiving this event !
74 | timeOfLastLocation = location.time
75 | //send message to parent containing the location object
76 | listener?.onLocationUpdated(LocationParserUtil.getLocationMapFromLocation(location))
77 | }
78 | }
79 |
80 | override fun onProviderDisabled(provider: String) {
81 | // nop
82 | }
83 |
84 | override fun onProviderEnabled(provider: String) {
85 | // nop
86 | }
87 | override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
88 |
89 | }
--------------------------------------------------------------------------------
/lib/settings/android_settings.dart:
--------------------------------------------------------------------------------
1 | import 'package:background_locator_2/keys.dart';
2 | import 'package:background_locator_2/settings/locator_settings.dart';
3 | import 'package:flutter/material.dart';
4 |
5 | enum LocationClient { google, android }
6 |
7 | class AndroidNotificationSettings {
8 | final String notificationChannelName;
9 | final String notificationTitle;
10 | final String notificationMsg;
11 | final String notificationBigMsg;
12 | final String notificationIcon;
13 | final Color notificationIconColor;
14 | final VoidCallback? notificationTapCallback;
15 |
16 | /// [notificationTitle] Title of the notification. Only applies for android. Default is 'Start Location Tracking'.
17 | ///
18 | /// [notificationMsg] Message of notification. Only applies for android. Default is 'Track location in background'.
19 | ///
20 | /// [notificationBigMsg] Message to be displayed in the expanded content area of the notification. Only applies for android. Default is '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.'.
21 | ///
22 | /// [notificationIcon] Icon name for notification. Only applies for android. The icon should be in 'mipmap' Directory.
23 | /// Default is app icon. Icon must comply to android rules to be displayed (transparent background and black/white shape)
24 | ///
25 | /// [notificationIconColor] Icon color for notification from notification drawer. Only applies for android. Default color is grey.
26 | ///
27 | /// [notificationTapCallback] callback for notification tap
28 | ///
29 | const AndroidNotificationSettings(
30 | {this.notificationChannelName = 'Location tracking',
31 | this.notificationTitle = 'Start Location Tracking',
32 | this.notificationMsg = 'Track location in background',
33 | this.notificationBigMsg =
34 | '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.',
35 | this.notificationIcon = '',
36 | this.notificationIconColor = Colors.grey,
37 | this.notificationTapCallback});
38 | }
39 |
40 | class AndroidSettings extends LocatorSettings {
41 | final AndroidNotificationSettings androidNotificationSettings;
42 | final int wakeLockTime;
43 | final int interval;
44 | final LocationClient client;
45 |
46 | /// [accuracy] The accuracy of location, Default is max accuracy NAVIGATION.
47 | ///
48 | /// [interval] Interval of retrieving location update in second. Only applies for android. Default is 5 second.
49 | ///
50 | /// [distanceFilter] distance in meter to trigger location update, Default is 0 meter.
51 | ///
52 | /// [androidNotificationSettings] Specific setting for android notification.
53 | ///
54 | /// [wakeLockTime] Time for living service in background in minutes. Only applies in android. Default is 60 minute.
55 | const AndroidSettings(
56 | {LocationAccuracy accuracy = LocationAccuracy.NAVIGATION,
57 | this.interval = 5,
58 | double distanceFilter = 0,
59 | this.androidNotificationSettings = const AndroidNotificationSettings(),
60 | this.wakeLockTime = 60,
61 | this.client = LocationClient.google})
62 | : super(accuracy: accuracy, distanceFilter: distanceFilter);
63 |
64 | Map toMap() {
65 | return {
66 | Keys.SETTINGS_ACCURACY: accuracy.value,
67 | Keys.SETTINGS_INTERVAL: interval,
68 | Keys.SETTINGS_DISTANCE_FILTER: distanceFilter,
69 | Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME: wakeLockTime,
70 | Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME:
71 | androidNotificationSettings.notificationChannelName,
72 | Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE:
73 | androidNotificationSettings.notificationTitle,
74 | Keys.SETTINGS_ANDROID_NOTIFICATION_MSG:
75 | androidNotificationSettings.notificationMsg,
76 | Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG:
77 | androidNotificationSettings.notificationBigMsg,
78 | Keys.SETTINGS_ANDROID_NOTIFICATION_ICON:
79 | androidNotificationSettings.notificationIcon,
80 | Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR:
81 | androidNotificationSettings.notificationIconColor.value,
82 | Keys.SETTINGS_ANDROID_LOCATION_CLIENT: client.index
83 | };
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/IsolateHolderExtension.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2
2 |
3 | import android.Manifest
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.pm.PackageManager
7 | import android.os.Build
8 | import android.util.Log
9 | import com.google.android.gms.location.LocationRequest
10 | import io.flutter.FlutterInjector
11 | import io.flutter.embedding.engine.FlutterEngine
12 | import io.flutter.embedding.engine.dart.DartExecutor
13 | import io.flutter.plugin.common.MethodChannel
14 | import io.flutter.view.FlutterCallbackInformation
15 | import yukams.app.background_locator_2.IsolateHolderService.Companion.isServiceInitialized
16 | import yukams.app.background_locator_2.provider.LocationRequestOptions
17 | import java.lang.RuntimeException
18 | import java.util.concurrent.atomic.AtomicBoolean
19 |
20 | internal fun IsolateHolderService.startLocatorService(context: Context) {
21 |
22 | val serviceStarted = AtomicBoolean(IsolateHolderService.isServiceRunning)
23 | // start synchronized block to prevent multiple service instant
24 | synchronized(serviceStarted) {
25 | this.context = context
26 | // resetting the background engine to avoid being stuck after an app crash
27 | IsolateHolderService.backgroundEngine?.destroy();
28 | IsolateHolderService.backgroundEngine = null
29 | try {
30 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
31 | context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
32 | == PackageManager.PERMISSION_GRANTED
33 | ) {
34 | // We need flutter engine to handle callback, so if it is not available we have to create a
35 | // Flutter engine without any view
36 | Log.e("IsolateHolderService", "startLocatorService: Start Flutter Engine")
37 | IsolateHolderService.backgroundEngine = FlutterEngine(context)
38 |
39 | val callbackHandle = context.getSharedPreferences(
40 | Keys.SHARED_PREFERENCES_KEY,
41 | Context.MODE_PRIVATE
42 | )
43 | .getLong(Keys.CALLBACK_DISPATCHER_HANDLE_KEY, 0)
44 | val callbackInfo =
45 | FlutterCallbackInformation.lookupCallbackInformation(callbackHandle)
46 |
47 | if(callbackInfo == null) {
48 | Log.e("IsolateHolderExtension", "Fatal: failed to find callback");
49 | return;
50 | }
51 |
52 | val args = DartExecutor.DartCallback(
53 | context.assets,
54 | FlutterInjector.instance().flutterLoader().findAppBundlePath(),
55 | callbackInfo
56 | )
57 | IsolateHolderService.backgroundEngine?.dartExecutor?.executeDartCallback(args)
58 | isServiceInitialized = true
59 | Log.e("IsolateHolderExtension", "service initialized")
60 | }
61 | } catch (e: UnsatisfiedLinkError) {
62 | e.printStackTrace()
63 | }
64 | }
65 |
66 | IsolateHolderService.getBinaryMessenger(context)?.let { binaryMessenger ->
67 | backgroundChannel =
68 | MethodChannel(
69 | binaryMessenger,
70 | Keys.BACKGROUND_CHANNEL_ID
71 | )
72 | try {
73 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
74 | context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
75 | == PackageManager.PERMISSION_GRANTED
76 | ) {
77 | backgroundChannel.setMethodCallHandler(this)
78 | }
79 | } catch (e: RuntimeException) {
80 | e.printStackTrace()
81 | }
82 | }
83 | }
84 |
85 | fun getLocationRequest(intent: Intent): LocationRequestOptions {
86 | val interval: Long = (intent.getIntExtra(Keys.SETTINGS_INTERVAL, 10) * 1000).toLong()
87 | val accuracyKey = intent.getIntExtra(Keys.SETTINGS_ACCURACY, 4)
88 | val accuracy = getAccuracy(accuracyKey)
89 | val distanceFilter = intent.getDoubleExtra(Keys.SETTINGS_DISTANCE_FILTER, 0.0)
90 |
91 | return LocationRequestOptions(interval, accuracy, distanceFilter.toFloat())
92 | }
93 |
94 | fun getAccuracy(key: Int): Int {
95 | return when (key) {
96 | 0 -> LocationRequest.PRIORITY_NO_POWER
97 | 1 -> LocationRequest.PRIORITY_LOW_POWER
98 | 2 -> LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
99 | 3 -> LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
100 | 4 -> LocationRequest.PRIORITY_HIGH_ACCURACY
101 | else -> LocationRequest.PRIORITY_HIGH_ACCURACY
102 | }
103 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.0.6
2 | * Fixing iOS build
3 | * Fixing memory leak on Android
4 | * Fixing callbacks on older Android devices
5 |
6 | ## 2.0.6-dev.2
7 | * Fixing iOS build
8 | * Fixing memory leak on Android
9 | * Fixing callbacks on older Android devices
10 |
11 | ## 2.0.6-dev.1
12 | * Fix Type mismatch: inferred type is String? but Any was expected
13 |
14 | ## 2.0.5
15 | * Fixing demo gif
16 |
17 | ## 2.0.4
18 | * Merging 2.0.4-dev1 and 2.0.4-dev2 to the main branch
19 |
20 | ## 2.0.4-dev.2
21 | * Adding auto stop on app terminate on iOS
22 | * Fixing import on example test script
23 |
24 | ## 2.0.4-dev.1
25 | * Fixing iOS build
26 | * Replacing package:background_locator_2 by background_locator_2
27 |
28 | ## 2.0.3
29 | * Replacing background_locator by background_locator_2 **(BREAKING CHANGE)**
30 | * Replacing rekab by yukams
31 |
32 | ## 2.0.2
33 | * Adding fields to pubspec.yaml
34 | * Changing README.md to prepare it to be published on pub.dev
35 | * Changing LICENCE file
36 |
37 | ## 2.0.1
38 | * Reverting minSdk from 31 to 29
39 |
40 | ## 2.0.0
41 | * New fork
42 | * Support for Flutter 3.0
43 | * Support for NullSafety
44 | * Fix initCallback is now called first as expected
45 | * Fix callback not called
46 | * Fix example
47 | * Fix FLAG_IMMUTABLE error for SDK 23+
48 | * Fix library not working after a phone reboot
49 | * Fix library not working after an app crash due to revoking permissions
50 | * Adding a bit more logs
51 | * Changing minSdk from 29 to 31
52 |
53 | ## 1.6.12
54 | * Fixes onStatusChanged crash;
55 | * Fixed issue #94;
56 | * Fix importing path_provider in ios example;
57 | * Fix issue #266;
58 | * Fix Android 12 location permission handling;
59 | * Add network location provider even gps location data not update;
60 |
61 | ## 1.6.6
62 | * Fix invoking method on flutter channel when engine is not ready; (#254)
63 |
64 | ## 1.6.5
65 | * Fix returning result for unRegisterPlugin method on Android; (#262)
66 |
67 | ## 1.6.4
68 | * Fix triggering location update when plugin is stopped; (#258)
69 | * Fix saving service start stop status; (#259)
70 |
71 | ## 1.6.3
72 | * Bug fixes;
73 |
74 | ## 1.6.2+1-beta
75 | * Bring back init and dispose callback;
76 |
77 | ## 1.6.1+1-beta
78 | * Fix crash on Android location client causing by change in status of location provider;
79 |
80 | ## 1.6.0+2-beta
81 | * Fix crash on start;
82 |
83 | ## 1.6.0+1-beta
84 | * Use new flutter engine;
85 | * Fix start stop bug which prevents correct state in plugin;
86 |
87 | ## 1.5.0+1
88 | * Add null safety support;
89 |
90 | ## 1.4.0+1
91 | * Set default value for autoStop;
92 | * Fix register and unregister futures never complete on Android;
93 | * Fix Doze problem for Android >= 10;
94 |
95 | ## 1.3.2+1
96 | * Fix compile error on sdk 30;
97 | * Fix app stop locating on android sdk 30 in background;
98 |
99 | ## 1.3.0+1
100 | * Add google location client as option;
101 | * Several bug fixes;
102 |
103 | ## 1.2.2+1
104 | * Add platform specific settings;
105 | * Add ability to update android notification;
106 | * Ability to showsBackgroundLocationIndicator on iOS;
107 |
108 | ## 1.1.13+1
109 | * add isServiceRunning method;
110 |
111 | ## 1.1.12+1
112 | * Added support for big text in Android notification;
113 |
114 | ## 1.1.11+1
115 | * Fix getCallbackHandle bug which caused some callbacks not getting executed;
116 |
117 | ## 1.1.10+1
118 | * Add region monitoring for iOS to get location info while app is terminated;
119 | * Minor iOS bug fix;
120 | * Add a way to use 3rd party plugins while app is terminated in iOS;
121 |
122 | ## 1.1.7+1
123 | * Add notification icon color;
124 | * Add isMocked property on location model;
125 | * Add channel name property on location dto;
126 |
127 | ## 1.1.5+1
128 | * Fix crash in onStartCommand caused by null intent on Android;
129 | * Fix getting several unwanted position on iOS;
130 |
131 | ## 1.1.3+1
132 | * Add possibility to restart locator service after reboot;
133 | * Fix triggering android notification callback with wrong notification;
134 |
135 | ## 1.1.2+2
136 | * Fix optional android notification callback.
137 |
138 | ## 1.1.2+1
139 | * Fix accessing other plugins when app is terminated.
140 |
141 | ## 1.1.1+1
142 | * Fix Callback is not triggered in iOS.
143 |
144 | ## 1.1.0+1
145 | * Add callback for android notification.
146 |
147 | ## 1.0.1+2
148 | * Fix crash on detach.
149 |
150 | ## 1.0.1+1
151 | * Add isRegistered method.
152 | * Bug fixes.
153 |
154 | ## 1.0.0+1
155 | * Add auto stop feature.
156 | * Update flutter plugin library to version 2.
157 |
158 | ## 0.0.4-beta
159 | * Add parameter to setting to change android wakelock time.
160 | * Prevent service from registering twice.
161 |
162 | ## 0.0.3-beta
163 | Change where location access requested.
164 |
165 | ## 0.0.2-beta
166 |
167 | * Improvements.
168 |
169 | ## 0.0.1-beta
170 |
171 | * initial release.
172 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/Keys.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2
2 |
3 | class Keys {
4 | companion object {
5 | @JvmStatic
6 | val SHARED_PREFERENCES_KEY:String = "SHARED_PREFERENCES_KEY"
7 |
8 | @JvmStatic
9 | val CALLBACK_DISPATCHER_HANDLE_KEY:String = "CALLBACK_DISPATCHER_HANDLE_KEY"
10 |
11 | @JvmStatic
12 | val CALLBACK_HANDLE_KEY:String = "CALLBACK_HANDLE_KEY"
13 |
14 | @JvmStatic
15 | val NOTIFICATION_CALLBACK_HANDLE_KEY:String = "NOTIFICATION_CALLBACK_HANDLE_KEY"
16 |
17 | @JvmStatic
18 | val INIT_CALLBACK_HANDLE_KEY:String = "INIT_CALLBACK_HANDLE_KEY"
19 |
20 | @JvmStatic
21 | val INIT_DATA_CALLBACK_KEY:String = "INIT_DATA_CALLBACK_KEY"
22 |
23 | @JvmStatic
24 | val DISPOSE_CALLBACK_HANDLE_KEY:String = "DISPOSE_CALLBACK_HANDLE_KEY"
25 |
26 | @JvmStatic
27 | val CHANNEL_ID:String = "app.yukams/locator_plugin"
28 |
29 | @JvmStatic
30 | val BACKGROUND_CHANNEL_ID:String = "app.yukams/locator_plugin_background"
31 |
32 | @JvmStatic
33 | val METHOD_SERVICE_INITIALIZED:String = "LocatorService.initialized"
34 |
35 | @JvmStatic
36 | val METHOD_PLUGIN_INITIALIZE_SERVICE:String = "LocatorPlugin.initializeService"
37 |
38 | @JvmStatic
39 | val METHOD_PLUGIN_REGISTER_LOCATION_UPDATE:String = "LocatorPlugin.registerLocationUpdate"
40 |
41 | @JvmStatic
42 | val METHOD_PLUGIN_UN_REGISTER_LOCATION_UPDATE:String = "LocatorPlugin.unRegisterLocationUpdate"
43 |
44 | @JvmStatic
45 | val METHOD_PLUGIN_IS_REGISTER_LOCATION_UPDATE:String = "LocatorPlugin.isRegisterLocationUpdate"
46 |
47 | @JvmStatic
48 | val METHOD_PLUGIN_IS_SERVICE_RUNNING:String = "LocatorPlugin.isServiceRunning"
49 |
50 | @JvmStatic
51 | val METHOD_PLUGIN_UPDATE_NOTIFICATION:String = "LocatorPlugin.updateNotification"
52 |
53 | @JvmStatic
54 | val ARG_INIT_CALLBACK:String = "initCallback"
55 |
56 | @JvmStatic
57 | val ARG_INIT_DATA_CALLBACK:String = "initDataCallback"
58 |
59 | @JvmStatic
60 | val ARG_DISPOSE_CALLBACK:String = "disposeCallback"
61 |
62 | @JvmStatic
63 | val ARG_IS_MOCKED:String = "is_mocked"
64 |
65 | @JvmStatic
66 | val ARG_LATITUDE:String = "latitude"
67 |
68 | @JvmStatic
69 | val ARG_LONGITUDE:String = "longitude"
70 |
71 | @JvmStatic
72 | val ARG_ACCURACY:String = "accuracy"
73 |
74 | @JvmStatic
75 | val ARG_ALTITUDE:String = "altitude"
76 |
77 | @JvmStatic
78 | val ARG_SPEED:String = "speed"
79 |
80 | @JvmStatic
81 | val ARG_SPEED_ACCURACY:String = "speed_accuracy"
82 |
83 | @JvmStatic
84 | val ARG_HEADING:String = "heading"
85 |
86 | @JvmStatic
87 | val ARG_TIME:String = "time"
88 |
89 | @JvmStatic
90 | val ARG_PROVIDER:String = "provider"
91 |
92 | @JvmStatic
93 | val ARG_CALLBACK:String = "callback"
94 |
95 | @JvmStatic
96 | val ARG_NOTIFICATION_CALLBACK:String = "notificationCallback"
97 |
98 | @JvmStatic
99 | val ARG_LOCATION:String = "location"
100 |
101 | @JvmStatic
102 | val ARG_SETTINGS:String = "settings"
103 |
104 | @JvmStatic
105 | val ARG_CALLBACK_DISPATCHER:String = "callbackDispatcher"
106 |
107 |
108 | @JvmStatic
109 | val SETTINGS_ACCURACY = "settings_accuracy"
110 |
111 | @JvmStatic
112 | val SETTINGS_INTERVAL = "settings_interval"
113 |
114 | @JvmStatic
115 | val SETTINGS_DISTANCE_FILTER = "settings_distanceFilter"
116 |
117 | @JvmStatic
118 | val SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME = "settings_android_notificationChannelName"
119 |
120 | @JvmStatic
121 | val SETTINGS_ANDROID_NOTIFICATION_TITLE = "settings_android_notificationTitle"
122 |
123 | @JvmStatic
124 | val SETTINGS_ANDROID_NOTIFICATION_MSG = "settings_android_notificationMsg"
125 |
126 | @JvmStatic
127 | val SETTINGS_ANDROID_NOTIFICATION_BIG_MSG = "settings_android_notificationBigMsg"
128 |
129 | @JvmStatic
130 | val SETTINGS_ANDROID_NOTIFICATION_ICON = "settings_android_notificationIcon"
131 |
132 | @JvmStatic
133 | val SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR = "settings_android_notificationIconColor"
134 |
135 | @JvmStatic
136 | val SETTINGS_ANDROID_WAKE_LOCK_TIME = "settings_android_wakeLockTime"
137 |
138 | @JvmStatic
139 | val SETTINGS_ANDROID_LOCATION_CLIENT = "settings_android_location_client"
140 |
141 | @JvmStatic
142 | val SETTINGS_INIT_PLUGGABLE = "settings_init_pluggable"
143 |
144 | @JvmStatic
145 | val SETTINGS_DISPOSABLE_PLUGGABLE = "settings_disposable_pluggable"
146 |
147 | @JvmStatic
148 | val BCM_SEND_LOCATION = "BCM_SEND_LOCATION"
149 |
150 | @JvmStatic
151 | val BCM_NOTIFICATION_CLICK = "BCM_NOTIFICATION_CLICK"
152 |
153 | @JvmStatic
154 | val BCM_INIT = "BCM_INIT"
155 |
156 | @JvmStatic
157 | val BCM_DISPOSE = "BCM_DISPOSE"
158 |
159 | @JvmStatic
160 | val NOTIFICATION_ACTION = "yukams.app.background_locator_2.notification"
161 | }
162 | }
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:isolate';
3 | import 'dart:ui';
4 |
5 | import 'package:background_locator_2/background_locator.dart';
6 | import 'package:background_locator_2/location_dto.dart';
7 | import 'package:background_locator_2/settings/android_settings.dart';
8 | import 'package:background_locator_2/settings/ios_settings.dart';
9 | import 'package:background_locator_2/settings/locator_settings.dart';
10 | import 'package:flutter/material.dart';
11 | import 'package:permission_handler/permission_handler.dart';
12 |
13 | import 'file_manager.dart';
14 | import 'location_callback_handler.dart';
15 | import 'location_service_repository.dart';
16 |
17 | void main() => runApp(MyApp());
18 |
19 | class MyApp extends StatefulWidget {
20 | @override
21 | _MyAppState createState() => _MyAppState();
22 | }
23 |
24 | class _MyAppState extends State {
25 | ReceivePort port = ReceivePort();
26 |
27 | String logStr = '';
28 | bool isRunning = false;
29 | LocationDto? lastLocation;
30 |
31 | @override
32 | void initState() {
33 | super.initState();
34 |
35 | if (IsolateNameServer.lookupPortByName(
36 | LocationServiceRepository.isolateName) !=
37 | null) {
38 | IsolateNameServer.removePortNameMapping(
39 | LocationServiceRepository.isolateName);
40 | }
41 |
42 | IsolateNameServer.registerPortWithName(
43 | port.sendPort, LocationServiceRepository.isolateName);
44 |
45 | port.listen(
46 | (dynamic data) async {
47 | await updateUI(data);
48 | },
49 | );
50 | initPlatformState();
51 | }
52 |
53 | @override
54 | void dispose() {
55 | super.dispose();
56 | }
57 |
58 | Future updateUI(dynamic data) async {
59 | final log = await FileManager.readLogFile();
60 |
61 | LocationDto? locationDto = (data != null) ? LocationDto.fromJson(data) : null;
62 | await _updateNotificationText(locationDto);
63 |
64 | setState(() {
65 | if (data != null) {
66 | lastLocation = locationDto;
67 | }
68 | logStr = log;
69 | });
70 | }
71 |
72 | Future _updateNotificationText(LocationDto? data) async {
73 | if (data == null) {
74 | return;
75 | }
76 |
77 | await BackgroundLocator.updateNotificationText(
78 | title: "new location received",
79 | msg: "${DateTime.now()}",
80 | bigMsg: "${data.latitude}, ${data.longitude}");
81 | }
82 |
83 | Future initPlatformState() async {
84 | print('Initializing...');
85 | await BackgroundLocator.initialize();
86 | logStr = await FileManager.readLogFile();
87 | print('Initialization done');
88 | final _isRunning = await BackgroundLocator.isServiceRunning();
89 | setState(() {
90 | isRunning = _isRunning;
91 | });
92 | print('Running ${isRunning.toString()}');
93 | }
94 |
95 | @override
96 | Widget build(BuildContext context) {
97 | final start = SizedBox(
98 | width: double.maxFinite,
99 | child: ElevatedButton(
100 | child: Text('Start'),
101 | onPressed: () {
102 | _onStart();
103 | },
104 | ),
105 | );
106 | final stop = SizedBox(
107 | width: double.maxFinite,
108 | child: ElevatedButton(
109 | child: Text('Stop'),
110 | onPressed: () {
111 | onStop();
112 | },
113 | ),
114 | );
115 | final clear = SizedBox(
116 | width: double.maxFinite,
117 | child: ElevatedButton(
118 | child: Text('Clear Log'),
119 | onPressed: () {
120 | FileManager.clearLogFile();
121 | setState(() {
122 | logStr = '';
123 | });
124 | },
125 | ),
126 | );
127 | String msgStatus = "-";
128 | if (isRunning != null) {
129 | if (isRunning) {
130 | msgStatus = 'Is running';
131 | } else {
132 | msgStatus = 'Is not running';
133 | }
134 | }
135 | final status = Text("Status: $msgStatus");
136 |
137 | final log = Text(
138 | logStr,
139 | );
140 |
141 | return MaterialApp(
142 | home: Scaffold(
143 | appBar: AppBar(
144 | title: const Text('Flutter background Locator'),
145 | ),
146 | body: Container(
147 | width: double.maxFinite,
148 | padding: const EdgeInsets.all(22),
149 | child: SingleChildScrollView(
150 | child: Column(
151 | crossAxisAlignment: CrossAxisAlignment.center,
152 | children: [start, stop, clear, status, log],
153 | ),
154 | ),
155 | ),
156 | ),
157 | );
158 | }
159 |
160 | void onStop() async {
161 | await BackgroundLocator.unRegisterLocationUpdate();
162 | final _isRunning = await BackgroundLocator.isServiceRunning();
163 | setState(() {
164 | isRunning = _isRunning;
165 | });
166 | }
167 |
168 | void _onStart() async {
169 | if (await _checkLocationPermission()) {
170 | await _startLocator();
171 | final _isRunning = await BackgroundLocator.isServiceRunning();
172 |
173 | setState(() {
174 | isRunning = _isRunning;
175 | lastLocation = null;
176 | });
177 | } else {
178 | // show error
179 | }
180 | }
181 |
182 | Future _checkLocationPermission() async {
183 | //final access = await LocationPermissions().checkPermissionStatus();
184 | final access = await Permission.location.status;
185 |
186 | if(access.isDenied || await Permission.location.isRestricted){
187 | final permission = await Permission.location.request();
188 | if(permission.isGranted){
189 | return true;
190 | }else{
191 | return false;
192 | }
193 | }else{
194 | return true;
195 | }
196 | }
197 |
198 | Future _startLocator() async{
199 | Map data = {'countInit': 1};
200 | return await BackgroundLocator.registerLocationUpdate(LocationCallbackHandler.callback,
201 | initCallback: LocationCallbackHandler.initCallback,
202 | initDataCallback: data,
203 | disposeCallback: LocationCallbackHandler.disposeCallback,
204 | iosSettings: IOSSettings(
205 | accuracy: LocationAccuracy.NAVIGATION,
206 | distanceFilter: 0,
207 | stopWithTerminate: true
208 | ),
209 | autoStop: false,
210 | androidSettings: AndroidSettings(
211 | accuracy: LocationAccuracy.NAVIGATION,
212 | interval: 5,
213 | distanceFilter: 0,
214 | client: LocationClient.google,
215 | androidNotificationSettings: AndroidNotificationSettings(
216 | notificationChannelName: 'Location tracking',
217 | notificationTitle: 'Start Location Tracking',
218 | notificationMsg: 'Track location in background',
219 | notificationBigMsg:
220 | '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.',
221 | notificationIconColor: Colors.grey,
222 | notificationTapCallback:
223 | LocationCallbackHandler.notificationCallback)));
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | #########################
2 | # .gitignore file for Xcode4 and Xcode5 Source projects
3 | #
4 | # Apple bugs, waiting for Apple to fix/respond:
5 | #
6 | # 15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation?
7 | #
8 | # Version 2.6
9 | # For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects
10 | #
11 | # 2015 updates:
12 | # - Fixed typo in "xccheckout" line - thanks to @lyck for pointing it out!
13 | # - Fixed the .idea optional ignore. Thanks to @hashier for pointing this out
14 | # - Finally added "xccheckout" to the ignore. Apple still refuses to answer support requests about this, but in practice it seems you should ignore it.
15 | # - minor tweaks from Jona and Coeur (slightly more precise xc* filtering/names)
16 | # 2014 updates:
17 | # - appended non-standard items DISABLED by default (uncomment if you use those tools)
18 | # - removed the edit that an SO.com moderator made without bothering to ask me
19 | # - researched CocoaPods .lock more carefully, thanks to Gokhan Celiker
20 | # 2013 updates:
21 | # - fixed the broken "save personal Schemes"
22 | # - added line-by-line explanations for EVERYTHING (some were missing)
23 | #
24 | # NB: if you are storing "built" products, this WILL NOT WORK,
25 | # and you should use a different .gitignore (or none at all)
26 | # This file is for SOURCE projects, where there are many extra
27 | # files that we want to exclude
28 | #
29 | #########################
30 |
31 | #####
32 | # OS X temporary files that should never be committed
33 | #
34 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html
35 |
36 | .DS_Store
37 |
38 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html
39 |
40 | .Trashes
41 |
42 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html
43 |
44 | *.swp
45 |
46 | #
47 | # *.lock - this is used and abused by many editors for many different things.
48 | # For the main ones I use (e.g. Eclipse), it should be excluded
49 | # from source-control, but YMMV.
50 | # (lock files are usually local-only file-synchronization on the local FS that should NOT go in git)
51 | # c.f. the "OPTIONAL" section at bottom though, for tool-specific variations!
52 | #
53 | # In particular, if you're using CocoaPods, you'll want to comment-out this line:
54 | #.lock
55 |
56 |
57 | #
58 | # profile - REMOVED temporarily (on double-checking, I can't find it in OS X docs?)
59 | #profile
60 |
61 |
62 | ####
63 | # Xcode temporary files that should never be committed
64 | #
65 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this...
66 |
67 | #*~.nib
68 |
69 |
70 | ####
71 | # Xcode build files -
72 | #
73 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData"
74 |
75 | DerivedData/
76 |
77 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build"
78 |
79 | build/
80 | Build/
81 | Index/
82 | Pods/
83 |
84 |
85 | #####
86 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups)
87 | #
88 | # This is complicated:
89 | #
90 | # SOMETIMES you need to put this file in version control.
91 | # Apple designed it poorly - if you use "custom executables", they are
92 | # saved in this file.
93 | # 99% of projects do NOT use those, so they do NOT want to version control this file.
94 | # ..but if you're in the 1%, comment out the line "*.pbxuser"
95 |
96 | # .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html
97 |
98 | *.pbxuser
99 |
100 | # .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html
101 |
102 | *.mode1v3
103 |
104 | # .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html
105 |
106 | *.mode2v3
107 |
108 | # .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file
109 |
110 | *.perspectivev3
111 |
112 | # NB: also, whitelist the default ones, some projects need to use these
113 | !default.pbxuser
114 | !default.mode1v3
115 | !default.mode2v3
116 | !default.perspectivev3
117 |
118 |
119 | ####
120 | # Xcode 4 - semi-personal settings
121 | #
122 | # Apple Shared data that Apple put in the wrong folder
123 | # c.f. http://stackoverflow.com/a/19260712/153422
124 | # FROM ANSWER: Apple says "don't ignore it"
125 | # FROM COMMENTS: Apple is wrong; Apple code is too buggy to trust; there are no known negative side-effects to ignoring Apple's unofficial advice and instead doing the thing that actively fixes bugs in Xcode
126 | # Up to you, but ... current advice: ignore it.
127 | *.xccheckout
128 |
129 | #
130 | #
131 | # OPTION 1: ---------------------------------
132 | # throw away ALL personal settings (including custom schemes!
133 | # - unless they are "shared")
134 | # As per build/ and DerivedData/, this ought to have a trailing slash
135 | #
136 | # NB: this is exclusive with OPTION 2 below
137 | xcuserdata/
138 |
139 | # OPTION 2: ---------------------------------
140 | # get rid of ALL personal settings, but KEEP SOME OF THEM
141 | # - NB: you must manually uncomment the bits you want to keep
142 | #
143 | # NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X,
144 | # or manually install git over the top of the OS X version
145 | # NB: this is exclusive with OPTION 1 above
146 | #
147 | #xcuserdata/**/*
148 |
149 | # (requires option 2 above): Personal Schemes
150 | #
151 | #!xcuserdata/**/xcschemes/*
152 |
153 | ####
154 | # XCode 4 workspaces - more detailed
155 | #
156 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :)
157 | #
158 | # Workspace layout is quite spammy. For reference:
159 | #
160 | # /(root)/
161 | # /(project-name).xcodeproj/
162 | # project.pbxproj
163 | # /project.xcworkspace/
164 | # contents.xcworkspacedata
165 | # /xcuserdata/
166 | # /(your name)/xcuserdatad/
167 | # UserInterfaceState.xcuserstate
168 | # /xcshareddata/
169 | # /xcschemes/
170 | # (shared scheme name).xcscheme
171 | # /xcuserdata/
172 | # /(your name)/xcuserdatad/
173 | # (private scheme).xcscheme
174 | # xcschememanagement.plist
175 | #
176 | #
177 |
178 | ####
179 | # Xcode 4 - Deprecated classes
180 | #
181 | # Allegedly, if you manually "deprecate" your classes, they get moved here.
182 | #
183 | # We're using source-control, so this is a "feature" that we do not want!
184 |
185 | *.moved-aside
186 |
187 | ####
188 | # OPTIONAL: Some well-known tools that people use side-by-side with Xcode / iOS development
189 | #
190 | # NB: I'd rather not include these here, but gitignore's design is weak and doesn't allow
191 | # modular gitignore: you have to put EVERYTHING in one file.
192 | #
193 | # COCOAPODS:
194 | #
195 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#what-is-a-podfilelock
196 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
197 | #
198 | #!Podfile.lock
199 | #
200 | # RUBY:
201 | #
202 | # c.f. http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
203 | #
204 | #!Gemfile.lock
205 | #
206 | # IDEA:
207 | #
208 | # c.f. https://www.jetbrains.com/objc/help/managing-projects-under-version-control.html?search=workspace.xml
209 | #
210 | #.idea/workspace.xml
211 | #
212 | # TEXTMATE:
213 | #
214 | # -- UNVERIFIED: c.f. http://stackoverflow.com/a/50283/153422
215 | #
216 | #tm_build_errors
217 |
218 | ####
219 | # UNKNOWN: recommended by others, but I can't discover what these files are
220 | #
221 | RekabNetwork
222 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/yukams/app/background_locator_2/PreferencesManager.kt:
--------------------------------------------------------------------------------
1 | package yukams.app.background_locator_2
2 |
3 | import android.content.Context
4 | import com.google.gson.Gson
5 | import com.google.gson.reflect.TypeToken
6 | import yukams.app.background_locator_2.provider.LocationClient
7 |
8 | class PreferencesManager {
9 | companion object {
10 | private const val PREF_NAME = "background_locator_2"
11 |
12 | @JvmStatic
13 | fun saveCallbackDispatcher(context: Context, map: Map) {
14 | val sharedPreferences =
15 | context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
16 |
17 | sharedPreferences.edit()
18 | .putLong(Keys.ARG_CALLBACK_DISPATCHER,
19 | map[Keys.ARG_CALLBACK_DISPATCHER] as Long)
20 | .apply()
21 | }
22 |
23 | @JvmStatic
24 | fun saveSettings(context: Context, map: Map) {
25 | val sharedPreferences =
26 | context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
27 |
28 | val callback = map[Keys.ARG_CALLBACK] as Number
29 | sharedPreferences.edit()
30 | .putLong(Keys.ARG_CALLBACK,
31 | callback.toLong())
32 | .apply()
33 |
34 | if (map[Keys.ARG_NOTIFICATION_CALLBACK] as? Long != null) {
35 | sharedPreferences.edit()
36 | .putLong(Keys.ARG_NOTIFICATION_CALLBACK,
37 | map[Keys.ARG_NOTIFICATION_CALLBACK] as Long)
38 | .apply()
39 | }
40 |
41 | val settings = map[Keys.ARG_SETTINGS] as Map<*, *>
42 |
43 | sharedPreferences.edit()
44 | .putString(Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME,
45 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME] as String)
46 | .apply()
47 |
48 | sharedPreferences.edit()
49 | .putString(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE,
50 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] as String)
51 | .apply()
52 |
53 | sharedPreferences.edit()
54 | .putString(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG,
55 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] as String)
56 | .apply()
57 |
58 | sharedPreferences.edit()
59 | .putString(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG,
60 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] as String)
61 | .apply()
62 |
63 | sharedPreferences.edit()
64 | .putString(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON,
65 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON] as String)
66 | .apply()
67 |
68 | sharedPreferences.edit()
69 | .putLong(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR,
70 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR] as Long)
71 | .apply()
72 |
73 | sharedPreferences.edit()
74 | .putInt(Keys.SETTINGS_INTERVAL,
75 | settings[Keys.SETTINGS_INTERVAL] as Int)
76 | .apply()
77 |
78 | sharedPreferences.edit()
79 | .putInt(Keys.SETTINGS_ACCURACY,
80 | settings[Keys.SETTINGS_ACCURACY] as Int)
81 | .apply()
82 |
83 | sharedPreferences.edit()
84 | .putFloat(Keys.SETTINGS_DISTANCE_FILTER,
85 | (settings[Keys.SETTINGS_DISTANCE_FILTER] as Double).toFloat())
86 | .apply()
87 |
88 | if (settings.containsKey(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME)) {
89 | sharedPreferences.edit()
90 | .putInt(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME,
91 | settings[Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME] as Int)
92 | .apply()
93 | }
94 |
95 | sharedPreferences.edit()
96 | .putInt(Keys.SETTINGS_ANDROID_LOCATION_CLIENT,
97 | settings[Keys.SETTINGS_ANDROID_LOCATION_CLIENT] as Int)
98 | .apply()
99 | }
100 |
101 | @JvmStatic
102 | fun getSettings(context: Context): Map {
103 | val sharedPreferences =
104 | context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
105 |
106 | val result = HashMap()
107 |
108 | result[Keys.ARG_CALLBACK_DISPATCHER] = sharedPreferences.getLong(Keys.ARG_CALLBACK_DISPATCHER, 0)
109 | result[Keys.ARG_CALLBACK] = sharedPreferences.getLong(Keys.ARG_CALLBACK, 0)
110 |
111 | if (sharedPreferences.contains(Keys.ARG_NOTIFICATION_CALLBACK)) {
112 | result[Keys.ARG_NOTIFICATION_CALLBACK] =
113 | sharedPreferences.getLong(Keys.ARG_NOTIFICATION_CALLBACK, 0)
114 | }
115 |
116 | val settings = HashMap()
117 |
118 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME] =
119 | sharedPreferences.getString(Keys.SETTINGS_ANDROID_NOTIFICATION_CHANNEL_NAME, "")
120 |
121 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE] =
122 | sharedPreferences.getString(Keys.SETTINGS_ANDROID_NOTIFICATION_TITLE, "")
123 |
124 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_MSG] =
125 | sharedPreferences.getString(Keys.SETTINGS_ANDROID_NOTIFICATION_MSG, "")
126 |
127 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG] =
128 | sharedPreferences.getString(Keys.SETTINGS_ANDROID_NOTIFICATION_BIG_MSG, "")
129 |
130 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON] =
131 | sharedPreferences.getString(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON, "")
132 |
133 | settings[Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR] =
134 | sharedPreferences.getLong(Keys.SETTINGS_ANDROID_NOTIFICATION_ICON_COLOR, 0)
135 |
136 | settings[Keys.SETTINGS_INTERVAL] =
137 | sharedPreferences.getInt(Keys.SETTINGS_INTERVAL, 0)
138 |
139 | settings[Keys.SETTINGS_ACCURACY] =
140 | sharedPreferences.getInt(Keys.SETTINGS_ACCURACY, 0)
141 |
142 | settings[Keys.SETTINGS_DISTANCE_FILTER] =
143 | sharedPreferences.getFloat(Keys.SETTINGS_DISTANCE_FILTER, 0f).toDouble()
144 |
145 | if (sharedPreferences.contains(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME)) {
146 | settings[Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME] = sharedPreferences.getInt(Keys.SETTINGS_ANDROID_WAKE_LOCK_TIME, 0)
147 | }
148 |
149 | settings[Keys.SETTINGS_ANDROID_LOCATION_CLIENT] =
150 | sharedPreferences.getInt(Keys.SETTINGS_ANDROID_LOCATION_CLIENT, 0)
151 |
152 | result[Keys.ARG_SETTINGS] = settings
153 | return result
154 | }
155 |
156 | @JvmStatic
157 | fun getLocationClient(context: Context): LocationClient {
158 | val sharedPreferences =
159 | context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
160 | val client = sharedPreferences.getInt(Keys.SETTINGS_ANDROID_LOCATION_CLIENT, 0)
161 | return LocationClient.fromInt(client) ?: LocationClient.Google
162 | }
163 |
164 | @JvmStatic
165 | fun setCallbackHandle(context: Context, key: String, handle: Long?) {
166 | if (handle == null) {
167 | context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
168 | .edit()
169 | .remove(key)
170 | .apply()
171 | return
172 | }
173 |
174 | context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
175 | .edit()
176 | .putLong(key, handle)
177 | .apply()
178 | }
179 |
180 | @JvmStatic
181 | fun setDataCallback(context: Context, key: String, data: Map<*, *>?) {
182 | if (data == null) {
183 | context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
184 | .edit()
185 | .remove(key)
186 | .apply()
187 | return
188 | }
189 | val dataStr = Gson().toJson(data)
190 | context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
191 | .edit()
192 | .putString(key, dataStr)
193 | .apply()
194 | }
195 |
196 | @JvmStatic
197 | fun getCallbackHandle(context: Context, key: String): Long? {
198 | val sharedPreferences = context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
199 | if (sharedPreferences.contains(key)) return sharedPreferences.getLong(key, 0L)
200 | return null
201 | }
202 |
203 | @JvmStatic
204 | fun getDataCallback(context: Context, key: String): Map<*, *> {
205 | val initialDataStr = context.getSharedPreferences(Keys.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
206 | .getString(key, null)
207 | val type = object : TypeToken