Organisation projet et environnements
samir
Membre
Hello,
J'essaie d'organiser au mieux mon projet. Comme la majorité des projets, je dois compiler le projet sur plusieurs environnements ( Prod, recette,...).
Ce que je fais pour l'instant : je crée plusieurs Targets ( prod, recette,..) et pour chaque tarrget un ficher de config associé et un .plist pour les différentes urls, bon ça marche bien mais je trouve que créer une target pour cet usage est un peu "Lourd" ( je me suis retrouvé avec 12 Targets sur un projet ).
Comment vous faites pour vous facilitez la vie ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Je suis pas un spécialiste, mais t'as regardé un peu les Schemes ?
De base, on peut déjà distinguer Debug et Release, il me semble qu'on peut en ajouter.
@Céroce Oui on peut rajouter nos propres schemes, c'est ce que je fais justement : je crée un schème Beta_distribution pour les béta rélease, mais ce que je veux est la configuration des différentes URL (Prod , recette,...).
Ce que je pense faire est une simple interface graphique qui te permet de sélectionner l'environnement avant le lancement de l'application.
Sinon un script en ligne de commande hors Xcode qui copie les fichiers en fonction d'un parametre et lance la compilation (pas besion de schemes dans ce cas)
1) Soit en changeant le #define PLATFORM dans le code
2) Soit en changeant le #define via un Build Setting (genre GCC_PREPROCESSOR_DEFINITIONS)
3) Mais en général c'est mon intégration continue qui s'en charge : de mon côté si je veux tester sur une PF ou une autre rapidement, je change le #define PLATFORM dans le code pour basculer, mais quand je demande à ma CI génère une OTA pour l'envoyer au client, j'ai 4 tâches différentes dans ma CI " une pour chaque plateforme " qui invoquent toutes la même commande rake mais avec un paramètre qui injecte "-DPLATFORM=1" ou une autre valeur selon la PF que je veux livrer.
Cette solution me permet d'éviter de multiplier les targets pour en avoir 4 identiques à juste un fichier près " d'autant que j'utilise déjà des targets différents quand je fais une application en Marque Blanche, où là je compile des Assets et des fichiers de constantes différents en fonction de la marque pour laquelle je génère le produit. Donc je vais éviter d'utiliser les targets aussi pour les différentes variantes de conf WS Prod/Preprod/Dev sinon ça multiplie trop et y'a des chances qu'en terme de maintenance j'oublie de reporter une modification que je pourrais faire sur un target sur les autres targets.
Je pourrais utiliser les Configurations (ne plus avoir que Debug et Release mais Debug-Prod, Debug-Preprod, Release-Prod, ...), après c'est aussi un peu ch*ant à gérer (et marche mal quand on a un Workspace avec plusieurs projets, même si on peut se débrouiller et que par exemple CocoaPods a une option pour gérer ce cas là )
Utiliser les scheme pour ça, je ne vois pas trop comment, quel levier on a dans les schemes qui permettrait de builder des fichiers différents, ou de façon conditionnelle, ou injecter des macros préprocesseur, etc... via des Schemes ?
Les seuls points d'action que je vois côté Scheme qui pourrait servir c'est d'injecter des variables d'environnement ou bien des paramètres de ligne de commande lors du lancement de l'application via Xcode. Ce qui marche très bien (on peut imaginer déclarer des paramètres de lancement comme "-platform 1" qui va injecter dans le domaine command-line des NSUserDefaults la valeur 1 pour la clé "platform", donc facile à récupérer par code au runtime), mais (1) ça veut dire que c'est un contrôle au Runtime, et pas à la compilation (donc le code de la dev/preprod & prod restera dans le binaire final, dommage) et (2) de toute façon ça n'a d'effet que quand l'app est lancée via Xcode, car c'est des paramètres de lancement, pas de compilation, donc quand vous ferez votre binaire final ou votre livraison OTA intermédiaire à votre client, vous pourrez pas lui faire une livraison intermédiaire pointant vers la Preprod automatiquement quand il la lancera depuis son iPhone...
Après, quand je vais passer à des projets purs Swift, ça sera une autre histoire car je ne pourrais pas appliquer ces mêmes principes à Swift, qui n'a pas de macros. Je n'ai pas encore réfléchi à comment j'allais faire dans ce cas-là .
Dave Delong (qui est Apple Evangelist donc il devrait savoir de quoi il cause ^^) a proposé ceci :
Cependant il admet que ce n'est pas non plus simple ni idéal, et a déjà remonté un bug à ses collègues de la team Xcode à ce propos (rdar://problem/20616717) pour proposer comme solution de pouvoir appliquer plusieurs Configurations croisées plutôt que de devoir choisir qu'une seule configuration Debug/Release, comme ça tu pourrais choisir la config "Debug" + la config "Preprod" et ça combine les deux, plutôt que d'avoir à faire 4 configurations "Debug-Preprod", "Release-Prepêrod", "Debug-Prod", "Release-Prod" et risquer de t'emmêler les pinceaux à les maintenir. Mais bon, pour l'instant ce problème n'a toujours pas été adressé et Xcode ne propose toujours pas de tel mécanisme :-/
Sinon, un autre propose sensiblement la même chose:
Un autre propose une approche avec des fichiers PLIST aussi, intéressante :
Quand j'ai évoqué que le problème avec ce genre d'approches c'est qu'on avait alors dans l'application à tout moment toutes les implémentations / valeurs pour tous les environnements, et qu'on prenait la décision au Runtime plutôt qu'à la compilation, Dave a proposé une alternative : extraire les différentes implémentations possibles de son EnvironmentVariablesProviders dans un framework (weak-linké) et choisir avec lequel on link à la compilation, par exemple via des configurations différentes ayant une valeur différente pour `Other Linker Flags`.
Mais il admet que c'est qd mm s'embêter beaucoup juste pour éviter que les infos de preprod partent sur l'AppStore et que ça requiert beaucoup de configuration, donc la solution PLIST est peut-être la plus simple à mettre en oeuvre.
Merci pour tous ces retours.
J'utilise une approche différente, qui mixe un peu tout ça.
Mon objectif était de pouvoir :
- définir le mode de fonctionnement au build, notamment pour les tests unitaires et fonctionnels
- avoir la possibilité dans certains cas de définir le mode de fonctionnement à l'exécution, en particulier pouvoir basculer entre prod et pre-prod pendant les tests de validation (sous TestFlight)
J'ai une classe OperationMode qui gère ce que j'appelle le mode de fonctionnement (test, pré-prod, prod, et pourquoi pas, tout autre mode que l'on peut inventer, en l'occurence j'ai ajouté un mode Demo qui sert aux commerciaux ; ils utilisent un environnement type bac à sable). Cette classe fournit :
- une méthode +mode qui permet à chaque autre classe qui voudrait adapter son comportement de connaà®tre le mode courant
- des méthodes setter/getter (de classe aussi) pour modifier/obtenir les User Defaults, car certains peuvent dépendre du mode de fonctionnement
Le mode de fonctionnement fourni par OperationMode était dans un premier temps défini par une macro dont la valeur était fixée à la compilation avec la technique d'Aligator citée ci-dessus. Mais j'ai abandonné cette technique pour adopter le fonctionnement suivant :
- le mode de fonctionnement est fixé par un paramètre au lancement (utilisé concrètement dans le Schème Debug)
- sinon le mode est donné par un User Default spécifique (OperationMode tout simplement)
- sinon, en l'absence de ce User Default, le mode de fonctionnement est "Production"
Pour compléter le tout, j'ai un Settings.bundle qui définit une valeur par défaut pour OperationMode :
- ainsi l'utilisateur peut changer le mode de fonctionnement par l'application Préférences (mon bidule est un peut rustre pour l'instant, l'utilisateur doit arrêter et relancer l'application pour que le changement soit effectif)
- ce Settings.bundle est absent de ma Target Delivery, qui sert pour la publication de l'application