L'histoire de la façon dont j'ai mis à jour Yandex MapKit sur iOS ou des cartes, de l'argent, 2 mappits

Préface



Bonjour mes amis , au début, je décrirai immédiatement le but de l'article: gagner du temps si vous devez mettre à jour ou intégrer des cartes Yandex dans votre client mobile iOS, ainsi que le désir de partager votre expérience.

Une fois, nous avons intégré l'application YandexMapkit (environ en octobre 2017) au lieu des cartes de messagerie (rien de personnel - juste des affaires). Après environ 3 mois, par une belle journée d'hiver, la version Androyd des cartes est tombée en panne le jour 2 à cause des clés, la carte s'est juste transformée en citrouille) Quelle est l'astuce du manuel: "Sur l'androïde, les cartes ont été cassées, ils ne savent pas comment y remédier" en tant que client iOS, cela n'a pas affecté. Pauvres gars sur l'androïde ... cette fois, les gars n'avaient rien à voir avec. À cette époque , de nombreuses loges sont tombées : le poste de Russie, l'ornithorynque, vous vous souvenez peut-être?



Je veux dire, lorsque votre application est liée à des services tiers, ce serait bien d'avoir un plan «B» pour ce cas, par exemple, passer à la version précédente de l'implémentation des cartes d'Apple, et ne pas les remplacer par une autre ...

Après encore 3 mois, quelque part en mars, une lettre est arrivée de Yandex qu'ils avaient finalement mis à jour sdk, (très peu de temps s'est écoulé, 4-5 ans depuis la mise à jour précédente):
"-Mettez à jour, éteignez l'ancien en un an", en bref. Avant cela, il y avait simplement une ancienne version 1.0



Eh bien, bien sûr, après un tel avertissement, nous n'avons pas tiré et avons immédiatement commencé la transition ... après 3 mois)) en août.

Étape de «commenter» (désactivation de la fonctionnalité)


Vous dites, ha ... ce qui est mis à jour là-bas, pod mis à jour, corrigé quelques endroits et c'est tout. Alors non, les gars, la nouvelle API de carte n'est absolument pas compatible avec l'ancienne, et de plus, comme il s'est avéré plus tard, il y a même beaucoup de nécessités vitales qui sont prêtes à l'emploi dans l'ancienne version et d'autres bibliothèques de cartes!

Ainsi, mapkit 3.0 (lors de la rédaction d'un article version 3.1 a été publié), un lien vers la documentation .

Et pourquoi, outre un avertissement de Yandex? En attendant, sur une version bêta de Xcode 10, un projet avec une vieille baleine ne va bêtement pas, car C ++ est utilisé quelque part à l'intérieur, qui est déprikrié dans la nouvelle version. Il faut le renommer dans la sous-liste, même le mettre à jour là-bas, etc., bref, je ne l'ai pas fait, car au final j'ai encore besoin de le mettre à jour

1) Nous mettons à jour sdk, au lieu de la version 1.0 immédiatement 3.0, bien sûr l'API a changé, mais tellement ....

Donc, l'ancien protocole YMKAnnotation est tout simplement manquant




En swift, cela ressemble à un strig forgé de force (: ce n'est pas un bourdonnement, puis vous portez un signe "!" Pour vous-même ... Exemple d'implémentation de protocole:



Eh bien, réécrivons) la nôtre, seulement au lieu de la méthode coordonnée (), nous créerons les propriétés, tout est simple, la méthode est redondante; title! () est remplacé par un title non formé (), d'autre part, vous pouvez créer une propriété, eh bien, il y a beaucoup de choses où vous devez changer le projet, donc je viens de supprimer le point d'exclamation.

Dans notre projet, il était nécessaire de remplacer plusieurs fois 3 contrôleurs, d'importer CoreLocation dans un autre, car il n'est désormais importé dans aucun des en-têtes Yandex MapPocket.

Afin de ne pas renommer le YMKMapCoordinate familier (vieille baleine) tout au long du projet, faites des typealias pour YMKPoint (nouvelle baleine)



2) Déclarons également quelques propriétés dont nous aurons besoin à l'avenir pour travailler avec la carte, principalement des getters:



3) La première chose à créer est YMKMapView (tout va bien, un tel objet est toujours disponible). Auparavant, je l'avais initialisé tout de suite, maintenant vous ne pouvez pas faire ça, ça va planter, car vous devez d'abord mettre la clé! La clé actuelle ne fonctionnera pas et vous devez en demander une nouvelle. Ajoutez à AppDelegate, selon la documentation. Ce n'est qu'après avoir défini la clé que nous pouvons créer YMKMapView et le configurer de la manière dont nous avons besoin dans la méthode setupMap ()



Ce qui se passe ici, nous analyserons en détail plus tard au cours de la nécessité de paramètres appropriés

4) Quelle est la prochaine étape?, Puis nous avons eu l'emplacement initial de CLLocation, mais maintenant pour l'utiliser, vous devez ajouter le framework CoreLocation manuellement, ou ... ou le remplacer par YMKPoint à partir du kit de cartes Yandex



5) De plus, la carte était centrée sur cette coordonnée par une méthode très simple, mais maintenant il n'y a pas de



Mais il y a un peu plus compliqué et un peu plus profond, l'objet map) ... mapView.mapWindow.map! .Move. Nous apprenons ici l'existence d'un tel objet comme YMKCameraPosition.



6) Ensuite, nous commentons la configuration de la carte, car il n'y a pas de telles API / propriétés. Maintenant, nous l'omettons juste pour commencer au moins de façon minimale.

Nous commentons l'ajout d'annotations (je ferai attention à ce que ce soit une fonctionnalité standard), nous commentons également à montrer les points les plus proches (c'est déjà une sorte de notre fonctionnalité).

Et l'ensemble de YMKMapViewDelegate est également un commentaire, que je n'ai pas trouvé dans le nouveau cadre, et un analogue similaire aussi.



J'ai omis l'implémentation, seulement les méthodes elles-mêmes:

- s'il faut afficher l'emplacement de l'utilisateur,
- quelles vues utiliser pour les broches,
- réaction au clic sur l'annotation,
- quelles légendes d'annotation,
- La réaction au clic sur la légende, c'est-à-dire tout ce que nous utilisons habituellement. À la fin, il y avait une sorte de notre méthode, qui utilisait également une carte API spécifique.

TOUT compris avec MapVC - c'est la classe principale où le mapkit a été utilisé

7) Un petit commentaire sur la légende personnalisée, elle n'héritera plus de YMKCalloutView, il n'y en a plus dans la nouvelle baleine.

Hourra, maintenant que le projet est rassemblé, j'ai pu tout démarrer et ... voir le cahier dans la boîte, car après le démarrage, il faut donner le temps de "se réchauffer")), mais je ne le savais pas et je pensais que quelque chose n'allait pas donc, même si j'ai suggéré qu'il fallait du temps pour activer la clé. Il s'avère que l'hypothèse était correcte. Vous devez attendre environ une heure (peut-être que quelque chose a changé maintenant).

Avec une autre tentative de modifier l'ancienne API d'une nouvelle manière, la carte a été affichée.

Deuxième étape - «recherche» (comment mettre en œuvre l'ancienne fonctionnalité d'une nouvelle manière)


Commençons par restaurer la fonctionnalité perdue. Donc, vous devez afficher le verrou utilisateur, mais à l'ancienne, il ne suffit pas de modifier la propriété et de définir le délégué.

Maintenant, cela se fait à travers la couche, voir le point 3 de la méthode setupMap ().



Nous allons jeter un œil à l'exemple de la démo (à télécharger sur Yandex github ), car il est là. Au fait, vous devez faire attention à setAnchorWith. Plus tard, je dirai pourquoi, il est associé au zoom. L'emplacement fonctionne bien.

2) Quelle est la prochaine, bien sûr, les annotations. Vous ne pouvez pas ajouter à l'ancienne, nous regardons à nouveau dans la démo. Il y a une classe là-bas - MapObjectsViewController. Dans la nouvelle version, pour ajouter des épingles à la carte, le délégué n'est pas nécessaire, pour cela, vous devez accéder à la propriété mapObjects, appeler la méthode addPlacemark sur l'objet et y transmettre les coordonnées (il y a encore d'autres surcharges) Exemple:



Nous parcourons la collection d'annotations (par exemple, après avoir reçu du serveur) et en ajoutons une à la carte. La méthode, en passant, renvoie «placeMark» (étiquette de lieu), qui peut être utilisé pour effectuer des paramètres supplémentaires, par exemple, changer l'ordre d'affichage via la propriété zIndex.

Ici, cependant, j'ai raté le point qu'avant cela, je suis monté pour chercher un délégué et je ne l'ai pas trouvé en toute sécurité et pas un seul délégué du tout (en fait, ils ont juste commencé à être appelés différemment, maintenant ils sont des auditeurs). Je sais par expérience précédente avec la baleine d'Apple et la vieille baleine Yandex que les annotations sont réutilisées, tout comme avec les cellules, mais il n'y a que addPlacemark dans la démo. À la question sur les cartes Yandex (une petite connaissance personnelle a aidé ici) "- Comment optimiser l'utilisation de la mémoire, réutiliser les objets?" Réponse: "Pourquoi, donc ça marche bien" ... enfin, en quelque sorte oui, ça marche.

Remarque: 1) Il est important de noter que Yandex.Maps utilise un mapkit et ne le développe pas. Ceci est fait par l'équipe de mapkit (surnom de Nikolai sur le hub - likhogrud @).

2) Explication pourquoi les objets ne sont pas réutilisés:

Dans la vieille baleine, les annotations étaient des vues, elles ont été créées par l'utilisateur, et bien sûr les vues doivent être réutilisées, car les créer n'est pas bon marché. Dans la nouvelle baleine, des repères sont créés par le mapkit directement dans GL ouvert. Et peut-être qu'ils sont réutilisés là-bas, mais c'est inexact. Dans tous les cas, c'est beaucoup plus efficace que de créer une vue.

3) A partir du nouveau, il y a d'ailleurs la possibilité de modifier l'icône d'annotation pour l'utilisateur. Implémenté comme suit: vous devez ajouter un écouteur (analogue du délégué), implémenter le protocole approprié - 1 méthode sur 3, 2 simplement laisser vide.

En même temps, rechargez le repère avec nos icônes.



Aussi, j'attire votre attention sur la propriété de l'ancre. Après avoir appuyé sur le bouton de localisation de l'utilisateur sur la carte, la caméra déplace la mise au point au centre de la position. Mais le problème est que presser à nouveau l'action ne produit pas. Quoi? Nous commentons la méthode d'ancrage et tout fonctionne.

4) Vous devez maintenant afficher la légende, respectivement, pour déterminer le clic. Il existe plusieurs méthodes dans les interfaces, la bonne est YMKMapObjectTapListener. Il y a 1 méthode intéressante et importante avec laquelle j'ai dû me tourmenter plus tard, elle revient vraie pour ne pas s'intégrer davantage si un abonné est trouvé. J'attire votre attention, vous devez d'abord vous abonner, mapObjects sera abonné (ligne 149).





Les clics sont donc satisfaisants. Hourra . Cependant, il y a eu des tentatives pour afficher les broches uniquement dans la zone visible, c'est superflu, montrons tout à la fois, alors laissons cela (juste parce qu'il ne ralentit pas)

5) Ensuite, je voulais faire un zoom avant / arrière sur les boutons pour plus de commodité. Un petit copier-coller et des modifications par analogie avec le bouton de localisation, et vous avez terminé.

De plus, puisque nous connaissons la caméra, en utilisant la méthode de déplacement et, en conséquence, le zoom actuel + - 1 ou 0,5, selon vos besoins. Tout va bien ici.



6) Nous passons à la fonction principale - légende (c'est un rectangle avec des informations supplémentaires, avec un triangle en bas). Il s'avère qu'il n'y a pas d'API («enivrant en été» - Yandex a reconnu mon discours lorsque j'ai lu des notes dans une brochure pour ne pas taper manuellement cet article).



Comment ça va? 100 500 applications utilisent une légende.

Nous écrivons bien dans le «support technique» (Kolya) comment procéder manuellement, je découvre. Quelles sont vos options?

Convertissez la vue en image, puisque vous ne pouvez pas ajouter directement une vue (ajout d'un fichier en 3.1), changez l'icône ...



Ces béquilles sont obtenues sur un plat, il semblait bien placé.
En fait, pas des béquilles, bien sûr, mais simplement l'absence je considère la fonctionnalité de base

7) D'accord, ajoutons d'abord une légende de test, en tant que tel, nous utilisons un carré rouge. Ainsi, en cliquant sur notre épingle, la méthode délégué / auditeur est appelée, où le point de clic et l'objet sont transférés. Sans attendre une astuce, nous prenons «point» comme le point où vous souhaitez ajouter la légende. (Attention, est-ce que tout est fait correctement: "Ils ont cliqué, pris le point, attaché?" Environ 80% ont répondu correctement, 20% - non)



Et appelez la méthode d'assistance showCallout dans le corps de la méthode:



ligne 544
À l'intérieur, créez une vue de test de couleur rouge quarante par quarante, convertissez-la en image, déclarez une constante x avec une valeur de 0,5, elle sera utilisée pour la position du triangle de légende au milieu du point. Il a refusé l'idée de changer de position, a ensuite préféré déplacer la caméra pour que la légende sélectionnée s'affiche au milieu de l'écran du téléphone.

Ensuite, nous déclarons la zone «push» de tappableArea, il existe une telle propriété dans le style d'icône pour la broche. Eh bien, vous pouvez limiter la zone de clic, et nous le ferons. La zone varie de 0,0 à 1,1. nous avons besoin de la partie inférieure, où il y a soi-disant un bouton qui a été transformé en image auparavant (rappelez-vous). D'accord, cela signifie la zone (0,0,5 - 1,1) puisque le bouton est en dessous.
La restriction de zone fonctionne, mais il y a une nuance, telle qu'elle annule tout. S'il y a une autre broche sous la zone non pressée, appuyez sur pour y travailler. La signification de cette zone? Feraient-ils un drapeau ou quelque chose pour que le clic ne passe pas. D'accord ...

550 ligne
créons un style pour l'icône, vous pouvez immédiatement spécifier la position de l'ancre dans le premier paramètre, par exemple, je l'ai fait ci-dessous à la ligne 557. La position y est de 1,05 pour élever verticalement le triangle au-dessus de la broche

559 ligne
créer notre légende personnalisée d'une certaine taille,
nous configurons les champs dont nous avons besoin en utilisant les informations de l'annotation sélectionnée selectedAnnotation, en particulier le titre et le sous-titre, l'inscription sur le bouton de cette légende. Vous pouvez alors faire ce que vous voulez. L'annotation sélectionnée est définie plus tôt dans le délégué. Mais pour l'instant, ajoutez le carré rouge créé plus tôt
Ensuite, ajoutez une épingle à la collection mapObjects, la méthode nous renverra le repère ajouté, enregistrez-le dans une variable,
En cliquant sur la légende elle-même, un contrôleur détaillé s'ouvre, et donc la nuance est que si sous la fenêtre contextuelle une autre broche y est également entrée, le délégué fonctionnera à nouveau, alors ici, vous devez changer l'ordre dans la hiérarchie via zIndex. Définissez la visibilité et déplacez notre légende vers le centre sur la ligne 564

Nuances : le repère variable est un pointeur vers la légende.
Au début, nous ne l'avons pas, après avoir cliqué sur l'épingle, il apparaît, après avoir cliqué sur l'épingle suivante, nous devons supprimer notre première légende et en ajouter une nouvelle. Par conséquent, si le repère variable! = Nil, vous devez supprimer l'ancien repère de la collection mapObjects)



De plus, dans le cas de tapas sur la carte, vous devez masquer la légende, donc dans la méthode déléguée, nous attribuons un repère, l'observateur fonctionne, la légende est supprimée, et nous effaçons l'annotation sélectionnée

Pour cela, nous nous sommes inscrits à YMKMapInputListener plus tôt



À son tour, la méthode de conversion des vues est la suivante. (Dans la version 3.1, ajout de la possibilité d'ajouter des vues à la carte)
Je ne décris pas comment faire la vue), mais s'il y aura beaucoup de problèmes (c'est possible avec un triangle) avec ça, alors écrivez, j'ajouterai cette étape



La magie 20 ajoutée à la hauteur est nécessaire pour une place sous le triangle ci-dessous, que vous devrez dessiner

Nous voulons également que le popup apparaisse (soit attaché) à la broche à un endroit spécifique (gauche, droite, au milieu), pour cela il y a une propriété d'ancrage. Défini comme suit:
Nous divisons la zone visible de la carte en 3 zones verticales et déterminons dans laquelle nous nous trouvons, en fonction de cela, changeons la position de la reliure. Dans l'exemple de code, nous vérifions si nous sommes sur le côté gauche, par analogie, nous faisons pour le milieu, sinon la gauche et pas au milieu, respectivement, le point à droite est



Une fonction d'aide pour vérifier si un point tombe dans une région:



Commencez. Ça marche. Mais il y a une nuance, il semblerait que nous essayons de zoomer, un, deux, trois, et la légende s'éloigne de la broche. Quoi? Comment?



7) Nous commençons le débogage, les coordonnées sont les mêmes



Puis il y a eu des tentatives pour comprendre ce qui se passe et comment ça marche, un autre retour à la démo, une recherche encore plus attentive des différences ...



Je remarque que les coordonnées sont transmises directement, et non celle qui est sur le robinet! Mais j'ai déboulonné, il est clair que les coordonnées sont les mêmes, c'est-à-dire que le cercle et le carré ont la même coordonnée.
C'est pourquoi dans la méthode, je n'ai pas immédiatement accédé à l'objet, mais passé le point, ce qui est incorrect.



Mais avez-vous besoin de mouler un objet, de prendre une propriété (partout où tout est appelé différemment, puis de coordonner, puis de pointer, ici maintenant la géométrie) est-ce une créative ou quoi)? 493 lignes



Étant donné que nous devons traiter deux options pressantes: la première pour épingler, la seconde pour appeler et ne pas traiter les clics si nous avons cliqué à nouveau sur la même épingle, la première chose que nous faisons est de trouver l'épingle sur laquelle nous avons cliqué dans la collection d'épingles, en comparant coordonne la ligne 495, sinon retourne vrai, disant ainsi que nous avons traité le clic et n'avons pas besoin d'aller plus loin dans la hiérarchie

Deuxièmement : nous le déterminons en cliquant sur la broche ou sur la légende, nous comparerons également les coordonnées des étiquettes de ligne 499. Test d'égalité:



De plus, si c'est une légende et que nous voulons répondre à un clic de bouton (ou simuler, car maintenant c'est une image), et non à toute la zone, alors nous devons faire des calculs avec des stylos :)

  1. Convertir les coordonnées du monde en ligne d'écran 501
    Nous nous considérons: nous allons convertir les coordonnées de la carte en écran, nous savons où nous nous trouvons, puis en ajoutant la largeur et la hauteur de la vue, nous obtenons les points d'angle, mais pour une raison quelconque, ils ne correspondent pas et j'ai multiplié manuellement par trois, dans mon cas pour le 10e iPhone)). Comme il s'est avéré plus tard, j'ai oublié et je n'ai pas pris en compte le nombre de pixels par point. Ce que nous pouvons avoir 1x, (un point 1 pixel), 2x, 3x un point est de trois pixels.
  2. Calculons la hauteur du bouton - la hauteur de la légende + la hauteur du triangle multipliée par l'échelle, informations sur l'échelle (ligne 498). Ensuite, nous divisons tout cela en deux, car la hauteur du bouton est la moitié de la hauteur de la légende
  3. Ensuite, nous calculons les coordonnées des angles, sur la base du fait que l'ancre (x: 0,5, y: 1), compte tenu de l'échelle et de l'aire du triangle))
  4. Puis convertissez ces coordonnées d'écran en monde
  5. Créer une zone visible basée sur eux, est une zone de bouton
  6. Et nous vérifions si nous frappons la zone des boutons ou non. Si vous appuyez, vérifiez le type d'annotation, selon le type que nous appelons une de nos méthodes: allez à l'écran détaillé ou sélectionnez ce magasin pour la livraison dans les cas avec StorePoint

Sinon, c'est un clic sur la broche et nous devons ajouter une légende, ce que nous avons fait ci-dessus.

C'est tout, cette première connaissance de la nouvelle baleine est terminée.

Ce que je veux dire d'autre, dans l'implémentation actuelle des cartes mapkit, il contient beaucoup de fonctionnalités qui ne sont pas utilisées, cela affecte également la taille du binaire résultant. Êtes-vous prêt pour de tels sacrifices, à l'avenir, les gars devraient être démolis en modules après tout . J'ai également entendu des collègues de l'androïde de l'atelier qu'il y avait des problèmes de compatibilité avec Kotlin.

P.S. Alors que j'ai décidé et commencé à écrire un article, la mise à jour 3.1 est sortie, d'où les problèmes ci-dessus ont été résolus et mis en œuvre:

Ajouté

Pour Android, les versions arm64 et x86 sont apparues.
Vous pouvez ajouter n'importe quel objet View à la carte.
L'itinéraire du vélo est apparu.
Ajout d'annotations annulables pour Android.

Changé

MapKit est divisé en plusieurs parties:
MapKit - seulement une carte;
MapKit Directions - itinéraire de la voiture;
MapKit Transport - itinéraires piétons, itinéraires des transports publics et itinéraires cyclables;
Recherche MapKit - recherche et géocodage;
MapKit Places - panoramas.
Pour iOS, les annotations annulables sont devenues plus strictes.

Fixe

Un certain nombre de bugs ont été corrigés.
Amélioration des performances.

tech.yandex.ru/maps/doc/mapkit/3.x/concepts/versions-docpage

Écrivez vos commentaires, questions.

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


All Articles