QtDataSync
4.2.0
A simple offline-first synchronisation framework, to synchronize data of Qt applications between devices
|
A Guide for adding background synchronization to mobile applications
This page consists of two guides, one for android and one for iOs, to add background synchronization to an application. There are multiple steps required that differ for each platform and those are discussed here.
For Android, you will have to add an additional service to your application that is to be run in the background, independently from your main application, to perform the sync. This library already supports all the elements needed to do so, but you still need to setup the project yourself.
You can find a working example of this tutorial in the repository. Check out the AndroidSync Sample.
First create any normal project in QtCreator. Select an android kit to build it and then go to "Projects > Build > Build Android APK" and under "Android" press "Create Templates". This should bring up a dialog to add android files to your project. Follow that wizard to add the files. Your pro file should now contain ANDROID_PACKAGE_SOURCE_DIR
.
Next you have to add the correct Qt modules. These are: QT += datasyncandroid
. Build and run your project. It should still function normally
The next step is to add the actual service to your project that performs the sync. This is done in 3 steps:
Add a new C++ class to the project and let it inherit from QtDataSync::AndroidBackgroundService. Adjust the constructor to match the one of the parent class (beware the reference) and implement any methods you need to. The only required method to be implemented is QtDataSync::AndroidBackgroundService::createForegroundNotification. An example would be:
And the corresponding implementation:
After creating the sync service class, you need to add code to your main to differentiate between whether the application is started normally or as a service.
The general idea is to split your main into 3 functions. One named activityMain
which does the stuff you did before, i.e. create a gui, an serviceMain
that launces the service and the actual main
that now only decides which of the other two to call based on the start parameters.
The serviceMain
should simply instanciate and execute the service from the given parameters:
The actual main
has to scan the passed arguments for the --backend
argument. If found, the serviceMain
should be run, otherwise the activityMain
:
Again, the activityMain
as basically what was previously the normal main
, just moved out into a different function.
After the C++ code is now ready, the final step is to update the AndroidManifest.xml. We need to add a few elements to register all components and permissions that are needed to actually run the service.
Now that the service was created and is startable if the correct command line arguments are specified, we have to add it to the manifest to make it known to the android system so it can actually be started. The <service>
should be placed next to the <activity>
element in the manifest, as a child of the root <application>
element. The following shows an example for such a service definition:
Most of the service was just copied from the <activity>
element. The attributes and elements that are different from the activity and thus must be changed after copying it over are:
android:process=":service_process"
- Makes shure the service runs in a seperate processandroid:name="de.skycoder42.qtservice.AndroidService"
- Specify the java class to be used<meta-data android:name="android.app.arguments" android:value="--backend android"/>
- Pass the arguments to the main
<meta-data android:name="android.app.background_running" android:value="true"/>
- Allow background executionNow that the service has been added, we need one more component to be added to the manifest. This is the boot receiver, which is started by android after a reboot and is needed to reactive your service after a boot. The class is ready to use, so you only need to add the following to the manifest, right after the <service>
element (still inside the <application>
element):
The last thing to add to the manifest are additional permissions. We need permissions to start a foreground service (which is exactly what we are doing) and allow the app to receive a signal when the system was rebooted, which is needed to reactive the service after a reboot. Simply add the following elements after the %INSERT_PERMISSIONS
comment
With all the previous steps the service is fully prepared to be used. All thats left to do is to actually use it by enabeling background synchronization. You can do this with the QtDataSync::AndroidSyncControl class. In the example, it is used from QML you you can play around with the possibilities, but for the sake of this guide, the simplest way is to just statically enable it from your activityMain
:
With that the preperations are done and ready to test. Compile and run your application and check if you can find control.enabled true
in the log. You can also run
to check if the alarm was correctly registered and when synchronization is triggered the next time. Wait for the timeout to arrive and see if the service executes correctly (i.e. without crashing). You can consult the logs via
to check the output of the service. You should find a message like:
If thats the case, the service works correctly, and you can extend it as you please.
For Ios, adding background sync requires the registration of a custom delegate that can start the synchronization as part of a background fetch operation. This is done as part of your main application and will run on the main thread - however only when the application is suspended in the background and no gui is currently shown.
You can find a working example of this tutorial in the repository. Check out the IosSync Sample.
First create any normal project in QtCreator and make shure you select ios or ios simulator as the kit. Next you have to add the correct Qt modules. These are: QT += datasyncios
. Build and run your project. It should still function normally
All you need to do to use this feature is to add a delegate. A default implemented delegate is already part of this library and can be used as is. However, if you want to do something with the new data after it was synchronized, you have to extend the delegate and add custom code.
If thats not relevant for your project, you can skip the next section and immediatly go to Initialize and enable the delegate
If you want to perform custom operations and synchronized data, you have to extend the QtDataSync::IosSyncDelegate. While there are multiple things you can customize, the only relevant method that needs to be reimplemented is QtDataSync::IosSyncDelegate::onSyncCompleted. An example for a custom delegate would be:
And the corresponding implementation:
Once you have your delegate ready (either by using a custom or the default one), the last step in C++ is to register it. This is done via the QtDataSync::IosSyncDelegate::init method from withing the main function:
With that the delegate is automatically registerd and enabled in the system on every start of your application.
The last thing that needs to be done is to declare that your application will use background fetch for the synchronization in the Info.plist file. If you do not already have such a file, simply copy it from your Qt installation. The path where you can find it is currently <path_to_qt_version>/ios/mkspecs/macx-ios-clang/Info.plist.app
.
There is only a single key-value pair that you need to add to the root <dict>
element at the very bottom:
A full example for the final Info.plist would be:
Testing this on ios is rather complicated, which is why I won't document this here. A helpful articel I found that explains how to test background fetching is linked below:
https://medium.com/livefront/how-to-debug-background-fetch-events-on-ios-29540b043adf