58 votes

Comment configurer des ensembles de paramètres d'exécution indépendants dans Xcode

Mon application iPhone se connecte à trois serveurs différents, à savoir: production, staging et testing. Il y a tout un tas de valeurs de configuration que l'application utilise en fonction du serveur auquel elle se connecte, par exemple l'identifiant d'application Facebook, la clé d'équipe TestFlight, etc.

J'aimerais avoir tous les paramètres dans GIT et ne sélectionner que la configuration que l'application est censée utiliser lors de la compilation ou de la publication. Par exemple, lorsque l'option testing est sélectionnée, Produit -> Exécuter dans Xcode lance la version de débogage de l'application se connectant à testing, et Produit -> Archiver crée le fichier IPA avec la version de publication qui se connecte également à testing.

Je ne veux pas créer plus de configurations de construction que debug et release (car cela signifierait 6 combinaisons différentes de configurations de construction/configurations d'exécution). La solution idéale, telle que je la vois, serait que j'aie trois schémas: production, testing et staging, et que chaque schéma sélectionne l'un des trois fichiers Info.plist à utiliser avec l'application. Cela me permettrait non seulement de définir différents paramètres d'exécution, mais aussi différentes versions d'application ou des identifiants de bundle différents en fonction du serveur back-end. Cependant, il ne semble pas possible de configurer l'action Archive d'une autre manière que de sélectionner une configuration de construction différente. Des idées si cela pourrait être réalisé de quelque manière que ce soit?

Modifier: Pour être un peu plus clair, production/staging/testing est le serveur back-end, et non la version de l'application iOS. L'application iOS se présente en deux versions: debug/release. En d'autres termes, je peux vouloir exécuter une version debug de l'application se connectant au serveur production, par exemple pour déboguer un crash causé par du JSON renvoyé par ce serveur. J'aurais pu nommer les serveurs A, B et C pour des raisons de clarté.

0 votes

Bonjour @Amiramix, je sais que cette question a été posée il y a longtemps mais j'apprécierais si vous pouviez m'aider. J'ai le même problème. J'ai besoin d'un environnement de compilation différent. Et il devrait avoir un identifiant de bundle différent afin d'avoir une application séparée pour chaque environnement. Je veux juste changer quelques URL pour chaque environnement. Comment avez-vous résolu votre problème?

0 votes

Désolé, je ne pourrai pas vous aider car cela fait un moment que je n'utilise pas la nouvelle version de XCode. D'après ce dont je me souviens, je n'ai pas résolu ce problème en particulier, j'ai simplement créé quelques applications différentes partageant le même code mais avec une configuration différente se connectant à différents serveurs backend.

112voto

Mike Weller Points 28387

Une bonne façon de faire cela serait avec des configurations de build et des macros C. Cela évite d'avoir à créer une cible séparée pour chaque configuration, ce qui n'est pas vraiment l'utilisation correcte des cibles.

Tout d'abord, vous voulez configurer les configurations au niveau du projet:

saisir la description de l'image ici

Vous pouvez créer différentes configurations pour le débogage, la distribution d'entreprise, et tout autre type de build spécial que vous voulez.

Ensuite, vous pouvez définir des drapeaux macro pour chaque configuration qui seront transmis au compilateur. Vous pouvez ensuite vérifier ces drapeaux au moment de la compilation. Trouvez le paramètre de build "Drapeaux du préprocesseur" au niveau de la cible:

saisir la description de l'image ici

Si vous déployez le triangle, vous pouvez définir différentes valeurs pour chacune de vos configurations. Vous pouvez définir des macros CLÉ=VALEUR ou simplement des macros CLÉ ici.

saisir la description de l'image ici

Dans votre code, vous pouvez vérifier l'existence de ces macros, ou leur valeur (s'il y en a une). Par exemple:

#ifdef DÉSACTIVER_FONCTION_X
    featureXButton.hidden = YES;
#endif

// ...

#if FOOBAR_VISIBLE == 0
    foobarView.hidden = YES;
#elif FOOBAR_VISIBLE == 1
    foorbarView.hidden = NO;
else
    #error Valeur non valide pour FOOBAR_VISIBLE
#endif

Vous pouvez également passer des valeurs de chaîne, qui doivent être encapsulées entre guillemets simples dans le paramètre de build, par exemple NOM_LOCALISATION_PAR_DEFAUT='"en"'.

Vous pouvez également configurer quelle configuration est utilisée pendant le débogage et l'archivage en utilisant l'éditeur de schémas. Si vous choisissez "Exécuter" ou "Archiver" dans l'éditeur de schémas, vous pouvez sélectionner la configuration appropriée.

saisir la description de l'image ici

Si vous devez paramétrer des entrées dans le fichier Info.plist, vous pouvez définir leur valeur en utilisant un paramètre de build personnalisé. Ajoutez un paramètre de build personnalisé pour votre cible:

saisir la description de l'image ici

Et donnez-lui une valeur appropriée pour vos différentes configurations:

saisir la description de l'image ici

Ensuite, dans le fichier Info.plist, vous pouvez faire référence à ce paramètre:

saisir la description de l'image ici

Notez que la limite de cette approche est que vous ne pouvez pas changer les éléments suivants :

  • Settings.bundle

De plus, dans les anciennes versions de Xcode sans prise en charge du catalogue d'assets, vous ne pouvez pas changer les éléments suivants :

  • Icon.png
  • Default.png

Ces éléments ne peuvent pas être définis explicitement dans le fichier Info.plist ou ailleurs, ce qui signifie que vous avez besoin de différentes cibles pour les modifier.

1 votes

Ce n'est pas une bonne solution, car comme je l'ai dit, je devrais créer 6 configurations de création différentes : production débogage, production release, staging débogage, staging release, testing débogage, testing release. Ensuite, maintenir tous les commutateurs de configuration de création devient un cauchemar. Je ne suis pas non plus convaincu par votre argument selon lequel ajouter de nouvelles cibles est incorrect. Dans ce cas, vous proposez de créer de nouvelles configurations de génération pour sélectionner les paramètres d'exécution appropriés. Les configurations de génération sont pour la phase de génération, pas pour la phase d'exécution. Pourquoi cela devrait-il être une meilleure solution alors?

6 votes

Les configurations de build ont été conçues en ayant exactement ce cas d'utilisation à l'esprit. Vous avez différentes configurations de votre application, et vous pouvez choisir de modifier des paramètres spécifiques pour des configurations spécifiques. Je ne vois pas comment vous voulez parvenir à cela autrement. Et ajouter des cibles multiples est beaucoup plus complexe. Vous vous retrouvez avec des paramètres de configuration et des valeurs Info.plist dupliquées. Les six exemples que vous avez donnés sont également confus. "Production Debug" est un peu contradictoire.

1 votes

Production Debug signifie une version de débogage de l'application se connectant au serveur de production. Les configurations de build doivent être utilisées pour créer des paramètres de build distincts, par exemple débogage contre version finale. Il ne s'agit pas de construire fonctionnellement la même application se connectant à différents serveurs back-end. Il est plus logique de créer des cibles distinctes, par exemple une application se connectant à la production en tant que cible distinct de l'application se connectant à la mise en scène avec éventuellement un identifiant de bundle et une version différents (pour distinguer ces applications).

10voto

adig Points 2102

Je suggérerais d'utiliser des cibles de construction différentes pour chaque environnement. J'ai déjà utilisé avec succès ce modèle auparavant. Dans les paramètres de votre projet, vous pouvez dupliquer la cible actuelle et modifier les paramètres de construction selon vos besoins. Il y a une propriété Fichier Info.plist qui vous permettra de changer le plist par défaut pour cette cible.

Après cela, vous pouvez créer un schéma pour chaque environnement qui utilisera la cible correspondante.

Vous pouvez aller plus loin et utiliser des identifiants de bundle différents pour chaque cible et des noms différents. Cela vous permettra par exemple d'installer à la fois les constructions de staging et de production sur le même appareil.

Le seul inconvénient de cela est que vous aurez plus de travail lorsque vous voudrez mettre à jour les profils de provisioning.

21 votes

Les cibles ne devraient vraiment être utilisées que pour des produits distincts. Si vous créez le même produit conceptuel avec différentes configurations ou paramètres, l'utilisation des cibles n'est pas vraiment la meilleure solution.

3 votes

@MikeWeller Je tiens à vous contredire. Comme je l'ai dit, j'ai déjà utilisé cette technique sans aucun problème. Et vous n'avez évidemment pas mentionné les inconvénients ou une véritable alternative. Quel est l'intérêt de votre commentaire ?

2 votes

Les cibles sont une meilleure idée pour séparer les constructions de test car vous pouvez avoir des AppID différents, ce qui vous permet de les exécuter aux côtés des constructions de production.

2voto

user229688 Points 1393

Voici une solution beaucoup plus simple si les bibliothèques concernées permettent de définir les clés dans le code, ce qui signifie que vous pouvez avoir une valeur de production dans votre fichier plist, mais les modifier dans votre AppDelegate (ou tout autre fichier où elles sont utilisées en premier).

Fonctionne avec les SDK Facebook, Twitter et Google pour le moment.

Ex :

#ifdef DEBUG
  // Facebook
  [FBSettings setDefaultAppID:@"SandboxID"];
  // Fabric / TwitterKit - doit être appelé avant [Fabric with:@[TwitterKit]];
  [[Twitter sharedInstance] startWithConsumerKey:@"SandboxKey" consumerSecret:@"SandboxIDSecret"];
#endif

La même chose en Swift, il suffit d'utiliser #if à la place de #ifdef.

Note à propos de Facebook Cela fonctionnait avec la version 3 de leur SDK, je ne suis pas sûr que ce soit possible avec les versions ultérieures.

0voto

Dan Points 579

C'est probablement très basique mais j'ai juste une méthode appelée apiURL() qui retourne l'URL de l'API que je veux. J'ai localhost, stage et production et je décommente simplement celui que je veux. Ça a bien fonctionné pour moi jusqu'à présent. J'ai juste oublié de le changer quelques fois. Oops.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X