Skip to content
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

Own database question. #1374

Open
KlipX opened this issue Oct 31, 2024 · 9 comments
Open

Own database question. #1374

KlipX opened this issue Oct 31, 2024 · 9 comments

Comments

@KlipX
Copy link

KlipX commented Oct 31, 2024

Hi, I use your package and it is great. Thanks for your work.
I would like to ask about one thing. I need to synchronize location events with the server, but also save them locally.
You answered a similar question here

#1318 (comment)

Your answer:

You can’t. The plug-in desires an empty database. If you want the location in a database, it’s up to you to implement your own SQLite database.

So you indicated that it is possible to create your own database.

Can you tell me how it is possible, how I can listen to location events and save them in the background to my database? I thought about bg.BackgroundGeolocation.registerHeadlessTask but from what I understand it is only for Android. I would like it to work for ios and Android in the background. Will appreciate any tip and link to documentation 😄

@christocracy
Copy link
Member

how I can listen to location events and save them in the background to my database

  • for both iOS and Android, implement .onLocation to insert records into your own custom database.
  • For Android, also implement a headless-task for the terminated state.

I thought about bg.BackgroundGeolocation.registerHeadlessTask but from what I understand it is only for Android. I would like it to work for ios and Android in the background

The background state != the terminated state. Android headless-mode is for the terminated state, not background.

For iOS, you only need to implement .onLocation.

@KlipX
Copy link
Author

KlipX commented Oct 31, 2024

how I can listen to location events and save them in the background to my database

  • for both iOS and Android, implement .onLocation to insert records into your own custom database.
  • For Android, also implement a headless-task for the terminated state.

I thought about bg.BackgroundGeolocation.registerHeadlessTask but from what I understand it is only for Android. I would like it to work for ios and Android in the background

The background state != the terminated state. Android headless-mode is for the terminated state, not background.

For iOS, you only need to implement .onLocation.

Ok, so correct me if I'm wrong but I probably meant the terminal state. (The case when the user switches the application or locks the phone for a long time. (We track the user's walk)). Generally I needs to have the exact same locations events saved as your package.

So if the app is to track a user's walk, I have to assume that it collects locations even if the phone remains locked for a long time. In that case, the system may close the app, as far as I know, but your package still collects locations. In summary, I probably need the same location events as your package collects. Is it possible with your package?

Additional question:
Are listening on BackgroundGeolocation.onLocation in the background state and saving to storage for both ios and android enough? What are the chances that the system will move application to terminated state when it runs for such a long time in the background and receives a lot of location events which save to storage?

@christocracy
Copy link
Member

iOS and Android are fundamentally different in the terminated state.

Android

When an Android app is terminated, the OS allows services to continue running "headless". All events while your app is terminated are forwarded to your registered headless-task. To implement a custom database, you must do you INSERT in both your .onLocation listener in addition to your registered headless-task.

iOS

When an iOS app is terminated (either by user or OS), absolutely everything is stopped. There is nothing running. The only thing that will re-awaken a terminated iOS app is to move at least 200 meters, when the OS will automatically relaunch your app in the background, just as if launched from the home-screen icon. All locations will be delivered to your .onLocation event-listener as normal.

@KlipX
Copy link
Author

KlipX commented Oct 31, 2024

iOS and Android are fundamentally different in the terminated state.

Android

When an Android app is terminated, the OS allows services to continue running "headless". All events while your app is terminated are forwarded to your registered headless-task. To implement a custom database, you must do you INSERT in both your .onLocation listener in addition to your registered headless-task.

iOS

When an iOS app is terminated (either by user or OS), absolutely everything is stopped. There is nothing running. The only thing that will re-awaken a terminated iOS app is to move at least 200 meters, when the OS will automatically relaunch your app in the background, just as if launched from the home-screen icon. All locations will be delivered to your .onLocation event-listener as normal.

It's really helpful. It allows me to save all events in the database. I assumed that if headless-task is only for Android, then for iOS it is not possible to save the location in the terminal state in the database. But if I understand correct that for ios terminal state the application is started and .onLocation is called. So for ios, just save the .onLocation events to storage and it should work fine even in the terminal state.

Please confirm that I understand this correctly so that I can rest easy.

And once again thank you for your answers, they are really helpful

@christocracy
Copy link
Member

Like I said above:

All locations will be delivered to your .onLocation event-listener as normal.

@KlipX
Copy link
Author

KlipX commented Nov 4, 2024

Like I said above:

All locations will be delivered to your .onLocation event-listener as normal.

Today I implemented the solution on andorid and in terminal state I have the following problem. Maybe you know what the problem is?

I/TSLocationManager(26088):   ✅  INSERT: 61049729-91aa-4287-807e-ae54853d4752
I/FA      (26088): Application backgrounded at: timestamp_millis: 1730729324145
E/TSLocationManager(26088): [c.t.f.b.HeadlessTask$TaskRunner run] 
E/TSLocationManager(26088):   ‼️  Invalid Headless Callback ids.  Cannot handle headless event
import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;
import 'package:hive_flutter/hive_flutter.dart';
import 'package:pergato/app/app.dart';
import 'package:pergato/app/infrastructure/geolocation/storage/location_hive_dto.dart';
import 'package:pergato/app/infrastructure/geolocation/storage/location_storage.dart';
import 'package:pergato/app/infrastructure/geolocation/utils/mappers.dart';
import 'package:pergato/bootstrap.dart';
import 'package:pergato/config/environment/environments.dart';

/// Receive events from BackgroundGeolocation in Headless state.
@pragma('vm:entry-point')
void backgroundGeolocationHeadlessTask(bg.HeadlessEvent headlessEvent) async {
  if (headlessEvent.name == bg.Event.LOCATION) {
    final bg.Location location = headlessEvent.event as bg.Location;
    await Hive.initFlutter();
    await LocationStorage().save(
      LocationHiveDTO.fromDomain(
        location.customLocation,
      ),
    );
  }
}

void main() {
  bg.BackgroundGeolocation.registerHeadlessTask(backgroundGeolocationHeadlessTask);

  bootstrap(() => const App(), dev);
}

`

@christocracy
Copy link
Member

Maybe you have an error in that file.

@KlipX
Copy link
Author

KlipX commented Nov 4, 2024

Maybe you have an error in that file.
which file?

My config:

{
   "desiredAccuracy":-1,
   "distanceFilter":10.0,
   "disableElasticity":true,
   "isMoving":true,
   "activityRecognitionInterval":1000,
   "disableStopDetection":true,
   "stopOnStationary":false,
   "autoSync":false,
   "maxDaysToPersist":2,
   "authorization":{
      "strategy":"jwt",
      "accessToken":null,
      "refreshToken":null,
      "refreshUrl":null,
      "refreshPayload":null,
      "refreshHeaders":null,
      "expires":-1
   },
   "stopOnTerminate":false,
   "startOnBoot":true,
   "debug":true,
   "logLevel":5,
   "reset":false,
   "locationAuthorizationRequest":"Always",
   "disableLocationAuthorizationAlert":true,
   "activityType":4,
   "disableMotionActivityUpdates":false,
   "enableHeadless":true,
   "backgroundPermissionRationale":{
      "title":"xxxx",
      "message":"yyyyy",
      "positiveAction":null,
      "negativeAction":null
   },
   "notification":{
      "layout":null,
      "title":"xxxx.",
      "text":"yyyyy",
      "color":null,
      "channelName":null,
      "channelId":null,
      "smallIcon":"drawable/notification_icon",
      "largeIcon":null,
      "priority":1,
      "sticky":false,
      "strings":null,
      "actions":null
   }
}

@christocracy
Copy link
Member

I suggest you test in a simple hello-world app. Do nothing more in your headless-task but a simple print statement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants