Skip to content
This repository was archived by the owner on Mar 4, 2023. It is now read-only.

Commit ba8a364

Browse files
committed
added ios sync module doc
1 parent 0dcbb05 commit ba8a364

File tree

9 files changed

+324
-12
lines changed

9 files changed

+324
-12
lines changed

doc/androidbackgroundservice.dox

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/*!
22
@class QtDataSync::AndroidBackgroundService
33

4-
This service can be used as Android service to create a background synchronizations service
5-
without much effort. However, a few additional setup steps are needed. This class only extends
6-
the QtService implementation of an android service to add the synchronization aspect.
4+
This service is part of the `QtDataSyncAndroid` module and can be used as Android service to
5+
create a background synchronizations service without much effort. However, a few additional setup
6+
steps are needed. This class only extends the QtService implementation of an android service to
7+
add the synchronization aspect.
78

89
@warning This class alone is **not** sufficient to make synchronization possible. Have a look at
910
the @ref qtdatasync_sync_guide_android to learn how to add background synchronization to your project.

doc/androidsynccontrol.dox

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ interval.
6666
@notifyAc{intervalChanged()}
6767
}
6868

69-
@sa AndroidSyncControl::serviceId
70-
*/
71-
7269
@sa AndroidSyncControl::valid, AndroidSyncControl::enabled
7370
*/
7471

doc/backsync.dox

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ used by the service from your activity (java code below):
137137

138138
@snippet android/src/de/skycoder42/qtdatasync/sample/androidsync/SvcHelper.java java_create_channel
139139

140-
@subsection qtdatasync_sync_guide_android_test Testing the setup
140+
@subsection qtdatasync_sync_guide_android_test Test the setup
141141
With that the preperations are done and ready to test. Compile and run your application and
142142
check if you can find `control.enabled true` in the log. You can also run
143143
@code
@@ -155,4 +155,80 @@ to check the output of the service. You should find a message like:
155155
@endcode
156156

157157
If thats the case, the service works correctly, and you can extend it as you please.
158+
159+
@section qtdatasync_sync_guide_ios Ios Background synchronization
160+
For Ios, adding background sync requires the registration of a custom delegate that can start
161+
the synchronization as part of a background fetch operation. This is done as part of your main
162+
application and will run on the main thread - however only when the application is suspended in
163+
the background and no gui is currently shown.
164+
165+
You can find a working example of this tutorial in the repository. Check out the
166+
[IosSync Sample](https://github.com/Skycoder42/QtDataSync/tree/master/examples/datasync/IosSync).
167+
168+
@attention Background fetch on Ios is badly implemented (by apple). You get no guarantee at all
169+
that your task will ever be run - if your unlucky, background synchronization will never happen.
170+
And since the logic behind that is proprietary apple stuff, there is nothing that can be done to
171+
improve the situation. Do not rely on this working for every user, as I can guarantee you it
172+
wont.
173+
174+
@subsection qtdatasync_sync_guide_ios_base Prepare the project
175+
@note For this section it is assumed you are using QtCreator and a qmake based project.
176+
For anything else you will have to figure out yourself how to do steps equivalent
177+
to these for your build system.
178+
179+
First create any normal project in QtCreator and make shure you select ios or ios simulator as
180+
the kit. Next you have to add the correct Qt modules. These are: `QT += datasyncios`.
181+
Build and run your project. It should still function normally
182+
183+
@subsection qtdatasync_sync_guide_ios_cpp Add the delegate to the project
184+
All you need to do to use this feature is to add a delegate. A default implemented delegate is
185+
already part of this library and can be used as is. However, if you want to do something with
186+
the new data after it was synchronized, you have to extend the delegate and add custom code.
187+
188+
If thats not relevant for your project, you can skip the next section and immediatly go to
189+
@ref qtdatasync_sync_guide_ios_cpp_main
190+
191+
@subsubsection qtdatasync_sync_guide_ios_cpp_delegate Extend the delegate (optional)
192+
If you want to perform custom operations and synchronized data, you have to extend the
193+
QtDataSync::IosSyncDelegate. While there are multiple things you can customize, the only relevant
194+
method that needs to be reimplemented is QtDataSync::IosSyncDelegate::onSyncCompleted. An example
195+
for a custom delegate would be:
196+
197+
@snippet syncdelegate.h delegate_hdr
198+
199+
And the corresponding implementation:
200+
201+
@snippet syncdelegate.cpp delegate_src
202+
203+
@subsubsection qtdatasync_sync_guide_ios_cpp_main Initialize and enable the delegate
204+
Once you have your delegate ready (either by using a custom or the default one), the last step
205+
in C++ is to register it. This is done via the QtDataSync::IosSyncDelegate::init method from
206+
withing the main function:
207+
208+
@snippet IosSync/main.cpp delegate_main
209+
210+
With that the delegate is automatically registerd and enabled in the system on every start of
211+
your application.
212+
213+
@subsection qtdatasync_sync_guide_ios_plist Add the Info.plist
214+
The last thing that needs to be done is to declare that your application will use background
215+
fetch for the synchronization in the Info.plist file. If you do not already have such a file,
216+
simply copy it from your Qt installation. The path where you can find it is currently
217+
`<path_to_qt_version>/ios/mkspecs/macx-ios-clang/Info.plist.app`.
218+
219+
There is only a single key-value pair that you need to add to the root `<dict>` element at
220+
the very bottom:
221+
222+
@snippet Info.plist plist_info_fetch
223+
224+
A full example for the final Info.plist would be:
225+
226+
@include Info.plist
227+
228+
@subsection qtdatasync_sync_guide_ios_test Test the setup
229+
Testing this on ios is rather complicated, which is why I won't document this here. A helpful
230+
articel I found that explains how to test background fetching is linked below:
231+
232+
https://medium.com/livefront/how-to-debug-background-fetch-events-on-ios-29540b043adf
233+
158234
*/

doc/iossyncdelegate.dox

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*!
2+
@class QtDataSync::IosSyncDelegate
3+
4+
This class is part of the `QtDataSyncIos` module, which is only available on the ios platform.
5+
It can be used to configure and run background synchronization so that your application is able
6+
to update it's internal data periodically in the background, even if your app is not actively
7+
used.
8+
9+
@warning This class alone is **not** sufficient to make this possible. You will also have to
10+
correctly set up the Info.plist and other things. Have a look at the
11+
@ref qtdatasync_sync_guide_ios to learn how to add background synchronization to your project.
12+
13+
@sa @ref qtdatasync_sync_guide_ios, AndroidSyncControl, AndroidBackgroundService
14+
*/
15+
16+
/*!
17+
@property QtDataSync::IosSyncDelegate::interval
18+
19+
@default{`60` (minutes)}
20+
21+
This value is passed to the operating system to schedule the background synchronization. There
22+
is no guarantee of exact delivery of those background synchronizations. For ios, this is only
23+
a minimal wait time, i.e. it is guaranteed that the synchronization will not be started before
24+
that time has passed.
25+
26+
@note Due to the stupidity of Ios, this means sometimes the system won't even run the sync task
27+
in days, even though you specify an interval of an hour or less. There is nothing that can be
28+
done here, as you are fully at the mercy of apples proprietary optimization logic.
29+
30+
@accessors{
31+
@readAc{interval()}
32+
@readAc{intervalMinutes()}
33+
@writeAc{setInterval()}
34+
@notifyAc{intervalChanged()}
35+
}
36+
37+
@note if persistState is enabled, this property is persisted
38+
39+
@sa IosSyncDelegate::enabled, IosSyncDelegate::persistState
40+
*/
41+
42+
/*!
43+
@property QtDataSync::IosSyncDelegate::enabled
44+
45+
@default{`false`}
46+
47+
These property directly communicates with the OS and schedules (or unschedules) the task to run
48+
the sync task. This means you must always set the interval first before enabling a task.
49+
50+
@accessors{
51+
@readAc{isEnabled()}
52+
@writeAc{setEnabled()}
53+
@notifyAc{enabledChanged()}
54+
}
55+
56+
@note if persistState is enabled, this property is persisted
57+
58+
@sa IosSyncDelegate::interval, IosSyncDelegate::persistState
59+
*/
60+
61+
/*!
62+
@property QtDataSync::IosSyncDelegate::waitFullSync
63+
64+
@default{`true`}
65+
66+
If set to true, the delegate will internally call SyncManager::runOnSynchronized() with the
67+
onSyncCompleted() as handler. If disable, SyncManager::runOnDownloaded() is used instead. Check
68+
the documentation of these two methods.
69+
70+
@accessors{
71+
@readAc{waitFullSync()}
72+
@writeAc{setWaitFullSync()}
73+
@notifyAc{waitFullSyncChanged()}
74+
}
75+
76+
@note if persistState is enabled, this property is persisted
77+
78+
@sa IosSyncDelegate::onSyncCompleted, SyncManager::runOnSynchronized,
79+
SyncManager::runOnDownloaded, IosSyncDelegate::persistState
80+
*/
81+
82+
/*!
83+
@property QtDataSync::IosSyncDelegate::persistState
84+
85+
@default{`true`}
86+
87+
If set to true, the delegate will store it's current state whenver the interval or the enabled
88+
properties are changed. The that will be automatically reloaded when passed to init().
89+
90+
For the default implementation of the delegate, persistance is always enabled. You can override
91+
this method in a custom class to deactivate it.
92+
93+
Properties that are stored are:
94+
95+
- IosSyncDelegate::enabled
96+
- IosSyncDelegate::interval
97+
- IosSyncDelegate::waitFullSync
98+
99+
@accessors{
100+
@readAc{persistState()}
101+
@constantAc
102+
}
103+
104+
@sa IosSyncDelegate::init, IosSyncDelegate::enabled, IosSyncDelegate::interval,
105+
IosSyncDelegate::waitFullSync
106+
*/
107+
108+
/*!
109+
@fn QtDataSync::IosSyncDelegate::init
110+
111+
@param delegate The delegate to be set as sync delegate
112+
113+
You must call this method after creating the core app (but before executing it) to register a
114+
delegate as "active" delegate. This delegate will then control whether sync is enabled and handle
115+
the sync requests if your application is in the background.
116+
117+
@note If persistState is true (the default), the init method will also restore the previously
118+
persisted state
119+
120+
@sa IosSyncDelegate::persistState, IosSyncDelegate::currentDelegate
121+
*/
122+
123+
/*!
124+
@fn QtDataSync::IosSyncDelegate::currentDelegate
125+
126+
@returns The delegate currently set via init() or `nullptr`, if no delegate was set
127+
128+
@sa IosSyncDelegate::init
129+
*/
130+
131+
/*!
132+
@fn QtDataSync::IosSyncDelegate::setupName
133+
134+
@returns The name of the setup
135+
136+
The default implementation returns `QtDataSync::DefaultSetup`. You can override the method if you
137+
need the delegate to create the setup under a different name.
138+
139+
@sa QtDataSync::DefaultSetup, IosSyncDelegate::prepareSetup
140+
*/
141+
142+
/*!
143+
@fn QtDataSync::IosSyncDelegate::prepareSetup
144+
145+
@param setup The setup to be prepared
146+
147+
You should override this method to configure the setup before creation (i.e. set properties on
148+
it). The default implementation does nothing.
149+
150+
@sa QtDataSync::Setup, IosSyncDelegate::setupName
151+
*/
152+
153+
/*!
154+
@fn QtDataSync::IosSyncDelegate::onSyncCompleted
155+
156+
@param state The state in which the synchronization finished
157+
@returns A sync result to tell the operating system how the synchronization finished
158+
159+
This method is called as soon as the datasync instance has finished the data synchronization. You
160+
can override it to perform additional operations with the data before quitting the service.
161+
162+
The default implementation only returns a sync result based on the sync state. You must
163+
do the same in your implementation. If you do not want to return synchronously, you must override
164+
the performSync() method instead.
165+
166+
Possible states that are typically passed to the method can be:
167+
- Uploading (only if waitFullSync is set to false)
168+
- Synchronized
169+
- Error
170+
- Disconnected
171+
172+
The default return value mapping is this method does is:
173+
174+
SyncState | SyncResult
175+
----------------|------------
176+
Downloading | NewData
177+
Uploading | NewData
178+
Synchronized | NewData
179+
Disconnected | NoData
180+
Error | Error
181+
182+
@sa IosSyncDelegate::waitFullSync, IosSyncDelegate::performSync
183+
*/
184+
185+
/*!
186+
@fn QtDataSync::IosSyncDelegate::performSync
187+
188+
@param callback A callback to be called with the sync result once the sync is done
189+
190+
This method is called by the operating system and contains the actual code to synchronize the
191+
data. If you want to reimplement this method, you should always call the base implementation
192+
as well to make shure synchronization works as expected.
193+
194+
In case you want to override this method to allow asynchronous sync result handling, you can use
195+
the following pattern. Simpyl impelement onSyncCompleted() as usual, but always return NewData
196+
(ignored). Instead add a signal with the SyncResult as parameter and emit this once the async
197+
sync operation has finished. Now implement this method and call the base implementation as usual,
198+
but pass an empty, self constructed callback to it that does nothing. Instead connect the actual
199+
callback to the previously declared signal (before calling the base impl.)
200+
201+
@sa IosSyncDelegate::onSyncCompleted
202+
*/

examples/datasync/IosSync/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@
3737
<string>UIInterfaceOrientationLandscapeLeft</string>
3838
<string>UIInterfaceOrientationLandscapeRight</string>
3939
</array>
40+
<!--! [plist_info_fetch] -->
4041
<key>UIBackgroundModes</key>
4142
<array>
4243
<string>fetch</string>
4344
</array>
45+
<!--! [plist_info_fetch] -->
4446
</dict>
4547
</plist>

examples/datasync/IosSync/main.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22
#include <QQmlApplicationEngine>
33
#include "syncdelegate.h"
44

5+
//! [delegate_main]
56
int main(int argc, char *argv[])
67
{
78
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
8-
99
QGuiApplication app(argc, argv);
1010

1111
QtDataSync::IosSyncDelegate::init(new SyncDelegate{&app});
12+
QtDataSync::IosSyncDelegate::currentDelegate()->setEnabled(true);
1213

14+
// ...
15+
//! [delegate_main]
1316
QQmlApplicationEngine engine;
1417
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
1518
if (engine.rootObjects().isEmpty())

examples/datasync/IosSync/syncdelegate.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ SyncDelegate::SyncDelegate(QObject *parent) :
55
IosSyncDelegate{parent}
66
{}
77

8+
//! [delegate_src]
89
QtDataSync::IosSyncDelegate::SyncResult SyncDelegate::onSyncCompleted(QtDataSync::SyncManager::SyncState state)
910
{
1011
qInfo() << "Finished synchronization in state:" << state;
11-
return SyncResult::NewData;
12+
return IosSyncDelegate::onSyncCompleted(state);
1213
}
14+
//! [delegate_src]

examples/datasync/IosSync/syncdelegate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <QObject>
55
#include <QtDataSyncIos/IosSyncDelegate>
66

7+
//! [delegate_hdr]
78
class SyncDelegate : public QtDataSync::IosSyncDelegate
89
{
910
Q_OBJECT
@@ -14,5 +15,6 @@ class SyncDelegate : public QtDataSync::IosSyncDelegate
1415
protected:
1516
SyncResult onSyncCompleted(QtDataSync::SyncManager::SyncState state) override;
1617
};
18+
//! [delegate_hdr]
1719

1820
#endif // SYNCDELEGATE_H

0 commit comments

Comments
 (0)