Comment je partage l'emplacement via l'API VK

Récemment, j'ai décidé d'essayer de mettre en œuvre l'idée de partager un emplacement via l'API VK avec des amis en mode presque en temps réel. La sortie était une application Qt multiplateforme pour iOS / Android, une application Web pour VKontakte et quelques demandes de tirage pour l'API VK. Dans cet article, je voudrais partager certains points d'implémentation non évidents qui peuvent intéresser quelqu'un. Donc, intéressé, veuillez demander un chat.

Pourquoi en ai-je besoin


Tôt ou tard, les enfants grandissent. Vérité banale. Alors ma fille de dix ans a dit un jour: "Papa, ne me prends plus en voiture, je veux aller à l'école toute seule!" Eh bien, j'ai trouvé la demande juste, j'ai demandé un délai de grâce de deux semaines et j'ai commencé les préparatifs.

Comme j'ai une certaine expérience dans l'écriture d'applications et que ma fille se déplace constamment dans la poche de l'iPhone SE, en guise de préparation, il a été décidé d'écrire rapidement une application qui montrerait où se trouve la fille à ce moment particulier. Oui, je sais qu'il y a maintenant beaucoup de telles applications (même des fonctionnalités similaires sont récemment apparues sur Google Maps), et il était possible d'utiliser une solution prête à l'emploi, mais j'étais intéressé à écrire quelque chose de moi-même.

Pourquoi VKontakte?


Comme je ne voudrais pas associer au traitement et au stockage des données personnelles d'autres personnes (dans une perspective possible) sur mon équipement avec tous les «charmes» qui en découlent, j'ai réfléchi à la façon de me passer de ma propre partie serveur. Et puis ça m'est venu à l'esprit - après tout, il y a un monstre comme VKontakte! Il est à la mode, puissant et avec sa propre API développée, et surtout, tous nos enfants y sont assis depuis longtemps et sont serrés (je ne peux pas dire que je l'ai aimé, mais c'est une réalité). Mais bon sang, Holmes, comment puis-je y fourrer des données de localisation afin que, premièrement, elles n'apparaissent pas là où elles ne sont pas nécessaires, et deuxièmement, afin que vous puissiez contrôler l'accès à ces données afin que les mauvais pédobirs leur n'y est pas arrivé?

Les notes sont venues à la rescousse. Oui, ces mêmes wikipedia notent qu'une fois (selon les rumeurs) étaient très populaires et sont maintenant dans le stylo, pour la plupart, ils ont cessé de clignoter dans les bandes et sont passés à une section distincte du site, que vous n'obtiendrez pas sur une chèvre boiteuse. Vous pouvez y placer des données de texte arbitraires, mais l'essentiel est de leur attribuer des listes d'accès qui répertorient les personnes et les groupes qui peuvent voir et commenter cette note.

Le schéma général de l'application à mes yeux a commencé à ressembler à ceci:

  • Créez une liste d'amis avec qui vous souhaitez partager les données de localisation (je l'ai appelé «Trusted Friends»);
  • Nous créons une note avec un nom spécifique, donnons le droit de l'afficher à la liste ci-dessus, notons les données de localisation là-bas et les mettons à jour périodiquement;
  • Nous parcourons régulièrement la liste des amis de confiance, vérifiant s'ils ont également une note avec ce nom spécifique, si c'est le cas, puis nous essayons d'extraire des données sur l'emplacement de l'ami à partir de son contenu, et si cela réussit, nous l'afficherons sur la carte;
  • ???
  • PROFIT!

Donc, il y a une idée, c'est à la petite chose de la réaliser.

iOS


Étant donné que sa fille utilise l'iPhone, il était logique de commencer la mise en œuvre avec la version iOS. Dans une perspective de multiplateforme, Qt a été choisi comme cadre, car je le connais depuis longtemps, et la bonne vieille Open Street Map, pour laquelle il existe un plugin dans Qt Location, a été choisie comme moteur de la carte. Depuis que l'application a été créée à l'origine comme open source, les restrictions de licence de Qt ne m'ont pas fait peur.

L'interface graphique a été écrite en QML, pour fonctionner avec VK, j'ai connecté et utilisé le SDK VK iOS normal, elle est écrite en Objective-C, donc son intégration n'a pas posé de problème. Le travail en arrière-plan sur iOS est mis en œuvre via le service de localisation de changement significatif. Pour réduire la consommation d'énergie, l'application surveille l'activité des mouvements, et si elle comprend qu'une personne est assise pendant une longue période au même endroit (par exemple, elle est venue à l'école ou au bureau), puis elle diminue la précision requise pour déterminer la géolocalisation, forçant l'OS à passer à des moyens moins énergivores de la déterminer (comment en règle générale, sur les tours cellulaires). Si l'application comprend que la personne a commencé à bouger activement, la précision augmente à nouveau.

Le code source complet de la version iOS est disponible sur GitHub . Voici quelques points non évidents que j'ai rencontrés lors du processus de mise en œuvre:

Substitution des méthodes NSApplicationDelegate dans une application Qt

Le SDK iOS de VKontakte nécessite l'ajout d'appels à certaines de ses fonctions dans l'application: didFinishLaunchingWithOptions: et application: openURL: options: méthodes. Avant une version de Qt (à mon avis, avant 5.11), il suffisait de créer une catégorie pour QIOSApplicationDelegate comme ceci:

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

Mais dans les versions récentes de Qt, QIOSApplicationDelegate a déjà une implémentation de l'application: openURL: options:, donc l'option avec les catégories ne roule plus. J'ai dû faire un héritier de QIOSApplicationDelegate et affecter un délégué via setDelegate:

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

Gestion des erreurs de VKRequest

Face à ce que VKRequest en cas d'erreur retourne une NSError vide (vide). J'ai créé un correctif qui corrige le correctif précédent de quelqu'un et tire une demande pour ce correctif, mais il se bloque toujours dans les correctifs non révisés.

Android


Ce qui suit était la version pour Android. Le code GUI a été réutilisé à partir d'iOS presque complètement, pour interagir avec le VK, le SDK VK Android régulier a été à nouveau utilisé, l'interaction avec laquelle se produit via le JNI, le travail en arrière-plan est mis en œuvre conformément aux engagements de Google pour de telles applications - à savoir, via le Foreground Service. Bien sûr, la logique de réduction de la consommation d'énergie, similaire à celle utilisée dans iOS, est également implémentée.

L'ensemble complet du code source de la version Android est à nouveau disponible sur GitHub , et voici quelques points non évidents que j'ai rencontrés lors de la mise en œuvre de cette version:

Comment créer un service Android sur Qt

Pour créer un service dans Qt 5.10, la classe QAndroidService est apparue, qui devrait être utilisée à la place de QGuiApplication. Vous pouvez compiler un .so distinct pour l'activité et le service, ou vous pouvez utiliser un .so pour tout, et pour que le code comprenne dans quel mode il fonctionne, vous pouvez spécifier ce mode via la touche de ligne de commande, quelque chose comme ceci:

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

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

Activité étrange de "balancement" dans onDestroy ()

Dans le processus de mise en œuvre du service, un problème amusant est devenu clair: QtActivity s'est «accroché» quelque part dans les entrailles de son onDestroy (), sous réserve de la disponibilité d'un service de premier plan fonctionnel. Apparemment, Qt ne s'attend pas à ce qu'une fois l'activité terminée, quelque chose d'autre puisse rester de l'application. Le problème a été résolu en espaçant l'activité et le service sur différents processus grâce à l'utilisation d'Android: processus dans le manifeste:

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

et clouer le processus dans lequel l'activité s'exécute, dans un onDestroy () surchargé:

 @Override public void onDestroy() { [...] /* * 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()); } 

Oui, les peluches ne cessent de jurer, mais comment y faire face différemment n'est pas encore évident pour moi, mais mettre la main sur QTBUG avec PoC sur ce sujet n'atteint encore rien.

MISE À JOUR : dans Qt 5.12.3 (peut-être un peu plus tôt - je n'ai pas vérifié) le bogue avec le blocage de QtActivity.onDestroy () a été corrigé au démarrage du service, cette solution de contournement n'est plus nécessaire.

Appel errorBlock manquant lors de l'annulation de VKBatchRequest

J'utilise largement les requêtes batch pour alléger la charge sur les serveurs VKontakte, et c'est sous Android (tout fonctionne bien sous iOS) que j'ai rencontré un problème si VKBatchRequest était annulé et errorBlocks n'était pas appelé pour les requêtes annulées. J'ai résolu ce problème dans la version locale de la bibliothèque, effectué le correctif approprié et demandé une extraction pour ce correctif, mais encore une fois, il se bloque dans les non révisés.

Conclusion


La version iOS d'Apple a été facilement placée dans l'App Store, et elle y est toujours disponible; la version Android a vécu sur Google Play pendant un certain temps jusqu'à ce que la politique de Google Play soit resserrée (elle prescrivait que les applications de géolocalisation de suivi devaient être explicitement destiné à un usage familial ou professionnel), après quoi mon application y a été bloquée en toute sécurité. À ma tentative d'appel, un employé responsable de Google (ou peut-être était-ce un bot, maintenant ce n'est pas si évident qui répond exactement à vos questions) a catégoriquement déclaré que "eh bien, cette application NE PEUT PAS ÊTRE UTILISÉE UNIQUEMENT pour le suivi familial ou d'entreprise" , auquel je n'ai rien trouvé à dire - en effet, avec un marteau, vous pouvez non seulement marteler les ongles, mais aussi vous frapper la tête ... J'ai placé la version Android dans Yandex.Store et Amazon Appstore et en tant qu'APK sur le site Web du projet.

Je serai heureux si cette application est utile à quelqu'un comme aide visuelle pour clarifier certains moments non évidents lors de l'écriture d'une application Qt pour iOS / Android, en particulier ceux liés à la mise en œuvre du service Android sur Qt (cette fonctionnalité est relativement nouvelle, des exemples de mise en œuvre, combien Je sais pas trop). Je serai également heureux de répondre aux questions dans les commentaires, le cas échéant.

Source: https://habr.com/ru/post/fr434996/


All Articles