For more visibility posting this on dev.to. The original article is posted on my website. 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
- Github actions.
- Basic understanding of android build using gradle.
- Basic of bash 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.
- 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
- Fewer dependencies of people on you.
- You have the environment set up in your local.
- 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.
- If you are an Indie developer working solely on the project, then you might be overwhelmed by this approach. The reason might be
- 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.
- Call the developer and ask for the apk with the required parameters.
- 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.
- 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.
- Configurability :
- The ability to build apk with configured parameters is something I find very useful. The most common parameters we configure in apps are.
- API Endpoints
- Secret/Access Keys.
- Other business based params like Threshold values, Number of Re attempts. etc.
- The ability to build apk with configured parameters is something I find very useful. The most common parameters we configure in apps are.
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.
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)
on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
tags:
description: 'Test scenario tags'
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.
- 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 inbuild.gradle
. -
Create or update the
local.properties
file like this.
BASE_URL="https://production.example.com/api/v1" MAP_KEY="production_sample_key" RETRY_ATTEMPTS=3 THRESHOLD_VALUE=0.05
-
Update
build.gradle
in the app like this.
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 { //.. } } }
-
We can refer local properties using
BuildConfig
in this app like this.
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 createBuildConfig
on sync. It will get generated when we build the apk. Ref
If you are facing any issues. You can check out the sample workflow app here. For setting the local.properties please checkout this mindork 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.
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.
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.
We will add command to build the apk.
- 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 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.
#!/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.
- 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 😂
Run the workflow
- We can now run the workflow from UI in github action tab.
- 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 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 tomain/master
branch. - It won't run on a branch that does not have the workflow. The UI will look like this.
- The linux text replace
sed -i
command will work on github action which runs on the linux. For mac we need usesed -i ""
- Sometimes the
local.properties
do not createBuildConfig
on sync. It will get generated when we build the apk. Ref
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. 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
- https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/
- https://blog.mindorks.com/using-local-properties-file-to-avoid-api-keys-check-in-into-version-control-system
- https://stackoverflow.com/questions/16745988/sed-command-with-i-option-in-place-editing-works-fine-on-ubuntu-but-not-mac
- https://abelsquidhead.com/index.php/2020/07/29/manually-trigger-actions-workflow-in-github-how-did-i-not-know-about-this/
- https://github.community/t/workflow-dispatch-event-not-working/128856
Top comments (1)
Manually generating an APK using GitHub Actions involves creating a workflow that automates the build process directly from your repository. First, you need to set up a YAML file in the .github/workflows directory of your project. This file defines the build steps, including checking out the code, setting up JDK, and running Gradle or your preferred build tool to generate the APK. By specifying tasks such as gradlew assembleRelease, GitHub Actions will compile and create the APK upon each push or pull request. You can follow guides on sites like tocalifesworld.com/ for additional tips on managing APK files and automation. This method ensures continuous integration, making it easy to maintain and distribute your APK versions efficiently.