We’re in a state the place corporations are releasing software program and options inside minutes, and they’re doing so by following the Steady integration (CI) and steady supply (CD) set of working rules.
A CI/CD pipeline makes the automated supply of your software program extra frequent, dependable, and safe. It focuses on increased code high quality, and that’s why it’s critical for a cellular developer or group.
On this tutorial, you’ll learn to deploy your Flutter app following CI/CD rules with GitHub Actions as a instrument.
This tutorial requires a Google service account, which will probably be utilized in GitHub Actions to publish the Android construct to the Play Retailer, so to create a challenge in GCP, create a service account and choose your created challenge.
N.B., this tutorial assumes you could have some prior information of Flutter. In case you are new to Flutter, please undergo the official documentation to find out about it.
What’s GitHub Actions?
GitHub Actions is a CI/CD instrument that helps you construct, check, and deploy your modifications on manufacturing instantly out of your repository. You need to use it to arrange app releases on sure occasions like committing a tag in a sure department of your repository.
Moreover, one doesn’t should create a workflow for widespread issues throughout the tasks as GitHub has a market from which you should utilize current workflows developed by others.
The GitHub Actions workflow makes use of .yml
(“YAML Ain’t Markup Language”) recordsdata, which will probably be saved within the .github
listing on the root of your challenge.
Moreover, GitHub Actions helps completely different environments and containers like Linux, macOS, Home windows, and even VMS.
Getting began
Observe the beneath steps for preliminary setup:
- Arrange a brand new Flutter challenge utilizing your favorite IDE or utilizing the Flutter command-line instrument
- Initialize Git in your new challenge in your machine and create a brand new repository related together with your GitHub account
- Create the config listing within the root of your flutter challenge
.github
and a brand new listing known asworkflows
. The workflows right here will comprise all of your CI/CD workflows as.yml
recordsdata
Use a fundamental Flutter motion to construct an Android launch
Now, you’ll create a fundamental Android workflow that will help you perceive how GitHub Actions works in constructing your Flutter app.
Create a .yml
file, android-release.yml
, inside workflows
with the next code:
identify: Android Launch # 1 on: # 2 push: branches: [ "master" ] pull_request: branches: [ "master" ] # 3 workflow_dispatch: # 4 jobs: # 5 construct: # 6 runs-on: ubuntu-latest # 7 steps: # 8 - makes use of: actions/[email protected] # 9 - makes use of: actions/[email protected] with: distribution: 'zulu' java-version: "12.x" # 10 - makes use of: subosito/[email protected] with: # 11 flutter-version: "3.0.0" channel: 'secure' # 12 - identify: Get dependencies run: flutter pub get # Runs a set of instructions utilizing the runners shell - identify: Begin launch construct run: flutter construct appbundle
The above workflow:
- Controls when the workflow will run
- Triggers the workflow on push or pull request occasions for the
"grasp"
department; you may change it in accordance with your requirement - Means that you can run this workflow manually from the Actions tab out of your GitHub repo (a workflow run is made up of a number of jobs that may run sequentially or in paralle)l
- Comprises a single job known as
construct
- Comprises the kind of runner that the job will run on
- Makes use of steps to signify a sequence of duties that will probably be executed as a part of job
- Readies your repository beneath
$GITHUB_WORKSPACE
, so your job can entry it - Units up Java so your job can use it for the Flutter app construct
- Units up Flutter utilizing the subosito Flutter workflow
- Adjusts to the Flutter model you might be working with
- Runs a single command utilizing the runner’s shell
Issues with this fundamental motion
The issue with this fundamental workflow is that everytime you push modifications within the grasp
department, this workflow will set off and begin organising the Java SDK and Flutter SDK each time. So ultimately, it is going to result in the latency of constructing your software as you need to arrange companies each time.
How will you make your workflow sooner?
You may make your Flutter workflow sooner by caching the Java and Flutter SDKs in order that on the following run, it gained’t fetch the SDK instantly earlier than checking for the existence of the SDKs.
In your most important.yml
file, make the next modifications:
- makes use of: actions/[email protected] with: distribution: 'zulu' java-version: "12.x" cache: 'gradle' // 1 - makes use of: subosito/[email protected] with: flutter-version: "3.0.0" channel: 'secure' cache: true // 2
You’ve up to date the SDK setup by offering Gradle to be cached with respect to the Java SDK (1
) and enabling caching for the Flutter SDK (2
).
Subsequent time you run the job publish, save the above modifications and observe the time spent; you will notice a time distinction from the essential movement.
Put together for the Play Retailer launch
Now you can be increasing your workflow to create an Android Play Retailer launch.
Generate a model quantity
For any new launch, it is best to have a brand new launch model quantity, so earlier than the construct, you must create a model quantity utilizing the beneath job:
# 1 model: identify: Create model quantity # The kind of runner that the job will run on runs-on: ubuntu-latest # Steps signify a sequence of duties that will probably be executed as a part of the job steps: - makes use of: actions/[email protected] # 2 - identify: Set up GitVersion makes use of: gittools/actions/gitversion/[email protected] with: versionSpec: "5.x" - identify: Use GitVersion id: gitversion makes use of: gittools/actions/gitversion/[email protected] # 3 - identify: Create model.txt with nuGetVersion run: echo ${{ steps.gitversion.outputs.nuGetVersion }} > model.txt # 4 - identify: Add model.txt makes use of: actions/[email protected] with: identify: gitversion path: model.txt
Within the above code, we did the next:
- Created a brand new job model that will probably be executed earlier than the construct job
- Put in the GitVersion, a instrument used for versioning by your Git historical past
- Posted utilizing GitVersion, putting the model in a
model.textual content
file - Uploaded the
model.textual content
file as an artifact for the actions system with a reputationgitversion
for use later within the construct job
Signal the app
To publish the app to Play Retailer, you must give your app a digital signature utilizing a keystore. Observe this official Flutter Doc on how to try this relying upon your machine:
keytool -genkey -v -keystore %userprofilepercentupload-keystore.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias add
This can retailer a file with a .jks
extension in your house listing or no matter path you offered.
N.B., be certain that so as to add the shop password, key password, and key alias in your GitHub repository secrets and techniques (from GitHub repository > Secrets and techniques > Actions)
Going through points whereas operating the keytool?
In case you are dealing with “’keytool’ just isn’t acknowledged as an inside or exterior command” challenge, then add the trail of the JDK bin to make use of surroundings variables, or else set up JDK and repeat the trail addition to surroundings variables.
Subsequent, create a brand new file key.properties
beneath the Android listing of your app and supply the reference to your keystore generated earlier than:
storePassword=<password from earlier step> keyPassword=<password from earlier step> keyAlias=add storeFile=<location of the important thing retailer file, corresponding to /Customers/<person identify>/your-keystore-file.jks>
To make use of this key when constructing your app in launch mode, replace your Android-level construct.gradle
file as beneath:
- Outline the
keyProperties
variable to check with thekey.properties
file from thefilesystem
:def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) }
- Replace the
buildTypes
and add thesigningConfigs
as beneath:signingConfigs { launch { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] } } buildTypes { launch { signingConfig signingConfigs.launch } }
After this, your new construct will probably be created in launch mode utilizing the important thing.
Extra nice articles from LogRocket:
N.B., don’t commit the keystore
key and the key.properties
file and allow them to be non-public.
So that you is likely to be questioning, how can our job know whether or not this key exists within the filesystem and use it as a reference within the key.properties
file?
To resolve this, do the next:
Base64
encode your keystore file in your machine utilizing Git Bash or Bash:base64 <your-keystore-file.jks>
- Create a brand new secret
ANDROID_KEYSTORE_BASE64
in your GitHub repository - Copy the output and paste it as
ANDROID_KEYSTORE_BASE64
in your GitHub repository; it’ll stay secure there
Now replace the construct job in your android-release.yml
file:
construct: identify: Create Android Construct # 1 wants: model runs-on: ubuntu-latest steps: - makes use of: actions/[email protected] # 2 - identify: Get model.txt makes use of: actions/[email protected] with: identify: gitversion # 3 - identify: Create new file with out newline char from model.txt run: tr -d 'n' < model.txt > version1.txt # 4 - identify: Learn model id: model makes use of: juliangruber/[email protected] with: path: version1.txt # 5 - identify: Replace model in YAML run: sed -i 's/99.99.99+99/${{ steps.model.outputs.content material }}+${{ github.run_number }}/g' pubspec.yaml # 6 - identify: Obtain Android keystore id: android_keystore makes use of: timheuer/[email protected] with: fileName: upload-keystore.jks encodedString: ${{ secrets and techniques.KEYSTORE_BASE64 }} # 7 - identify: Create key.properties run: | echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > android/key.properties echo "storePassword=${{ secrets and techniques.STORE_PASSWORD }}" >> android/key.properties echo "keyPassword=${{ secrets and techniques.KEY_PASSWORD }}" >> android/key.properties echo "keyAlias=${{ secrets and techniques.KEY_ALIAS }}" >> android/key.properties - makes use of: actions/[email protected] with: distribution: 'zulu' java-version: "12.x" cache: gradle - makes use of: subosito/[email protected] with: flutter-version: "3.0.0" channel: 'secure' cache: true - identify: Get dependencies run: flutter pub get - identify: Begin Android Launch Construct run: flutter construct appbundle # 8 - identify: Add Android Launch makes use of: actions/[email protected] with: identify: android-release path: construct/app/outputs/bundle/launch/app-release.aab
Within the above code, you carried out the next:
- Added dependency on the model job to run this one sequentially
- Downloaded the model file uploaded within the first job utilizing the identify
gitversion
- Created a brand new file with out
newline char
frommodel.txt
- Learn the up to date model from
version1.txt
file - Up to date the
pubspec.yml
file with the model ID having the model in it - Decoded the
base64
encoded keystore worth saved as a secret to IDandroid_keystore
- Created
key.properties
utilizing the secrets and techniques andandroid_keystore
- Uploaded the Android launch bundle as an artifact for use within the subsequent job
Deploy the app
Now, you must use the bundle and ship it to Play Retailer. Earlier than that, it’s time to make use of the service account that you simply created in the beginning of this tutorial. If the service account is created, copy the important thing for that account and retailer it in secrets and techniques as PLAYSTORE_ACCOUNT_KEY
.
Subsequent, in your Google Play Console > Customers & Permissions, invite the person and add the service account person electronic mail right here.
In case you are not seeing your app in App permissions, ensure that the Google Play Developer API in GCP is enabled on your challenge.
Subsequent, replace the permission of the person in order that it has the entry to launch the app just like the admin function.
Now, add a brand new job deploy in your android-release
movement:
deploy: identify: Deploy Android Construct # 1 wants: construct runs-on: ubuntu-latest steps: - makes use of: actions/[email protected] # 2 - identify: Get Android Construct from artifacts makes use of: actions/[email protected] with: identify: android-release # 3 - identify: Launch Construct to inside observe makes use of: r0adkll/[email protected] with: serviceAccountJsonPlainText: ${{ secrets and techniques.PLAYSTORE_ACCOUNT_KEY }} packageName: <YOUR_PACKAGE_NAME> releaseFiles: app-release.aab observe: alpha standing: accomplished
Right here, you probably did the next:
- Added a dependency to run this job sequentially
- Downloaded the Android construct from artificats utilizing the identify
android-release
- Used the [email protected] workflow with the
PLAYSTORE_ACCOUNT_KEY
secret, your app bundle identify, the observe during which you need to add the construct and its standing
After this, push your modifications to GitHub and see the workflow deploy your app to the Play Retailer.
Right here’s the whole workflow:
identify: Android Launch on: push: branches: [ "master" ] pull_request: branches: [ "master" ] workflow_dispatch: jobs: model: identify: Create model quantity runs-on: ubuntu-latest steps: - makes use of: actions/[email protected] - identify: Set up GitVersion makes use of: gittools/actions/gitversion/[email protected] with: versionSpec: "5.x" - identify: Use GitVersion id: gitversion makes use of: gittools/actions/gitversion/[email protected] - identify: Create model.txt with nuGetVersion run: echo ${{ steps.gitversion.outputs.nuGetVersion }} > model.txt - identify: Add model.txt makes use of: actions/[email protected] with: identify: gitversion path: model.txt construct: identify: Create Android Construct wants: model runs-on: ubuntu-latest steps: - makes use of: actions/[email protected] - identify: Get model.txt makes use of: actions/[email protected] with: identify: gitversion - identify: Create new file with out newline char from model.txt run: tr -d 'n' < model.txt > version1.txt - identify: Learn model id: model makes use of: juliangruber/[email protected] with: path: version1.txt - identify: Replace model in YAML run: sed -i 's/99.99.99+99/${{ steps.model.outputs.content material }}+${{ github.run_number }}/g' pubspec.yaml - identify: Obtain Android keystore id: android_keystore makes use of: timheuer/[email protected] with: fileName: upload-keystore.jks encodedString: ${{ secrets and techniques.KEYSTORE_BASE64 }} - identify: Create key.properties run: | echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > android/key.properties echo "storePassword=${{ secrets and techniques.STORE_PASSWORD }}" >> android/key.properties echo "keyPassword=${{ secrets and techniques.KEY_PASSWORD }}" >> android/key.properties echo "keyAlias=${{ secrets and techniques.KEY_ALIAS }}" >> android/key.properties - makes use of: actions/[email protected] with: distribution: 'zulu' java-version: "12.x" cache: gradle - makes use of: subosito/[email protected] with: flutter-version: "3.0.0" channel: 'secure' cache: true - identify: Get dependencies run: flutter pub get - identify: Begin Android Launch Construct run: flutter construct appbundle - identify: Add Android Launch makes use of: actions/[email protected] with: identify: android-release path: construct/app/outputs/bundle/launch/app-release.aab deploy: identify: Deploy Android Construct wants: construct runs-on: ubuntu-latest steps: - makes use of: actions/[email protected] - identify: Get Android Construct from artifacts makes use of: actions/[email protected] with: identify: android-release - identify: Launch Construct to inside observe makes use of: r0adkll/[email protected] with: serviceAccountJsonPlainText: ${{ secrets and techniques.PLAYSTORE_ACCOUNT_KEY }} packageName: <YOUR_PACKAGE_NAME> releaseFiles: app-release.aab observe: alpha standing: accomplished
Be aware:
- You possibly can mix all these jobs in a single and solely job so sharing recordsdata between jobs gained’t require artifacts publishing, which consumes a free utilization restrict
- There’s a recognized challenge that generally the app just isn’t printed on the preliminary run. So, add an APKor appbundle constructed from this pipeline and roll it out for inside customers. After that, this workflow will be capable to launch apps with none points
- In case you are nonetheless dealing with points throughout deployment, be certain that all config and permissions are appropriate, or test this points web page
Flutter internet launch to GitHub pages
Now create a brand new web-release.yml
workflow and paste the next code:
identify: Net Launch on: push: branches: [ "master" ] pull_request: branches: [ "master" ] workflow_dispatch: jobs: construct: identify: Create Net Construct runs-on: ubuntu-latest steps: - makes use of: actions/[email protected] - makes use of: actions/[email protected] with: distribution: 'zulu' java-version: "12.x" cache: gradle - makes use of: subosito/[email protected] with: flutter-version: "3.0.0" channel: 'secure' cache: true - identify: Get dependencies run: flutter pub get - identify: Begin Net Launch Construct run: flutter construct internet --release - identify: Add Net Construct Information makes use of: actions/[email protected] with: identify: web-release path: ./construct/internet deploy: identify: Deploy Net Construct wants: construct runs-on: ubuntu-latest steps: - identify: Obtain Net Launch makes use of: actions/[email protected] with: identify: web-release - identify: Deploy to gh-pages makes use of: peaceiris/[email protected] with: github_token: ${{ secrets and techniques.GITHUB_TOKEN }} publish_dir: ./
The above workflow is sort of just like the Android workflow, however right here you might be utilizing the Flutter internet construct
command and later utilizing the peaceiris/[email protected] workflow to deploy the online construct to GitHub Pages.
Be aware:
- The
GITHUB_TOKEN
just isn’t a private entry token. It will get mechanically created to authenticate in your workflow - Be sure the department within the GitHub Pages part in Settings is about to
gh-pages
Conclusion
On this tutorial, you realized about find out how to arrange a GitHub Actions workflow to deploy your Flutter app throughout the Net and Android. For the following step, you may copy and modify the workflow to instantly launch the app to the app retailer or find out about different alternate options of GitHub Actions like CircleCI, GitLab CI, Jenkins, and extra.
We hope you loved this tutorial. Be happy to achieve out to us when you’ve got any queries. Thanks!