Manually Generate apk using Github Actions
Tags: github, actions, cicd, android
Published: 2021-01-03 07:02:05

---
title: Manually Generate apk using Github Actions
published: true
description: In this blog, we will talk about how we can solve above problems by manually generating APK using Github actions
tags: github,actions,cicd,android
cover_image: http://burhanrashid52.com/wp-content/uploads/2020/11/danist-8Gg2Ne_uTcM-unsplash-940x510.jpg
---

For more visibility posting this on dev.to. The [original](http://burhanrashid52.com/2020/11/28/manually-generate-apk-using-github-actions/) article is posted on my [website](http://burhanrashid52.com). Let's get started :)

Have you been in a situation where you want to test a feature from a specific branch? But you don't have an environment set up in the local? Or you are out somewhere and don't have access to your PC? Or your client/QA is pinging you all the time to provide APK with specific configuration and features?

In this blog, we will talk about how we can solve above problems by manually generating APK using Github actions. So Let's get started.

# Prerequisite

1. [Github actions.](https://wkrzywiec.medium.com/github-actions-for-android-first-approach-f616c24aa0f9) 
2. Basic understanding of android build using [gradle](https://developer.android.com/studio/build/building-cmdline).
3. Basic of [bash](https://www.taniarascia.com/how-to-create-and-use-bash-scripts/) scripting.

# What problem we are trying to solve?

The problem might differ based on your working environment, team size, and clients. Let's try to understand each of them.

1. Indie Developer: 
    - If you are an Indie developer working solely on the project, then you might be overwhelmed by this approach. The reason might be
        1. Fewer dependencies of people on you. 
        2. You have the environment set up in your local. 
        3. No one asking for the APK to test on daily basis.
    - You can skip this whole article. But it's good to be aware of this approach because eventually, your team size will grow, and you need be well prepared for it.
2. Setting up the environment:
    - Let say our non-technical client wants to test a feature on the stagging environment which we have pushed to a specific branch. There are two solutions to this.
        1. Call the developer and ask for the apk with the required parameters.
        2. Setup the android environment in the client local machine, check out the branch, tweak the parameters, and build the apk. (I don't think a non-technical client will like this solution)
    - We can avoid this by providing a GUI to build the apk with configurable parameters. That's exactly what run workflow UI does. (More on this next section)
    - The same problem mention above can be applied to QA as well. The major difference is QA is technically sound. They can get the apk by using GitHub trigger like push, pull_request, etc. The problem here is why to create this unnecessary push and pull request trigger to just generate apk. It will clutter the git history and unnecessary PR requests.
3. Configurability :
    - The ability to build apk with configured parameters is something I find very useful. The most common parameters we configure in apps are.
        1. API Endpoints
        2. Secret/Access Keys.
        3. Other business based params like Threshold values, Number of Re attempts. etc.

# How do we solve this problem ?

Github Actions provides various trigger events to run your workflow. Following is an example of some of the trigger events, like pushing a commit on the main branch, creating pull requests, tags, etc.

```yaml
on:
  # Trigger the workflow on push or pull request,
  # but only for the main branch
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

	branches:    
      # Push events on main branch
      - main
      # Push events to branches matching refs/heads/mona/octocat
      - 'mona/octocat'
      # Push events to branches matching refs/heads/releases/10
      - 'releases/**'

	tags:        
      - v1             # Push events to v1 tag
      - v1.*

```

To trigger an event manually, Github actions have added a new trigger event called workflow_dispatch. Below is the sample code and UI. (More in the next section)

```yaml
on: 
  workflow_dispatch:
    inputs:
      logLevel:
        description: 'Log level'     
        required: true
        default: 'warning'
      tags:
        description: 'Test scenario tags' 
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wbnxscjfwlwo9d7gerf7.png)

# Setup

First we need to setup a configurable parameters in android and then we can update those params using GitHub inputs in the workflow. So will start with android first.

## Configurable properties in android.

1. We need to set up the configurable parameters in a file. In this case, we are putting this into `local.properties` file, which we usually **do not check-in** VCS.
**Note:** It can be any file. We just to point to that file in `build.gradle`.
2. Create or update the `local.properties` file like [this](https://github.com/burhanrashid52/SampleWorkflow/blob/update_existing_properties/local.properties).

    ```yaml
    BASE_URL="https://production.example.com/api/v1"
    MAP_KEY="production_sample_key"
    RETRY_ATTEMPTS=3
    THRESHOLD_VALUE=0.05
    ```

3. Update `build.gradle` in the app like [this](https://github.com/burhanrashid52/SampleWorkflow/blob/main/app/build.gradle#L6).

    ```groovy
    def localProperties = new Properties()
    localProperties.load(new FileInputStream(rootProject.file("local.properties")))

    android {

        defaultConfig {
            //...
            buildConfigField("String", "APP_BASE_URL", localProperties['BASE_URL'])
            buildConfigField("int", "APP_RETRY_ATTEMPTS", localProperties['RETRY_ATTEMPTS'])
            buildConfigField("float", "APP_THRESHOLD_VALUE", localProperties['THRESHOLD_VALUE'])
        }

        buildTypes {
            debug {
                resValue("string", "maps_key", localProperties['MAP_KEY'])
            }
            release {
               //..
            }
        }
    }
    ```

4. We can refer local properties using `BuildConfig` in this app like this.

    ```kotlin
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            val txtConfig = findViewById<TextView>(R.id.txtConfig)

            val configText = """
                BASE URL :  ${BuildConfig.APP_BASE_URL}
                MAP_KEY :  ${getString(R.string.maps_key)}
                RE-ATTEMPT :  ${BuildConfig.APP_RETRY_ATTEMPTS}
                THRESHOLD VALUE :  ${BuildConfig.APP_THRESHOLD_VALUE}
            """.trimIndent()

            txtConfig.text = configText
        }
    }
    ```

    **Note:** Sometimes the `local.properties` do not create `BuildConfig` on sync. It will get generated when we build the apk. [Ref](https://stackoverflow.com/a/60430117/5301119)

5. The output will look like this when we run the apk.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u57ooxsrgaij3yhmk3ld.png)

If you are facing any issues. You can check out the sample workflow app [here](https://github.com/burhanrashid52/SampleWorkflow/). For setting the [local.properties](http://local.properties) please checkout this [mindork](https://blog.mindorks.com/using-local-properties-file-to-avoid-api-keys-check-in-into-version-control-system) blog.

## Setup Github workflow

We create yaml file inside `.github/workflow` folder. To trigger the workflow manually we will use `workflow_dispatch` as a trigger. This will show the Run Workflow UI which we have seen above.

```yaml
name: Manual Generate APK
on:
  workflow_dispatch:
    /....
```

To show the input config values, we use inputs here. The `baseUrl` is an input key which we will use to read the value.

```yaml
name: Manual Generate APK
on:
  workflow_dispatch:
    inputs:

      baseUrl:
        description: 'Base URL'
        required: true
        default: 'https://production.example.com/api/v1'

      mapKey:
        description: 'Map Key'
        required: true
        default: 'production_sample_key'

      reAttempt:
        description: 'Number of re-attempts'
        default: '3'

      thresholdValue:
        description: 'Threshold value'
        default: '0.05'
```

Setting `required` params as `true` show an asterisk indicating a mandatory field. The `description` is shown as the field name in the UI. The `default` param will set the default value in the input field.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/klr3o8lr8n9jh06o1jot.png)

We will add command to build the apk.

```yaml
- name: Assemble app debug APK
  run: bash ./gradlew assembleDebug --stacktrace
```

### Setting up bash script

If we try to run this workflow now, it will fail with error [local.properties](http://local.properties) not found. This is because we have not checked-in that file in our VCS. We can fix this by creating local.properties on the fly while running the github workflow. We can do this by running the linux command in the workflow which creates `local.properties` file with all config values. 

It's a better to wrap this sequence of linux command into bash script. It will avoid the clutter code in the workflow and provide more flexibility to update the script.

Now we will create and checked in the bash script file `update_properties.sh` in the VCS which will look this.

```bash
#!/bin/bash

touch local.properties
echo "BASE_URL=\"$1\"" >> local.properties
echo "MAP_KEY=\"$2\"" >> local.properties
echo "RETRY_ATTEMPTS=$3" >> local.properties
echo "THRESHOLD_VALUE=$4" >> local.properties
```

$1, $2,$3, and $4 are the 4 arguments that will be passed into the script from the inputs values.

We need to run the bash script with input values before building the apk. We get these values by using `github.event.inputs.{key}` properties. You can find the source file [here](https://github.com/burhanrashid52/SampleWorkflow/blob/main/.github/workflows/manual_generate_apk.yml#L37).

```yaml
- name: Print Params Values
  run: |
          bash update_properties.sh ${{ github.event.inputs.baseUrl }} ${{ github.event.inputs.mapKey }} ${{ github.event.inputs.reAttempt }} ${{ github.event.inputs.thresholdValue }}
- name: Assemble app debug APK
  run: bash ./gradlew assembleDebug --stacktrace
```

Fun Fact: I was able to run the script after 17 failed attempts. So don't worry if the script does not work for the first time. Keep googling as I did 😂
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h35w82b0hox3easpqcoo.png)

# Run the workflow

- We can now run the workflow from UI in github action tab.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mc9k7lt8ouqmi1his2sn.gif)  

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/piv14astm52t5cux9aey.png)

- If you want to update the existing `local.properties` or any other file which you are already using then you need to change your script. Please check this [branch](https://github.com/burhanrashid52/SampleWorkflow/blob/update_existing_properties/update_properties.sh) for example.

# Key things to remember

- The workflow UI won't show up if the workflow is pushed into a separate branch but not in the `main/master` branch. The workflow will only be visible if it is pushed to `main/master` branch.
- It  won't run on a branch that does not have the workflow. The UI will look like this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/13ohexyd96jzgohwa391.png)

- The linux text replace `sed -i` command will work on github action which runs on the linux. For mac we need use `sed -i ""`
- Sometimes the `local.properties` do not create `BuildConfig` on sync. It will get generated when we build the apk. [Ref](https://stackoverflow.com/a/60430117/5301119)

# Conclusion

The GitHub manually trigger was something the dev asked for when the action was initially launched. Because it provides more flexibility and ease of use, especially for clients/QA's. They also have an API to trigger this workflow which opens the door for more automation.

In case of any question and issue, you can reach me on [Twitter](https://www.twitter.com/burhanrashid52). Stay updated by subscribing to my blog. Thank you for taking the time to read this article. If you like this article, please like and share it with your friends/colleagues and spread the word.

# Resources

1. [https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/](https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/)
2. [https://blog.mindorks.com/using-local-properties-file-to-avoid-api-keys-check-in-into-version-control-system](https://blog.mindorks.com/using-local-properties-file-to-avoid-api-keys-check-in-into-version-control-system)
3. [https://stackoverflow.com/questions/16745988/sed-command-with-i-option-in-place-editing-works-fine-on-ubuntu-but-not-mac](https://stackoverflow.com/questions/16745988/sed-command-with-i-option-in-place-editing-works-fine-on-ubuntu-but-not-mac)
4. [https://abelsquidhead.com/index.php/2020/07/29/manually-trigger-actions-workflow-in-github-how-did-i-not-know-about-this/](https://abelsquidhead.com/index.php/2020/07/29/manually-trigger-actions-workflow-in-github-how-did-i-not-know-about-this/)
5. [https://github.community/t/workflow-dispatch-event-not-working/128856](https://github.community/t/workflow-dispatch-event-not-working/128856)