Introduction
In this post, you'll see how to automate the delivery of your Flutter app to the testing team. For this to work, your app must have follow these conditions:
- You're developing a Flutter app;
- Your code is hosted on GitHub;
- Your testing team is using AppCenter.
Got it? Let's begin.
What is Continuous Integration?
According to Atlassian's Max Rehkopf, it's about automatically running builds and tests with every change. This speeds up development, since it is happening automatically, the developer can focus on the development of new features and leave validation and testing to automated tools.
Ok, so what's Continuous Delivery then?
Taking inspiration from Pittet's post, CD is automatic deployment of the code on testing and/or production environment. It's often confused with Continuous Deployment, which is the automated release to the end customers.
In this post we'll focus on Continuous Delivery, since we'll be automating the deployment of your app to AppCenter.
Step 1 - Setting up a Runner for GitHub Actions
If your code is hosted on GitHub, the best approach to DevOps is to write GitHub Actions. You can read more about Actions here, but everything that you need to know will be explained later on. For now, you have to setup a Runner.
A runner is where your action's jobs will be run. It can be a hosted virtual environment, or you can self-host a runner in your machine.
To register your own machine as a runner, you must go to the Settings of your repository and follow the instructions on Settings > Actions > Runner.
There you'll see a green button "New self-hosted runner". Click on it and then follow the steps. It is simply running a few commands on you terminal, so I'll not be covering it here.
In the end, you should be running your runner and it will be shown in the same page of the Settings, such as below.
If you have any issues on this part, feel free to leave a comment below.
Step 2 - Set up your AppCenter app
On your AppCenter app's settings, go to Settings > App API Tokens. There, you can create a token that'll be used on our Actions workflow.
Click on "New API Token". You'll be asked to set up a name and access for your token. Set whatever you'd like, but the token must have Full access. Don't worry, only you can see this token.
When the pop-up with the token appears - such as the one below, copy the token and save it somewhere safe. You cannot see it again, and if you happen to lose it, you must delete it and create a new one.
With your AppCenter API Token, go back to your repository on GitHub. On Settings > Secrets and variables > Actions, we'll create a Secret for our repository.
A secret is a variable that is used by our GitHub actions but is not displayed for who does not have permission. The automated workflow can use the value, but no one is able to see what it is. This enables the user to have environment variables such as AppCenter's API Token without it being compromised or leaked. For more information on secrets, refer to the documentation.
Now, click on "New repository secret" and create a APPCENTER_API_TOKEN and paste the value of the token previously created. If you've done everything correctly, this must be what you see on your page.
Now we can finally start creating workflows for our repository.
Step 3 - Creating your GitHub Actions Workflow
First of all, you repository needs a .github folder on the root folder. Then, you create a workflows folder. There, we'll create a main.yml file. The end result should be something like this:
Note that the file doesn't have to be named
main.yml
, this is just for this example.
In the main.yml file, we must add some code so that it does what we want. Start by writing this:
name: Deploy App on AppCenter
on:
push:
branches:
- main
- 'releases/**'
- name: Self explanatory. Sets the name of this workflow.
-
on: Defines the triggers of this workflow. On our case, we want this workflow to be triggered on every
push
that happens on themain
branch, or any other branch that starts withreleases/
, such asreleases/1.0.0
,releases/hotfix-login
, etc.
For more information on
on
tag, see the documentation.
But still, it's not doing anything. So now we need to add Jobs. Jobs are what make up workflows, and are the steps you want to execute.
For this post, we'll set up these steps:
- Set up Flutter;
- Set up AppCenter CLI;
- Build the app's package;
- Deploy the package to AppCenter.
In this post, only Android will be covered. Follow me to know when the post for iOS is released!
Step 3.1 - Set up Flutter
Now that you have your main.yml
file configured, we can add jobs
to achieve what we want. Start by adding a jobs
and a "Set up Flutter" step, such as the code below.
jobs:
setup-flutter:
name: Setup Flutter
runs-on: self-hosted
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Install jq
uses: dcarbone/install-jq-action@v2.0.2
- uses: subosito/flutter-action@v2
with:
channel: master
architecture: x64
- run: flutter pub get
Let's take this apart:
- jobs: Defines jobs that must be run for this workflow. These can be run in parallel or sequentially. By default, they are run in parallel. More information later.
- runs-on: Defines on what kind of Runner this job can be run. Since we've defined our self-hosted runner in the previous steps, we just add this value.
- steps: Defines the steps for this job. Each will be run sequentially.
If you pay attention, we already created 3 steps. They have two tags: name and uses. Name is self explanatory.
Uses defines what action is used on this step. In the first case, actions/checkout@v4 is used. This format says what repository and action is used. Below is the list of actions used:
- actions/checkout@: Checks out the code in the runner. This makes sure that the workflow is being run on updated code.
-
dcarbone/install-jq-action: This actions installs
jq
on the runner machine. It's a lightweight command-line JSON processor. For more information, check it's page. This is not necessary to build Flutter, but it's used in other actions later on. -
subosito/flutter-action: This action installs and runs Flutter commands. It's what we'll use to get dependencies and build our package. It can also be used to run our tests and check for coverage, but it's not being implemented in this guide. This action has a
run
parameter, which defines the specific command we want to be run.
If you pay attention, all these actions are actually public repositories that we can use. GitHub Actions have a public marketplace that you can add actions that have been developed by the community. To check what's the code is doing, you can go to the repository and check it. It's best to see what it's doing to make sure that you're not using anything with a specific vulnerability.
So to summarize, we've set up a workflow that on every push that happens on master or release/** installs Flutter and the Pub dependencies on the runner.
Now, we can add the next step.
Step 3.2 - Set up AppCenter CLI
This step is going to be easier since we already know what we're doing.
setup-appcenter-cli: # must have node and npm installed!
name: Setup AppCenter CLI
runs-on: self-hosted
steps:
- name: Install appcenter-cli
uses: charliealbright/appcenter-cli-action@v1.0.1
with:
token: '${{secrets.APPCENTER_API_TOKEN}}'
command: 'appcenter help'
We now have a new tag to go over:
-
with: This sets some parameters to be given to the action as an input.
In this case, we add
token
andcommand
. If you pay attention, we're usingsecrets.APPCENTER_API_TOKEN
.
Secret is an object that contains every variable we've set in the repository's secret. Since we've set APPCENTER_API_TOKEN, this token can now be used in this action. Again, make sure that you know what your actions are doing.
We then add "${{"
and "}}"
around the variable so that Actions knows that it must change this value to the one set on the secrets.
So now we have two steps: setting up Flutter and AppCenter CLI.
Step 3.3 - Call Deploy Android job on the main workflow
We now can use some of the superpowers of GitHub Actions - creating different jobs on different files. Add this specific job below setup-appcenter-cli
:
deploy_android:
name: Deploy Android
needs: [setup-flutter, setup-appcenter-cli]
uses: ./.github/workflows/deploy_android.yml
with:
file: './build/app/outputs/apk/release/app-release.apk'
name: 'AlvaroBarrosC/GithubAction-Android'
We now have two tags to go over:
- needs: This sets some requirements for this job. In our case, it needs Flutter and AppCenter CLI to be set up. This also means that this Deploy job will be run sequentially.
-
uses: We've already seen this tag, but now we're giving a local path. This will use a
deploy_android.yml
file that we've created onworkflows
folder. So let's create the file.
As described previously, the with tag adds some inputs. In this case, we've added file and name.
-
file: This must be the path to the file that is generated by the Flutter
build
command. Above is the default output directory, but this can be changed. -
name: This one is the username, slash and the app’s name on AppCenter. Mine is
AlvaroBarrosC
andGithubAction-Android
, but you must change it to your own.
Step 4 - Create Deploy Android workflow
As said in the previous step, create the file on .github/workflow/deploy_android.yml
, the same folder where your main.yml
file is located. Then, you can paste this code:
name: Deploy Android App on AppCenter
on:
workflow_call:
inputs:
file:
description: 'The path to the file to be released'
required: true
type: string
name:
description: 'The name of the app'
required: true
type: string
group:
description: 'The group that will have access to the version released'
required: false
type: string
default: '"Collaborators"'
jobs:
build:
name: Build .apk file
runs-on: self-hosted
steps:
- run: flutter build apk --release --verbose
Deploy:
name: Deploy file to AppCenter
needs: [build]
runs-on: self-hosted
steps:
- name: AppCenter CLI Action
uses: charliealbright/appcenter-cli-action@v1.0.1
with:
token: ${{secrets.APPCENTER_API_TOKEN}}
command: 'appcenter distribute release -f ${{inputs.file}} --app ${{inputs.name}} --group ${{inputs.group}}'
You now can see how the inputs are defined on the top of the file. They have some metadata, such as required
, type
and description
. You can also see them being used on the command
parameter of the AppCenter CLI Action. By using ${{inputs.[field]}}
`, you place the value given when the workflow was called.
We can now make a push on any change in the affected branches and see the workflow being run. Make sure your runner is running.
Step 5 - Deploy!
If you followed every step correctly, whenever you go to your Repository’s Actions tab, you can see your previous runs there. Also, you can debug and see the log of the steps.
Note that iOS deployment was not covered on this post.
Thanks for reading!
If you've missed any of the steps or is encountering any problem, you can check the code on this repo. Feel free to comment on this post with any questions that you have.
Top comments (10)
Thanks. very details, I setup success now but i try push new commit and run ./run.sh in flutter project but this workflow has no runs yet. I try input all fields such as token appcenter but it still not working. You can make a video to guide more. Thanks
Hey there! I'm sad to hear that.
If you could maybe send a link to your repo or even show any error message, I'm glad to help!
Anyway, if you've got your Runner running you should make a commit to either a master or a release/** branch.
If not, you can also add a way to the workflow to be "forced" on the Actions page.
Change
on: push
toon: workflow_dispatch
just like the code below and then the button "Run workflow" should appear on Actions page.Use this commit specifically as a reference.
github.com/AlvBarros/flutter-appce...
Hey guys, this is a longer post than average.
Feel free to leave any feedback if there's any details that I should've left out, or if you'd prefer if I split this post into multiple posts. Anyways, I'll be posting the guide to deploy iOS apps later. It includes some extra configuration for signing, that's why it's been left out. Thanks!
0s
Run flutter build apk --release --verbose
flutter build apk --release --verbose
shell: /usr/bin/bash -e {0}
/home/runner/work/_temp/d4cdd1ed-ffe7-47a6-b800-64ead539ec17.sh: line 1: flutter: command not found
Error: Process completed with exit code 127.
Where should I input these variables?
command: 'appcenter distribute release -f ${{inputs.file}} --app ${{inputs.name}} --group ${{inputs.group}}'
If I am not mistaken it should input by us on github action right?
CMIIW
Hey there!
On this example, it's currently on
deploy_android.yml
. If you want to take a look at the file completed on this guide, click here to go to the file on the GitHub repo.If you're still having issues, you could share the project link with me!
If it's private, maybe just add my user and then I can take a look.
Best of luck!
Yes, I already checked you git repo.
But still error ...
github.com/KominfoPemudaPersis/Qur...
github.com/KominfoPemudaPersis/Qur...
This log shows a specific error:
flutter: command not found
.This probably means that Flutter was not correctly set up in the Runner.
It's supposed to be set up on the
Setup Flutter
step of the job, so maybe take a look at that log to make sure it ran without any issue?/usr/local/bin/appcenter distribute release -f ./build/app/outputs/apk/release/app-release.apk --app QuranPersis --group Collaborators --token ***
Error: Command 'distribute release -f ./build/app/outputs/apk/release/app-release.apk --app QuranPersis --group Collaborators --token ***' failed with exception "'QuranPersis' is not a valid application id"
Error: The process '/usr/local/bin/appcenter' failed with exit code 3
Where Can I get the application ID?