Sync mobile device with server to run command at the same time across many mobile devices

315

To sync times you can use the toUtc method

Returns this DateTime value in the UTC time zone.

And then to start on it at the exact same time on all device use Timer

Creates a new timer. The callback function is invoked after the given duration.

Working example below:

import 'dart:core';

DateTime startTime = DateTime.utc(2021, 2, 16, 15, 0); // you feed the startTime from your server using websocket.

void checkForStart(Timer timer) {
  print(startTime);
  timer?.cancel();
  while (true) {
    print('Run Forest!');
    // [... do your app things]
  }
}

...

 initState() {
    super.initState();

    var current = DateTime.now().toUtc(); // this is what you want
    Duration difference = startTime.difference(current);
    timer = Timer(Duration(microseconds: difference.inMicroseconds), () => checkForStart(timer));
[...]

dispose() {
    timer?.cancel();
    super.dispose();
  }

output:

I/flutter ( 5819): 2021-02-16 15:00:00.000Z
I/flutter ( 5819): Run Forest!
I/chatty  ( 5819): uid=10154() 1.ui identical 65535 lines
I/flutter ( 5819): Run Forest!

This code will guarantee that the app starts at the same time for everybody as it will perform a check with timer and start it on local device at the same time that the startTime that you had fed to devices (NB: this is the foreground version, meaning everyone should have the app opened)

I have not detailed the websocket part because I assumed that you had no problem to implement it, if not you can take a look at this repository or different documentations, tutorials and stackOverflow answer. Please let me know if it helps.

Share:
315
zuboje
Author by

zuboje

Updated on December 27, 2022

Comments

  • zuboje
    zuboje 11 months

    I am building a real-time competing app for mobile devices for fitness equipment (over BLE). Mobile devices can receive a command from the server at different times due to latency. I am trying to achieve something where all devices are "synced up" with the server and execute the "start race" command at the same time. This way users that are not necessarily next to each other will get near real-time experience as much as possible and start competing at the near exact moment. At this moment I use WebSockets to publish commands to my mobile app but let's say device A will receive it within 20ms and device B will receive it within 150ms. As much as this is a blink of an eye, it is very much noticeable on the fitness equipment. How can I architecturally make an application that will for example execute the command on all devices at 1 PM UTC? The problem here is that mobile devices may have different time time so I want my mobile app to be in sync with server time and if I say execute command at 1 PM UTC server time, I know all mobile devices will achieve this.

    Current architecture:

    schedule or manually invoked command -> SignalR notifies all connected devices -> devices execute "start"

    Possible architecture:

    schedule or manually invoked command let devices know the exact time to run command -> SignalR (WebSockets or some other technology) notify connected device to sync mobile app time with server and command execution time -> Command is executed in near real-time across many devices

    How do I sync times? Using NTP? What do you suggest is the best architecture for this scenario?

    I've seen many apps similar to this but I am trying to understand the architecture. Technologies I think are irrelevant, I cannot control BLE execution times on fitness equipment but they are fast. If it helps I use SignalR for WebSockets (.NET Core 3.x in C#), the mobile app is running on Flutter/Dart.

  • zuboje
    zuboje over 2 years
    thanks for this answer. I have no problem with WebSockets or any other part of the app, it is all in working condition, I am just trying to "sync" devices to execute commands at the same time (or near the same time since Android hardware could be super fast or cheap and slower). The app does have to run in the foreground regardless because running in the background disables WebSockets at some point (iOS quicker than Android), this is by the OS design. While Android has some flexibility, iOS is very strict and it kills them at some point if the app is in the background for too