ios 如何在 Xcode 中配置独立的运行时设置集

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10497552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:17:10  来源:igfitidea点击:

How to configure independent sets of runtime settings in Xcode

iphoneiosxcodeconfigurationruntime

提问by Greg

My iPhone application connects to three different servers, say: production, stagingand testing. There is a bunch of configuration values that the application uses depending on to which server it connects to, e.g. Facebook App ID, TestFlight team key, etc.

我的iPhone应用程序连接到三个不同的服务器上,说:生产分期测试。应用程序使用的配置值取决于它连接到的服务器,例如 Facebook 应用程序 ID、TestFlight 团队密钥等。

I'd like to have all the settings in GIT and only select which configuration the application supposed to use when compiling or releasing. For example, when testingis selected, Product -> Runin Xcode runs the debug version of the app connecting to testing, and Product -> Archivecreates the IPA file with the release version that also connects to testing.

我想在 GIT 中拥有所有设置,并且只选择应用程序在编译或发布时应该使用的配置。For example, when testingis selected, Product -> Runin Xcode runs the debug version of the app connecting to testing, and Product -> Archivecreates the IPA file with the release version that also connects to testing.

I don't want to create more build configurations than debug and release (because that would mean 6 different combinations of build configurations/run-time configurations). The ideal solution, as I see it, would be that I have three schemes: production, testingand staging, and each scheme selects one of three Info.plist files to use with the application. That would allow me to not only define different run-time settings, but also different application versions or bundle identifiers depending on the back-end server. But it doesn't look like I can configure the Archive action in any other way apart from selecting a different build configuration. Any ideas if that could be achieved in any way?

我不想创建比调试和发布更多的构建配置(因为这意味着构建配置/运行时配置的 6 种不同组合)。在我看来,理想的解决方案是我有三个方案:productiontestingstaging,每个方案选择三个 Info.plist 文件之一与应用程序一起使用。这将使我不仅可以定义不同的运行时设置,还可以根据后端服务器定义不同的应用程序版本或包标识符。但是,除了选择不同的构建配置之外,我似乎无法以任何其他方式配置存档操作。如果可以以任何方式实现,有什么想法吗?

Edit:To make it a bit more clear, production/staging/testingis the back-end server, not the version of the iOS application. The iOS app comes in two versions: debug/release. In other words I may want to run a debugversion of the application connecting to the productionserver for example to debug a crash caused by JSON returned from that server. I could have named the servers as A, B and C for the sake of clarity.

编辑:为了更清楚一点,生产/登台/测试是后端服务器,而不是 iOS 应用程序的版本。iOS 应用程序有两个版本:debug/release。换句话说,我可能想要运行连接到生产服务器的应用程序的调试版本,例如调试由从该服务器返回的 JSON 导致的崩溃。为了清楚起见,我可以将服务器命名为 A、B 和 C。

采纳答案by adig

I would suggest using different build targets for each environment. I successfully used this model before. In your project's settings you can duplicate the current target and change the build settings as needed. There's an Info.plist Fileproperty that will let you change the default plist for that target.

我建议为每个环境使用不同的构建目标。我之前成功使用过这个模型。在您的项目设置中,您可以复制当前目标并根据需要更改构建设置。有一个Info.plist File属性可以让您更改该目标的默认 plist。

After that, you can create a scheme for each environment that will use the according target.

之后,您可以为将使用相应目标的每个环境创建一个方案。

You can get a step further and use different bundle id for each target and different names. That will allow you to install both the staging and the production builds on the same device for example.

您可以更进一步,为每个目标和不同的名称使用不同的包 ID。例如,这将允许您在同一设备上安装暂存和生产版本。

The only downside in this is that you have more work when you want to update provisioning profiles.

在这唯一的缺点是,你有更多的工作,当你想更新预置描述文件。

回答by Mike Weller

A good way to do this would be with build configurations and C macros. This avoids having to create a separate target for every configuration which is not really the correct use of targets.

一个很好的方法是使用构建配置和 C 宏。这避免了创建一个单独的目标,每一个配置,它不是真正的正确使用的目标。

First you want to set up the configurations at the project level:

首先,您要在项目级别设置配置:

enter image description here

在此处输入图片说明

You can create different configurations for debugging, enterprise distribution, and any other type of special build you want.

您可以创建调试,企业分布,以及任何其他类型的你想要特别打造的不同配置。

Next you can define some macro flags for each configuration which will be passed to the compiler. You can then check for these flags at compile time. Find the "Preprocessor flags" build setting at the target level:

接下来,您可以为将传递给编译器的每个配置定义一些宏标志。然后,您可以检查这些标志在编译时。在目标级别找到“预处理器标志”构建设置:

enter image description here

在此处输入图片说明

If you expand the triangle you can define different values for each of your configurations. You can define KEY=VALUEor just KEYmacros here.

如果您展开三角形,您可以为每个配置定义不同的值。您可以在此处定义KEY=VALUE或仅定义KEY宏。

enter image description here

在此处输入图片说明

In your code, you can check for the existance of these macros, or their value (if there is one). For example:

在您的代码中,您可以检查这些宏是否存在,或者它们的值(如果有的话)。例如:

#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

You can pass in string values as well, which must be wrapped with single quotes in the build setting, e.g. DEFAULT_LOCALIZATION_NAME='@"en"'.

您也可以传入字符串值,这些值必须在构建设置中用单引号括起来,例如DEFAULT_LOCALIZATION_NAME='@"en"'.

You can also configure which configuration is used during Debug and Archive time using the Schemes editor. If you choose "Run" or "Archive" in the Schemes editor you can select the appropriate configuration.

您还可以使用 Schemes 编辑器配置在调试和存档期间使用的配置。如果您在方案编辑器中选择“运行”或“存档”,您可以选择适当的配置。

enter image description here

在此处输入图片说明

If you need to parameterize entries in the Info.plist file, you can define their value using a custom build setting. Add a custom build setting for your target:

如果您需要参数化 Info.plist 文件中的条目,您可以使用自定义构建设置来定义它们的值。为您的目标添加自定义构建设置:

enter image description here

在此处输入图片说明

And then give it an appropriate value for your different configurations:

然后为您的不同配置赋予适当的值:

enter image description here

在此处输入图片说明

Then in the Info.plist file you can reference this setting:

然后在 Info.plist 文件中,您可以引用此设置:

enter image description here

在此处输入图片说明

Note that the one limitation of this approach is that you cannot change the following items:

请注意,此方法的一个限制是您无法更改以下项目:

  • Settings.bundle
  • 设置.bundle

Additionally, in older versions of Xcode without asset catalog support, you cannot change the following items:

此外,在没有资产目录支持的旧版 Xcode 中,您无法更改以下项目:

  • Icon.png
  • Default.png
  • 图标.png
  • 默认.png

These cannot be explicitly defined in the Info.plist file or anywhere else, which means you need different targets to change them.

这些不能在 Info.plist 文件或其他任何地方明确定义,这意味着您需要不同的目标来更改它们。

Hope this helps.

希望这可以帮助。

回答by Nycen

Here's a much easier solution if the concerned libs allow to set the keys in code, meaning that you can have production value in your plist file, but change them in your AppDelegate (or whichever file they are first used in).

如果相关的库允许在代码中设置键,那么这是一个更简单的解决方案,这意味着您可以在 plist 文件中具有生产价值,但在 AppDelegate(或它们首次使用的任何文件)中更改它们。

Works with facebook, twitter and google sdk at the moment.

目前可与 facebook、twitter 和 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

Same in Swift, just use #if instead of #ifdef.

在 Swift 中也是如此,只需使用 #if 而不是 #ifdef。

Note about FacebookThis worked with version 3 of their SDK, I'm not sure it's possible with later versions.

关于 Facebook这适用于他们 SDK 的第 3 版,我不确定以后的版本是否可行。

回答by Dan

It is probably very low tech but I just have a method called apiURL()that returns the URL of the API I want. I have localhost, stage, and production and I simply uncomment the one I want. It's worked well for me so far. I've only forgotten to switch it back a few times. Oops.

它的技术可能非常低,但我只有一个调用的方法apiURL()可以返回我想要的 API 的 URL。我有本地主机、舞台和制作,我只是取消注释我想要的那个。到目前为止,它对我来说效果很好。我只是忘记把它切换回来几次。哎呀。