-
Notifications
You must be signed in to change notification settings - Fork 321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue on Android: Not capture when app is closed, but shows notification #30
Comments
Look like your callback isn't static, try to create a static function like |
Sorry my bad, it is static... i just copy and paste it here on same code of static void callback(LocationDto locationDto) async {
print('location in dart: ${locationDto.toString()}');
final SendPort send = IsolateNameServer.lookupPortByName(_isolateName);
send?.send(locationDto);
} Looking at topic 3 on Android item on documentation: 3. If you need to call other plugins, even when the application is terminated, create the Application.kt file and add the necessary plugins to the registerWith function. I'm calling calling a function in another file, not in same file, and using shared prefs to store locations, and it has other plugins that i need. In that case i need to register all imported plugins on `Application.kt? Look at imports: lib/main.dart port.listen(
(dynamic data) async {
// await updateUI(data);
await locationBackground.updateHomeTime(data);
},
); lib/uteis/locator.dart import 'dart:async';
import 'dart:isolate';
import 'dart:ui';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:geodesy/geodesy.dart';
import 'package:background_locator/location_dto.dart';
import 'package:geohash/geohash.dart';
import 'package:geoflutterfire/geoflutterfire.dart';
import './constants.dart';
import './location_model.dart';
import './uteis.dart';
class Locator{
Uteis uteis = new Uteis();
ReceivePort port = ReceivePort();
static final _isolateName = 'LocatorIsolate';
bool isRunning = true;
static void callback(LocationDto locationDto) async {
print('location in dart: ${locationDto.toString()}');
final SendPort send = IsolateNameServer.lookupPortByName(_isolateName);
send?.send(locationDto);
}
static void notificationCallback() {
print('Background Location notificationCallback');
}
// Here is when i save the loction in shared prefs
Future<void> updateHomeTime(LocationDto data) async {
DateTime now = DateTime.now();
List<LocationModel> locations = await uteis.getLocations();
locations.add(LocationModel.fromGelocation(userPoint['email'], now, data));
await uteis.storeLocations(locations);
// TODO: Persist these locations on shared prefs to firebase firestore
} I am storing locations on shared prefs to send then to firebase firestore later... |
Basically you have two part on your app, Flutter and the plugins's service On topic 3 like you said you need to import the plugin you want to use inside the kotlin file (its path_provider on the example) so this way you can use this plugin inside the callback (Basically when you download through Take a look here #27 you will maybe better understand (also check the example) |
in Android I want to send location and another data (eg.SharedPreferences data , battery_level) to my server in background process. It works well in port.listen function. When I kill process port.listen not working but callback still work. I move code from port.listen function to callback function. There was some problem . Can I pass some parameter to callback function or you have any idea for my situation? |
I think you don't have imported the kotlin part of the two plugins so you get NotImplementedError |
is there any way to stop the callback when the application is killed? |
Then you can set |
@RomanJos According to the ReadMe > [autoStop] If true locator will stop as soon as app goes to background. I have set [autoStop] to true, but once my application goes to background (without killing it), the callback stop and the notification disappear. |
Oh my bad I read too fast lol I think that you can achieve this by following this post https://medium.com/pharos-production/flutter-app-lifecycle-4b0ab4a4211a basically when the app is paused you stop the locator service and re-start it when the app get resumed |
Finally, I found a workaround. I think many users of this plugin looking for this use case. I achieved that by editing the 2 services from background_locator in my androidManifest.xml:
|
This is actually really clever, I don't know how android's manifest work actually I will add it in the readme |
I think I have to take more time reading the issue, I don't know why I came up with lifecycle lol anyway |
Hi, make the package br.com.myapp
import rekab.app.background_locator.LocatorService
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.pathprovider.PathProviderPlugin
class Application : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
LocatorService.setPluginRegistrant(this)
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
PathProviderPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.pathprovider"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin")) {
CloudFirestorePlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.firebaseauth.FirebaseAuthPlugin'")) {
FirebaseAuthPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebaseauth.FirebaseAuthPlugin'"))
}
if (!registry!!.hasPlugin("com.baseflow.location_permissions.LocationPermissionsPlugin'")) {
LocationPermissionsPlugin.registerWith(registry!!.registrarFor("com.baseflow.location_permissions.LocationPermissionsPlugin'"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.sharedpreferences'")) {
SharedPreferencesPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.sharedpreferences'"))
}
}
} There are a couple of plugins that are installed and i use them on app but are not registered in
Is this a proble? |
If they are not in |
Ok, understand. Making a build now, with
My kotlin version in So i change the kotlin file using the fixes you post in PR #27 but the error persist. See below the package br.com.myapp
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.pathprovider.PathProviderPlugin
import io.flutter.view.FlutterMain
import rekab.app.background_locator.LocatorService
class LocationService : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
LocatorService.setPluginRegistrant(this)
FlutterMain.startInitialization(this)
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
PathProviderPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.pathprovider"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin")) {
CloudFirestorePlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.firebaseauth.FirebaseAuthPlugin'")) {
FirebaseAuthPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebaseauth.FirebaseAuthPlugin'"))
}
if (!registry!!.hasPlugin("com.baseflow.location_permissions.LocationPermissionsPlugin'")) {
LocationPermissionsPlugin.registerWith(registry!!.registrarFor("com.baseflow.location_permissions.LocationPermissionsPlugin'"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.sharedpreferences'")) {
SharedPreferencesPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.sharedpreferences'"))
}
}
} See the registered plugins on |
You can't do import io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin
import io.flutter.plugins.firebaseauth.FirebaseAuthPlugin
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin I don't think its a good idea to have permisison handler checking every callback but rather before launching the plugin |
I just have to ask, do you have this plugins in your |
It's imported on my
OK, understand... It makes perfect sense, since the permission should have been resolved when you first started the app. Will remove this plugin,
My challenge is to make it work when user closes the app, so i need to persist data to firestore and if there is no internet connection, store it in shared prefs first. |
Yeah exactly you need to import them in your kotlin files before calling their if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
PathProviderPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.pathprovider"))
} Here we check if registry (that shouldn't be null) don't have the plugin "io.flutter.plugins.pathprovider" to register it but why do we check it and don't just register it ? |
Man, my bad... i think i understand it now... Below my last try... every plugin, has a commented line showing how it is listed on package br.com.myapp
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.pathprovider.PathProviderPlugin
import io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin
import io.flutter.plugins.firebaseauth.FirebaseAuthPlugin
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin
import io.flutter.view.FlutterMain
import rekab.app.background_locator.LocatorService
class LocationService : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
LocatorService.setPluginRegistrant(this)
FlutterMain.startInitialization(this)
}
override fun registerWith(registry: PluginRegistry?) {
// flutterEngine.getPlugins().add(new io.flutter.plugins.pathprovider.PathProviderPlugin());
if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
PathProviderPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.pathprovider"))
}
// io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin"));
if (!registry!!.hasPlugin("io.flutter.plugins.firebase.cloudfirestore")) {
CloudFirestorePlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebase.cloudfirestore"))
}
// io.flutter.plugins.firebaseauth.FirebaseAuthPlugin.registerWith(shimPluginRegistry.registrarFor("io.flutter.plugins.firebaseauth.FirebaseAuthPlugin"));
if (!registry!!.hasPlugin("io.flutter.plugins.firebaseauth")) {
FirebaseAuthPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebaseauth"))
}
// flutterEngine.getPlugins().add(new io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin());
if (!registry!!.hasPlugin("io.flutter.plugins.sharedpreferences")) {
SharedPreferencesPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.sharedpreferences"))
}
}
}
|
Oh yeah but I forgot to tell that my last two question wasn't specifically for you I mean I didn't do this part of the readme and I don't know nothing about kotlin lol but if its working now thats perfect then |
Ok. Understand. Well. Make a release now. App crash when start at first time. |
Oh, I though it worked :( then I don't know, I tried myself with your example #30 (comment) with adding the tree import I said after and it didn't crashed on start |
Nope. don't working. App crash when start. See below: Removed all plugins, and copy and paste documentation example. Just change the app package: package br.com.myapp
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.pathprovider.PathProviderPlugin
import io.flutter.view.FlutterMain
import rekab.app.background_locator.LocatorService
class LocationService : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
LocatorService.setPluginRegistrant(this)
FlutterMain.startInitialization(this)
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
PathProviderPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.pathprovider"))
}
}
}
<application
android:name="br.com.myapp"
android:label="My App"
android:icon="@mipmap/ic_launcher"> But when i remove the |
Ohh you forgot to add |
Yeah, right! Changed now. App builds and run without conflict. What i expect: Store locations to shared preferences with 6 minutes interval, whether the application is open or closed. After store in shared prefs, is internet is available; persist them to firestore too Below a report about what is working and what's not:
In short. Is working as before. When app is opened it works. but not when closes app. When open app, works fine again and capture every 6 minutes. android/app/src/main/kotlink/br.copm/myapp/LocationService.kt package br.com.myapp
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback
import io.flutter.plugins.pathprovider.PathProviderPlugin
import io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin
import io.flutter.plugins.firebaseauth.FirebaseAuthPlugin
import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin
import io.flutter.view.FlutterMain
import rekab.app.background_locator.LocatorService
class LocationService : FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate()
LocatorService.setPluginRegistrant(this)
FlutterMain.startInitialization(this)
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.pathprovider")) {
PathProviderPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.pathprovider"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.firebase.cloudfirestore")) {
CloudFirestorePlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebase.cloudfirestore"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.firebaseauth")) {
FirebaseAuthPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebaseauth"))
}
if (!registry!!.hasPlugin("io.flutter.plugins.sharedpreferences")) {
SharedPreferencesPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.sharedpreferences"))
}
}
} android/app/src/main/AndroidManifest.xml <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="br.com.myapp">
<!-- App permissions -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Background Locator permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="br.com.myapp.LocationService"
android:label="My App"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Facebook Login configuration -->
<meta-data android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id"/>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges=
"keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
<!-- Background Locator configuration -->
<receiver
android:name="rekab.app.background_locator.LocatorBroadcastReceiver"
android:enabled="true"
android:exported="true"
/>
<service
android:name="rekab.app.background_locator.LocatorService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"
/>
<service
android:name="rekab.app.background_locator.IsolateHolderService"
android:permission="android.permission.FOREGROUND_SERVICE"
android:exported="true"
/>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest> BackgroundLocator.registerLocationUpdate(
LocationBackground.callback,
androidNotificationCallback: LocationBackground.notificationCallback,
settings: LocationSettings(
notificationTitle: "My App",
notificationMsg: "My Notification text",
wakeLockTime: 20,
autoStop: false,
interval: 360, // 6 minutes
),
);
static void callback(LocationDto locationDto) async {
print('location in dart: ${locationDto.toString()}');
final SendPort send = IsolateNameServer.lookupPortByName(_isolateName);
send?.send(locationDto);
}
static void notificationCallback() {
print('Background Location notificationCallback');
} |
You need to put every background operation like writing in a file, send to internet the location etc inside the |
Hello, Now i understand! It works here. It works in a 6 minutes interval, exactly as i configured. The unique issue is when it works with opened app, store both; from UI and from Background and i need just one! Can i disable the ports right? Just remove port variable declaration and port.listen? Is there more lines to remove? // ReceivePort port = ReceivePort();
bool isRunning = true;
static final _isolateName = 'LocatorIsolate';
@override
void initState() {
super.initState();
if (IsolateNameServer.lookupPortByName(_isolateName) != null) {
IsolateNameServer.removePortNameMapping(_isolateName);
}
/*
IsolateNameServer.registerPortWithName(port.sendPort, _isolateName);
port.listen(
(dynamic data) async {
await LocationBackground.updateHomeTime(data);
},
onError: (err) {
print("Error log in dart: $err");
},
cancelOnError: false,
);
*/
initPlatformState();
}
Future<void> initPlatformState() async {
await BackgroundLocator.initialize();
final _isRunning = await BackgroundLocator.isRegisterLocationUpdate();
setState(() {
isRunning = _isRunning;
});
}
static void callback(LocationDto locationDto) async {
print('location in dart: ${locationDto.toString()}');
await updateHomeTime(locationDto); // My Function
// final SendPort send = IsolateNameServer.lookupPortByName(_isolateName);
// send?.send(locationDto);
} |
If you don't need UI update then remove the port. There should be no problem. I'm closing this issue Because I think it's more like stackoverflow question. Feel free to open it. |
Yeah if (IsolateNameServer.lookupPortByName(_isolateName) != null) {
IsolateNameServer.removePortNameMapping(_isolateName);
}
I don't think Stackoverflow is used for Flutter libraries lol |
) Fix memory leak bug (rekabhq#27)
Hello.
Testing in Android, plugin works fine, but have an issue: When close app, the notification baloon still shows on device; but stop capturing. There is some extra config to do when close app ?
Settings:
The text was updated successfully, but these errors were encountered: