it-swarm.com.de

So konfigurieren Sie unabhängige Laufzeiteinstellungen in XCode

Meine iPhone-Anwendung stellt eine Verbindung zu drei verschiedenen Servern her, beispielsweise: Produktion , Staging und Testen . Es gibt eine Reihe von Konfigurationswerten, die die Anwendung verwendet, abhängig davon, zu welchem ​​Server sie eine Verbindung herstellt, z. Facebook-App-ID, TestFlight-Teamschlüssel usw.

Ich möchte alle Einstellungen in GIT haben und nur auswählen, welche Konfiguration die Anwendung beim Kompilieren oder Freigeben verwenden soll. Wenn beispielsweise testing ausgewählt ist, führt Product -> Run in XCode die Debugversion der App aus, die eine Verbindung zu testing herstellt, und Product -> Archive erstellt die IPA-Datei mit der Release-Version, die auch eine Verbindung zu testing herstellt.

Ich möchte nicht mehr Build-Konfigurationen als Debug und Release erstellen (da dies 6 verschiedene Kombinationen von Build-Konfigurationen/Laufzeit-Konfigurationen bedeuten würde). Die ideale Lösung, so wie ich es sehe, wäre, dass ich drei Schemas habe: production , testing und staging , und jedes Schema wählt eine der drei Info.plist-Dateien aus, die mit der verwendet werden sollen Anwendung. Dies würde mir erlauben, nicht nur verschiedene Laufzeiteinstellungen zu definieren, sondern auch unterschiedliche Anwendungsversionen oder Paketkennungen, abhängig vom Back-End-Server. Es sieht jedoch nicht so aus, als könnte ich die Archivierungsaktion anders konfigurieren, außer eine andere Build-Konfiguration auszuwählen. Irgendwelche Ideen, wenn dies auf irgendeine Weise erreicht werden könnte?

Edit: Um es etwas klarer zu machen: production/staging/testing ist der Back-End-Server und nicht die Version der iOS-Anwendung. Die iOS-App gibt es in zwei Versionen: debug/release . Mit anderen Worten, ich möchte möglicherweise eine debug - Version der Anwendung ausführen, die eine Verbindung zum production -Server herstellt, um beispielsweise einen Absturz zu debuggen, der durch von diesem Server zurückgegebenes JSON verursacht wird. Ich hätte die Server aus Gründen der Übersichtlichkeit als A, B und C bezeichnen können.

57
Amiramix

Ich würde vorschlagen, für jede Umgebung unterschiedliche Build-Ziele zu verwenden. Ich habe dieses Modell bereits erfolgreich verwendet. In den Projekteinstellungen können Sie das aktuelle Ziel duplizieren und die Build-Einstellungen nach Bedarf ändern. Es gibt eine Info.plist File-Eigenschaft, mit der Sie die Standard-Plist für dieses Ziel ändern können. 

Danach können Sie für jede Umgebung ein Schema erstellen, in dem das entsprechende Ziel verwendet wird. 

Sie können einen Schritt weitergehen und für jedes Ziel eine andere Bundle-ID und unterschiedliche Namen verwenden. Auf diese Weise können Sie z. B. sowohl die Bereitstellung als auch die Produktionsumgebung auf demselben Gerät installieren. 

Der einzige Nachteil ist, dass Sie mehr Arbeit haben, wenn Sie die Bereitstellungsprofile aktualisieren möchten. 

10
adig

Ein guter Weg, dies zu tun, wäre mit Build-Konfigurationen und C-Makros. Dies vermeidet, dass für jede Konfiguration ein separates Ziel erstellt werden muss, bei dem es sich nicht um die korrekte Verwendung von Zielen handelt.

Zunächst möchten Sie die Konfigurationen auf Projektebene einrichten:

enter image description here

Sie können verschiedene Konfigurationen für das Debugging, die Unternehmensverteilung und jeden anderen speziellen Build-Typ erstellen.

Als Nächstes können Sie für jede Konfiguration einige Makroflags definieren, die an den Compiler übergeben werden. Sie können dann zur Kompilierzeit nach diesen Flags suchen. Suchen Sie auf der Zielebene die Buildeinstellung "Präprozessorflags":

enter image description here

Wenn Sie das Dreieck erweitern, können Sie für jede Ihrer Konfigurationen unterschiedliche Werte definieren. Sie können hier KEY=VALUE oder nur KEY Makros definieren.

enter image description here

In Ihrem Code können Sie prüfen, ob diese Makros vorhanden sind oder deren Wert (falls vorhanden). Zum Beispiel:

#ifdef DISABLE_FEATURE_X
    featureXButton.hidden = YES;
#endif

// ...

#if FOOBAR_VISIBLE == 0
    foobarView.hidden = YES;
#Elif FOOBAR_VISIBLE == 1
    foorbarView.hidden = NO;
#else
    #error Invalid value for FOOBAR_VISIBLE
#endif

Sie können auch Zeichenfolgewerte übergeben, die in der Build-Einstellung in einfache Anführungszeichen gesetzt werden müssen, z. DEFAULT_LOCALIZATION_NAME='@"en"'.

Sie können auch konfigurieren, welche Konfiguration während der Debug- und Archivierungszeit verwendet wird, indem Sie den Schema-Editor verwenden. Wenn Sie im Schema-Editor "Ausführen" oder "Archivieren" wählen, können Sie die entsprechende Konfiguration auswählen.

enter image description here

Wenn Sie Einträge in der Info.plist-Datei parametrisieren müssen, können Sie deren Wert mithilfe einer benutzerdefinierten Erstellungseinstellung definieren. Fügen Sie eine benutzerdefinierte Erstellungseinstellung für Ihr Ziel hinzu:

enter image description here

Und geben Sie dann einen angemessenen Wert für Ihre verschiedenen Konfigurationen:

enter image description here

In der Info.plist-Datei können Sie dann auf diese Einstellung verweisen:

enter image description here

Beachten Sie, dass die einzige Einschränkung dieser Vorgehensweise darin besteht, dass Sie die folgenden Elemente nicht ändern können:

  • Settings.bundle

Darüber hinaus können Sie in älteren Xcode-Versionen ohne Unterstützung des Asset-Katalogs folgende Elemente nicht ändern:

  • Icon.png
  • Default.png

Diese können nicht explizit in der Info.plist-Datei oder anderswo definiert werden. Sie benötigen daher unterschiedliche Ziele, um sie zu ändern.

Hoffe das hilft.

112
Mike Weller

Dies ist eine viel einfachere Lösung, wenn die betroffenen Bibliotheken das Festlegen der Schlüssel im Code zulassen. Dies bedeutet, dass Sie in Ihrer plist-Datei Produktionswerte haben können, sie jedoch in Ihrer AppDelegate (oder in welcher Datei sie zuerst verwendet werden) ändern können.

Arbeitet momentan mit Facebook, Twitter und Google SDK.

Ex:

#ifdef DEBUG
  // Facebook
  [FBSettings setDefaultAppID:@"SandboxID"];
  // Fabric / TwitterKit - must be called above [Fabric with:@[TwitterKit]];
  [[Twitter sharedInstance] startWithConsumerKey:@"SandboxKey" consumerSecret:@"SandboxIDSecret"];
#endif

Das Gleiche gilt für Swift. Verwenden Sie einfach #if anstelle von #ifdef.

Hinweis zu Facebook Dies funktionierte mit Version 3 ihres SDK. Ich bin mir nicht sicher, ob es mit späteren Versionen möglich ist.

2
Nycen

Es ist wahrscheinlich sehr wenig technisch, aber ich habe nur eine Methode namens apiURL(), die die URL der gewünschten API zurückgibt. Ich habe localhost, stage und production und ich entkomme einfach das, was ich will. Es hat bisher gut für mich funktioniert. Ich habe nur vergessen, es ein paar Mal zurückzuschalten. Hoppla.

0
Dan