6

I have an API key defined on my CI/CD platform like so:

export API_KEY="XXXXXXXXXX"

Is there a way I can somehow compile this variable with my build so that I can reference it in Swift and not have to worry about the variable being defined in the binary's environment at runtime? I can't use ProcessInfo.processInfo.environment obviously, because the API key is only defined in my CI/CD environment. I want to have my binary compiled with the key so that when I distribute my app the key is available to use.

My use case is that I want to avoid putting an API key in my git repository, and instead fetch it from the CI/CD platform when the build is generated. If there is a way to inject an environment variable that then gets compiled as part of the binary, that would be ideal.

sschilli
  • 2,021
  • 1
  • 13
  • 33
  • Not really. One way or another, your app has to have it (in order to be able to transmit it to the API) – Alexander Nov 05 '19 at 18:49
  • @Alexander you might be misunderstanding my request. I know my app has to have the API key somehow; I am not trying to avoid that. I just want to grab it from an environment variable when the app is built and have it compiled with the app if that is possible. – sschilli Nov 05 '19 at 19:29
  • IDK about your CI platform, but at the worst, you can make a script that reads the CI env var, and stores it into a place that's accessible to your app. But "not have to worry about the variable being defined in the binary's environment at runtime" isn't possible. – Alexander Nov 05 '19 at 19:38
  • @Alexander Just to be clear, when I say "binary's environment" I mean I don't want to define an environment variable from the binary's running directory (as I have no control over the environment variables present when the app is distributed, and do not want the API key stored in our git repository). For example, if I could somehow inject an environment variable into a Swift config class of some sort that gets compiled as part of the binary, that would be an ideal solution. – sschilli Nov 05 '19 at 20:14
  • Your script could inject the api key into a place holder of a Swift class, like Sombre's answer shows. You could also just write it to an plist/xml/json/yaml/whatever file that will be bundled into your app, and read it from there at runtime. – Alexander Nov 06 '19 at 00:07
  • @sschilli did you figured out how to pass data from Jenkins to Xcode? I also want to achieve the same. can you please help me out – Shruti Jan 29 '21 at 09:39

1 Answers1

4

You can do a pre-action script in Xcode build section Xcode pre-action build

Which will modify placeholder with the following code:

let apiKey : String = "<# THE_API_KEY #>"

Modify the code directly in the source file

Before each build.

And you can add another one if you have a production key in the Archive pre-action

Exemple

place the apiKey variable in the file you want to access it

In Pre-action do a script to remplace a place holder text like THE_API_KEY

The script will look like this

 cat $PROJECT/$PATH_TO_FILE | sed 's/THE_API_KEY/YOUR_KEY' > $PROJECT/$PATH_TO_FILE

Don't forget to clean the code to avoid put the API key in you commit

With a Post-action

cat $PROJECT/$PATH_TO_FILE | sed 's/YOUR_KEY/THE_API_KEY' > $PROJECT/$PATH_TO_FILE
Sombre Osmo'z
  • 165
  • 1
  • 8
  • Would this enable me to reference `apiKey` in my other source files? I have a specific class in my application that handles API initialization which needs access to that API variable. It doesn't seem like the pre-action variable is globally scoped though, and thus not accessible in my other source files. – sschilli Nov 05 '19 at 20:02
  • The `apiKey` is a global variable so you decide which access control you give it – Sombre Osmo'z Nov 05 '19 at 20:27
  • Your script will modify the swift file where the variable is written, with the `$PROJECTDIR` Xcode variables – Sombre Osmo'z Nov 05 '19 at 20:29
  • Variables that have a scope global/internal are accessible in all target source file If you want to restrict to a file use `fileprivate` – Sombre Osmo'z Nov 05 '19 at 20:31
  • 1
    I am unclear about the usage you provided. Does the `let apiKey : String = "<# THE_API_KEY #>"` go in the pre-action run script? Or in the source file where I want to use it? Also, I have never seen the `<# #>` syntax before and didn't find it described anywhere in the Swift documentation, what does it do? It clearly has some special meaning and Xcode formats it differently when you type it, but I don't see it documented anywhere – sschilli Nov 05 '19 at 20:33
  • I think maybe you included the wrong screenshot that does not have the pre-action script contents – sschilli Nov 05 '19 at 20:37
  • The `apiKey` variables goes where you want to use it – Sombre Osmo'z Nov 05 '19 at 20:41
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201901/discussion-between-sombre-osmoz-and-sschilli). – Sombre Osmo'z Nov 05 '19 at 20:41
  • the pre script you mentioned is way to complicated to be shoved into 1 line. – CDM social medias in bio Nov 29 '21 at 19:22