How we customise and deliver on-demand our native mobile app templates automatically with Fastlane and Jenkins

Dong Mai
Altitude
Published in
9 min readFeb 2, 2022

Introduction

In this article I want to share how we implement a solution that helps us customize on demand our native Altitude Guest app templates (A smart hotel in your guests’ pocket) without writing a line of code, and then deliver it to customers.

Some of you may have heard about “Print on demand”, it’s where you can go to custom a T-Shirt, a Mug, or a Blanket, you can upload your images here, change some text … once its done you can buy it through the checkout process. And after some days the item will be delivered to you looking exactly as same as your customization.

We want the same for our app templates. Imagine there is a webpage where you can customize an app, including the icon, styles, text color, turn on/off features, or change the app’s language. Then when you’re happy, with a click of a button, it will start building your app and notify you via email that it is ready to install on your devices.

What problem does this solve?

Below are three versions of the Altitude Guest app, it is a white label app that we can adjust configurations and styles and deliver different apps depending on customer needs from single source code.

Example apps with different colors, styles and icons

The current process

First we made our apps code-base support templates and each time a new customer on-boards our customer success team and developers have to complete the manual tasks as below:

  • Setup a new target for the customer and clone template files from existing targets
  • Update app configuration file (a JSON file that configures functionalities in the app, for example customer A might need feature X but customer B does not need it)
  • Update localization (we support multiple translations, plus allows a customer to set their preferred marketing languages, e.g. Stay vs Reservation. As well as cross industries: Student Accommodation vs Hotels)
  • Update images (for example; splash screen, logos, app icon, etc.)
  • Update app styles (a JSON file that styles the app — all elements style in app features, including button colors, header/text colors, shadows, corner radius and more)
  • Additional configuration and third party setup (like social logins, OS specific setup, push notifications and more)
  • Test app
  • Deliver apps to customers (for beta testing and store release)
The problem: Many manual tasks

The solution

Automation is the key to time and cost saving. Our web services already implement many levels of continuous deployment — why should our apps not.

Building automation tools saves time on setting up new customers but will also allow us to give potential and new customers a web page to configure their apps and click “Build My App” and all steps above are done automatically. As well as allow us and customers to update apps very simply.

Expected result after applying the solution

Main Components

1. The Web UI
The font-end part that will works directly with customers to collect their requirement, it will have one service as its backend.

Here customers will customize the app as they need, we will list out what can be customized like app template (set of colors, style), localization's for display items, and more. The interface will also later include a web render of what their app will look like.

2. The App Generation Service
When users manipulate their apps on web UI we need a service to store the data for later use in the build process, plus it will have to communicate with the build machine for builds and keep track on build status/history (here we used Typescript for development).

The service is a series of CURD APIs and additional calls to 3rd party services (e.g. Firebase, Apple, Graph Facebook APIs, Google, etc.).

3. Build machine with CI/CD tool
The service itself cannot build and deliver apps (e.g. Apple OS can only build iPhone apps) so we need a build machine, here we use a Mac Mini (M1) that has an internet connection (can consider it as a Mac server) and it has Jenkins installed.

The Mac is set up in a way so the App Generation Service is able to communicate with Jenkins (securely) to tell it to do tasks as creating a job or triggering a build etc. Fortunately, Jenkins provides a Remote Access API as well, as well as a NodeJS API wrapper since we are writing the service in TypeScript.

4. A tool that helps to do manually tasks automatically
As mentioned above our developers have to complete manual tasks when we have a new customer; here we have fastlane come to the rescue: “fastlane is an open source platform aimed at simplifying Android and iOS deployment. fastlane lets you automate every aspect of your development and release workflow”, see: https://fastlane.tools.

With fastlane we can write custom functions in its script (Fastfile) to help to do all those tasks that developers have to do manually before building progress starts.

Automation tasks we need to deal with

1. Auto configure app on Firebase console on the service
In the app we provide Google login functionality, Firebase crashlytics and Firebase push notifications. So we have to manually configure for it on Firebase console every time we build new app for a new customer.

To automate this we use Firebase Management API. We integrate the API with help of firebase-admin library, for detail on how setting it up please take a look at https://firebase.google.com/docs/admin/setup.

Bellow are those APIs that I used:

  • Create iOS app: projects.iosApps.create
  • Create Android App: projects.androidApps.create
  • Get operation detail: operations.get when creating app (iOS/Android) it will return an operation name - you will use this name for the API. The API returns content of config file in base64 that when decoding will be the GoogleService-Info.plist if app is iOS and Google-Services.json if app is Android. You need to save those Base64 in database to update it in projects via fastlane script

Note, you still manually need to create a Firebase project on Firebase console and make an account service key and give it to the service so it can be able to authenticate with Firebase Management API and do things for you.

2. Auto configure Facebook logins on the service
Our app also provides Facebook login and if you’re mobile developers you should be familiar with it that any time you setup for new app you have to go Facebook Developer site to create a new one and configure it.

But there is an other way to do it via Graph API provided by Facebook, below are those ones that I used:

We can’t create new applications via the API so we create a set of Facebook applications before hand, then use those ones to configure for new app that customer requests — because once we have Facebook app we can give the service it’s appID and secret that are two parameters need for generating app access token.

3. Manage Jenkins job and build via API
The service will communicate with Jenkins via its provided APIs to create jobs and trigger builds, we’ll create a job per customer app.

To make it easy we have created template jobs here with necessary setup including git repository, execute scripts, placeholder environment variables that we can easily replace when creating the job from service side.

Job templates

Here I use copy_job function from the jenkins-api library, but first you will need an API token to call the api.

While building is in progress we also need to keep track of build status so from the service we provide an API (PUT /jenkins-job/jobId/updateLatestBuild) and fastlane can consume it to update latest build status — there are build statuses we’re using: scheduled, running, finished, cancelled and paused.

4. Fastlane helps do manual tasks
Fastlane script — fastfile — is ruby so we can do with a custom ruby function. Additionally, fastlane also provides a list of ready-to-use plugins and actions you can pick the ones suite your needs.

As mentioned above currently we have to setup a new target on iOS project or flavor in Android project for any new customers and clone template files from existing targets/flavors (of old customers) then update those files to match new requirements. To make it easy for fastlane we have made a placeholder target/flavor that have already have any template files it needs, and fastlane’s tasks are just updating files and configuring project no need to create any new files.

4.1. Pull template data via API
Firstly fastlane need to pull the template data for the app via the service, I wrote a custom function to get it and class using here is NET::HTTP. Its quite simple like you do api calls in other client languages as Swift, Java … .

function definition
using in fastfile

4.2. Change app name and bundle ID/package name
For iOS we use update_info_plist action

For Android we use android_change_string_app_name plugin to change app name, and for package name I’ve to write a custom function to parse build.gradle file and update applicationId field

4.3. change app icon
All images the server will return as urls so we need a way to download them first before handling — here we use down tool for it. To be able to use it you need add gem "down" in the Gemfile

for iOS we use appicon plugin:

for Android we use android_appicon plugin:

4.4. Change app images
Change other images is quite simple as it’s just replacing file, I wrote a function for it so can replace one by one with ease:

4.5. change app localizations and other files by replacing
The service will return localization files in platform-specific format so again it’s just a simple replacing files

and for other files like app configuration (json), GoogleService-info.plist, Google-Service.json we just need to replace it with contents returned by server

4.6. Configure Facebook/Google logins
For iOS we have to update plist file to add FacebookAppID and URL Schemes to make Facebook/Google logins working like bellow screenshot:

so I’ve to write custom functions to modify the plist file:

For Android I need to update config_string.xml file:

Finally, we’ve done all manually tasks with help of fastlane scripts, now let’s move on delivering apps…

5. Deliver app
For iOS side we use TF to deliver the app, but due to App Store limitation we couldn’t setup new apps 100% automatically via App Store Connect API, as to setup new app ready for TF we need two steps:
- Setup new app identifier on Apple developer site (1)
- Setup the new app on App store connect (2)

with App store connect API we can just do (1) so only got half the job done, finally we come to a solution that we made before hand a list of apps here as placeholders, we’ll pick one by one to deliver the app.

Additionally, we also provide an option to deliver the app to customer’s Apple account, this option will require customers to do some manually steps:
- Provide us API key with developer role
- Setup the new app on both Apple developer and App store connect

For Android, its much simpler for deploying beta testing app, we just upload it on AWS S3 then its done, and you can use s3 action for it.

Conclusion

Huge time savings means we can relay the cost savings to our customers.

Automation within Jenkins allows us to do a lot of very exciting things — automation, auto-review code, alerts, tests, and more!

The future of our Altitude Apps include new and exciting products and our DevOps solutions will ensure we can continue to innovate with our applications and services.

--

--