Dealing with sensitive variables in Flutter and Travis CI

Thomas Gallinari
4 min readJul 23, 2020
“Look right here”

Hello and welcome to this new article of the Journey to Flutter series!

At Intent Technologies, we rely on several third-party services (Algolia, Sentry, Segment,…) which most of the time require some secret API key or application ID to authenticate.

While we can store these keys on our own machines when we build the project locally, it can be a bit tricky when we need to build on Travis CI. We do not want to take the risk of committing these sensitive, private, secret keys to our GitHub repository for Travis CI to get them. So what solutions do we have?

Define variables

Since Flutter 1.17 we are now able to pass global variables to the Flutter command line with --dart-define. This is good news because it means we can now pass sensitive variables at build time without relying on any embedded configuration file. These variables can be retrieved with String.fromEnvironment('var_name'). Obviously it would be cumbersome to pass our variables manually every time we build, so let’s write them to a local file — which we will never commit to our repository of course.

Then cat dev.conf | xargs flutter build. This way we pass the arguments we just defined to the Flutter command line. We can also keep different configuration files for each environment we need to build for.

Warning! On iOS these variables are copied to the .xcconfig file, which does not accept double slashes (they are interpreted as a comment). That means you cannot store a whole URL with --dart-define ; as a workaround you can just store the part after https:// and add it afterwards in your code.

Make it work on Travis CI

As we told before, we cannot just commit our configuration files so Travis CI can read them, because we want to keep our secret variables… well, secret.

However, Travis CI (and most of the other CI platforms out there) allows to define secret environment variables. Let’s use this:

As you can see, Travis CI allows us to define the same variable with different values depending on the branch. This is very useful when you have separate branches to build for different environments.

Now we need to write a new configuration file, that will read these environment variables and pass them to the Flutter CLI:

However, it will not work to cat the file anymore because it will just print the variable names; we need to replace them with their actual values, so we need to eval the variables:

eval echo `<travis.conf` | xargs flutter build

Note: This is a bash syntax, so if you need to embed it to a script, do not forget #!/bin/bash as first line.

To sum it up

Legend!

In the end we should have:

  • 1 configuration file per environment for local builds; we must not commit them so do not forget to add them to .gitignore.
  • 1 configuration file for Travis CI; we need to commit this one, but it is safe as it does not contain any value. The values should be stored in hidden environment variables on Travis CI.
  • In both cases we can pass the variables to Flutter with eval echo `<file.conf` | xargs flutter ... and read them from Dart with String.fromEnvironment('xxx').

Another solution for local builds could be to use the same configuration file as for Travis CI, and export the environment variables before the build with some script. It is up to you and your team to chose a solution you are comfortable with, please let me know if you have come to a different solution!

--

--