How I shared the location through the VC API

Recently I decided to try to implement the idea of ​​how to share a location via the VKontakte API with friends in a mode close to real time. The output was a cross-platform Qt-application for iOS / Android, a web application for VKontakte and a couple of pull requests for the VK API. In this article I would like to share some unobvious moments of implementation that may be of interest to someone. So, I ask those interested under the cat.

Why do I need it at all


Sooner or later, children grow up. Banal truth. So my ten-year-old daughter one day said: “Dad, don't take me by car anymore, I want to go to school on my own!”. Well, I found the demand fair, asked for a two-week reprieve, and began the preparation.

Since I have some experience in writing apps, and the daughter is constantly carrying in the pocket of the iPhone SE, then as a preparation it was decided to quickly write an application that would show where the daughter is at this particular moment. Yes, I know that now there are quite a few such applications (even Google Maps recently had similar functionality), and it was possible to use some kind of ready-made solution, but it was interesting for me to write something of my own.

Why VKontakte?


Since I would not like to deal with the processing and storage of other people's (in the potentially possible future) personal data on my equipment with all the “charms” arising from this, I wondered how to do without my own server part. And then it dawned on me - after all, there is such a monster as VKontakte! It is fashionable, powerful and with its developed API, and most importantly - all our children have been sitting together for a long time and in a tight place (you cannot say that I like it, but it is a reality). But damn it, Holmes, how do I stuff location data into it so that, firstly, it doesn’t show where it’s not necessary, and secondly, you can regulate access to this data so that bad pedobirs do not need it didn't get it?

Notes came to the rescue. Yes, yes, the very Wikited notes that were once (rumored) were very popular, and are now in the pen, for the most part have ceased to shine in the tapes and have moved to a separate section of the site that you won't get on the lame goat. You can place arbitrary text data in them, but the main thing is that they can be assigned access lists in which people and groups are listed who can see and comment on this note.

The general scheme of the application in my eyes began to look like this:

  • Create a list of friends with whom you want to share location data (I called it "Trusted Friends");
  • We create a note with a specific name, give rights to view it to the above list, write down the location data there and periodically update it;
  • We regularly go over the list of trusted friends, checking whether they have a note with this specific name, if it does, then we try to extract friend’s location data from its content, and if we succeed, then show it on the map;
  • ???
  • PROFIT!

So, the idea is there, the case for small is to implement it.

iOS


Since the daughter uses the iPhone, it was logical to start the implementation with the iOS version. With an eye to cross-platform, Qt was chosen as the framework, because I’ve been familiar with it for quite a long time, and the good old Open Street Map, for which Qt Location has a plugin, was chosen as the map engine. Since the application was originally created as an open source, Qt’s licensing restrictions did not frighten me.

GUI was written in QML, to work with VK I connected and used the regular VK iOS SDK, it is written in Objective C, so its integration did not cause any problems. Work in the background on iOS is implemented through the Significant Change Location Service. To reduce power consumption, the application monitors the activity of movements, and if it understands that a person is sitting in about one place for a long time (let's say, came to school or office), then it lowers the required accuracy of geo-location determination, forcing the OS to switch to less energy-intensive ways to determine it ( usually on cell towers). If the application understands that the person has begun to move actively, the accuracy rises again.

The full set of iOS sources is available on GitHub . Here are a couple of unobvious moments that I encountered during the implementation process:

Redefinition of NSApplicationDelegate methods in the Qt-

iOS iOS application from VKontakte requires adding calls to some of its functions in the application: didFinishLaunchingWithOptions: and application: openURL: options: methods. Prior to some version of Qt (in my opinion, before 5.11) it was enough to create a category for QIOSApplicationDelegate something like this:

@interfaceQIOSApplicationDelegate : UIResponder <UIApplicationDelegate>@end@interfaceQIOSApplicationDelegate (QIOSApplicationDelegateVKGeoCategory)@end@implementationQIOSApplicationDelegate (QIOSApplicationDelegateVKGeoCategory)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[...]
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
[...]
}
@end

But in recent versions of Qt, QIOSApplicationDelegate already has an application: openURL: options :, so the option with categories is no longer rolling. I had to make a successor from QIOSApplicationDelegate and assign a delegate via setDelegate:

@interfaceVKGeoApplicationDelegate : QIOSApplicationDelegate@end@implementationVKGeoApplicationDelegate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
[...]
}
@endvoid InitializeVKGeoApplicationDelegate()
{
    [[UIApplication sharedApplication] setDelegate:[[VKGeoApplicationDelegate alloc] init]];
}
int main(int argc, char *argv[])
{
[...]
    InitializeVKGeoApplicationDelegate();
[...]
}

Error handling from VKRequest

Faced with the fact that VKRequest returned an empty (empty) NSError when an error occurred. I made a patch that patches someone's previous patch and pull request this patch, but it still hangs in unexamined.

Android


The next was a version for Android. The GUI code was almost completely reused from iOS, the VK Android SDK was also used to interact with the VC , which interacts through the JNI, the background work is implemented in accordance with Google's precepts for such applications - namely, the Foreground Service. Of course, the energy-saving logic is also implemented, similar to that used in iOS.

The full set of source code for the Android version is available again on GitHub , and here are a couple of unobvious moments that I encountered during the implementation of this version:

How to create an Android service on Qt

To create a service in Qt 5.10, a QAndroidService class appeared, which should be used instead of QGuiApplication. You can build separate .so for activity and for service, or you can use one .so for everything, and in order for the code to understand in which mode it works, you can specify this mode via the command line key, like this:

<serviceandroid:name=".VKGeoService"><meta-dataandroid:name="android.app.arguments"android:value="-service"/></service>

intmain(int argc, char *argv[]){
    if (argc == 1) {
        QGuiApplication app(argc, argv);
[...]
    } elseif (argc == 2 && QString(argv[1]) == "-service") {
        QAndroidService app(argc, argv);
[...]
    } else {
        return0;
    }
}

Strange “hanging” of activity in onDestroy ()

During the implementation of the service, a funny problem emerged - QtActivity “hung” somewhere in the depths of its onDestroy () provided that there is a running foreground service. Apparently, Qt does not expect that after the completion of the activity, something else may remain from the application. The problem was solved by separating activity and service across various processes through the use of android: process in the manifest:

<serviceandroid:name=".VKGeoService"android:process=":VKGeoService">
[...]
</service>

and nailing the process in which the activity works in the overridden onDestroy ():

@OverridepublicvoidonDestroy(){
[...]
   /*
    * This call hangs when foreground service is running,
    * so we just kill activity process instead (service
    * is running in a different process).
    *
    * super.onDestroy();
    */
    Process.killProcess(Process.myPid());
}

Yes, lint constantly swears at this, but how to cope with it in a different way is not obvious to me yet, but I don’t get QTBUG with PoC on this topic yet.

UPDATE : in Qt 5.12.3 (perhaps, I didn’t check it a bit earlier), the bug with QtActivity.onDestroy () hanging was fixed when the service was started, this workaround is no longer needed.

The lack of an errorBlock call when VKBatchRequest is canceled

I widely use batch requests to ease the load on VK servers, and it was for Android (everything works fine for iOS) I had a problem - if VKBatchRequest was canceled, errorBlock was not called for canceled requests. Fixed this problem in the local version of the library, made the corresponding patch and pull request of this patch, but again it is still hanging in the unexamined.

Заключение


The iOS version of Apple has easily placed on the App Store, and it is available there to this day, the Android version lived on Google Play for a while until the Google Play Policy was tightened (it was prescribed that geo-location tracking applications should be clearly are intended either for family use, or for corporate use), after which my application was safely blocked there. At my appeal attempt, a Google employee in charge (or maybe it was a bot, now it’s not so obvious who answers your questions) relentlessly stated that "well, this application CAN BE USED NOT ONLY for family or corporate tracking" , to which I could not find, to argue - indeed, with a hammer, you can not only hammer in nails, but also pierce heads ... Placed the Android version in Yandex.

I would be glad if this application is useful to someone as a visual aid for clarifying some unobvious moments when writing a Qt-application for iOS / Android, especially related to the implementation of Android service on Qt (this functionality is relatively new, examples of implementation, I know, not so much). Also I will be glad to answer questions in the comments, if any.

Also popular now: