Introduction
CI/ CD (Continuous delivery and continuous deployment) is one of the best practices that developer teams should implement, to deliver code changes frequently and reliably.
In this blog, we will discuss how to create a version for an android app in GitHub, and we will discuss how to automate uploading to Google Play in the next episode. This is really important to protect the app, and to make users able to install it on their Android phones.
CI/ CD
Continuous delivery (CI)
It is a cryptographic philosophy and set of practices that drive development teams to implement small changes and check code frequently for version control repositories. Since most modern applications require the code to be developed in different platforms and tools, the team needs a mechanism to integrate and validate the changes.
CI’s technical goal is to create a consistent and automated way to create, package and test applications. Teams are more likely to commit to frequent code changes, resulting in better collaboration and better software quality.
Continuous deployment (CD)
Starting where CI ends, CD automates the delivery of applications to defined infrastructure environments. CI / CD tools help store environment-specific information that must be filled out with every delivery. Then the CI / CD automation connects to web servers, databases, and other services that may need to be restarted or other procedures followed when deploying applications.
CI in Flutter
Create a new Flutter package, via Flutter new CIProject, and follow the best CI methods with Flutter to ensure that your application is delivered to beta testers and verified frequently without resorting to manual workflows, then sign the application request by:
- Create a keystore file in “android / app”
keytool -genkey -v-keystore keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
- Create a stock configuration in “android / keystore.properties” properties
storePassword = <password from previous step>
keyPassword = <password from previous step>
keyAlias = app
storeFile = keystore.jks - Add both files to “gitignore”
keystore.properties
keystore.jks - Now we have a configuration that we add to the Android version (gradle) file (android / app / build.gradle) above the file.
def keystoreProperties = new Properties ()
}
def keystorePropertiesFile = rootProject.file ('key.properties')
if (keystorePropertiesFile.exists ()) {
keystoreProperties.load (new FileInputStream(keystorePropertiesFile)) - Change the icon from
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now,
// so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
To mesigningConfigs {
release {
keyAlias keystore Properties ['keyAlias']
keyPassword keystoreProperties ['keyPassword']
storeFile keystoreProperties ['storeFile']? file(keystoreProperties ['storeFile']): null
storePassword keystoreProperties ['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
Now, we start adding CI tools, here we have used fastlane because it offers a set of tools that are open source and easier to use and implement.
Local setup
It is recommended that you test the build and publish process locally before migrating to the include-based system. You can also choose to perform a continuous delivery from the local machine.
- Install Fastlane
- Install Ruby using the official website (we need the full version, not the small one.)
- After that we install the “bundler” using the “gem install bundler” in CMD or Powershell.
- We are entering the “android” folder and create the following “Gemfile”.
source “https://rubygems.org”
gem “fastlane” - Install dependencies using the “bundle install”.
- Use “bundle exec fastlane init” to start creating the files required for “fastlane”, in our case it’s “Fastfile” only.
- Edit “android / fastlane / Fastfile” as follows:
default_platform (: android)
platform: android do
desc "Submit a new build to alpha Track on Play"
lane: alpha do
gradle (
gradle_path: "/ usr / bin / gradle",
task: "assemble",
build_type: 'Debug'
}
gradle (
gradle_path: "/ usr / bin / gradle",
task: "assemble",
build_type: 'Profile'
)
gradle (
gradle_path: "/ usr / bin / gradle",
task: "assemble",
build_type: 'Release'
)
Now, this is tricky. if you are using Mac or Linux just install “gradle” in the selector.
If you are using windows, then you need to change the appropriate path value then when using github actions make sure to change it back to this format.
We build all of these configs for a simple reason, sometimes Flutter decides that he won’t build the version if both the profile and debugging have not been created before. So, we are building it just in case if you are sure Flutter won’t have this issue then go ahead and remove the previous builds.
GitHub
GitHub routines make it easy to automate all software workflows, now with CI/ CD. Build, test, and publish your own code directly from GitHub. Do code reviews, manage branches, and arrange issues the way you want them, you want to do this, do the following:
- Create a new folder “github / workflows”.
- Create a new “android -loy.yaml” to represent the flow you want to create.
- Use the following “yaml” file, and change “FlutterApplication” to Application Name
yaml
name: Android Deploy
on:
push:
branches:
- 'release-v *'jobs:
deploy-android:
runs-on: ubuntu-latest
steps:- uses: actions / checkout @ v2
- uses: actions / setup-ruby @ v1
with:
ruby-version: '2.6'
- name: Setup JDK
uses: actions / setup-java @ v1
with:java-version: "12.x"
- name: Setup flutter
uses: subosito / flutter-action @ v1
with:
flutter-version: "1.24.0-10.2.pre"
channel: "beta"- name: Install NDK
run: echo "y" | sudo / usr / local / lib / android / sdk / tools / bin / sdkmanager - install "ndk; 21.0.6113669" --sdk_root = $
{ANDROID_SDK_ROOT}
- name: Configure Keystore
run: |
cd ./android
echo "$ ANDROID_KEYSTORE_FILE"> key.jks.b64
base64 -d -i key.jks.b64> ../key.jks
echo "storeFile = .. / .. / key.jks"> key.properties
echo "keyAlias = $ KEYSTORE_KEY_ALIAS" >> key.properties
echo "storePassword = $ KEYSTORE_STORE_PASSWORD" >> key.properties
echo "keyPassword = $ KEYSTORE_KEY_PASSWORD" >> key.properties
lsenv:
ANDROID_KEYSTORE_FILE: $
{{secrets.ANDROID_KEYSTORE_FILE}}
KEYSTORE_KEY_ALIAS: $
{{secrets.KEYSTORE_KEY_ALIAS}}
KEYSTORE_KEY_PASSWORD: $
{{secrets.KEYSTORE_KEY_PASSWORD}}
KEYSTORE_STORE_PASSWORD: $
{{secrets.KEYSTORE_STORE_PASSWORD}}
- name: Firebase Key ** Remove me if you are not using firebaserun: |
cd ./android
echo "$ FIREBASE_CONFIG"> firebase.json.b64
base64 -d -i firebase.json.b64> app / google-services.json
env:
FIREBASE_CONFIG: $ {{secrets.FIREBASE_CONFIG}}
- name: Get Flutter Packages toolsrun: |
flutter pub get
- name: Install bundle
run: |
cd ./android
gem install bundler
bundle update --bundler
bundle config path vendor / bundle
bundle install --jobs 4 --retry 3
- name: Distribute app to Alpha trackrun: |
cd android
bundle exec fastlane alpha
- name: Create release and upload apk
uses: underwindfall/create-release-with-debugapk@v2.0.0
env:
GITHUB_TOKEN: $ {{secrets.GITHUB_TOKEN}}
with:
asset_path: build / app / outputs / flutter-apk / app-release.apk
asset_name: FlutterApplication.apk
asset_content_type: application / zip
tag_name: $ {{github.ref}} - Create the appropriate secrets, which are:
Note: In our case, we have restricted the procedure to work on branches that have a “version” at their inception. This means that if the developer decides to release an app, he must check a new branch of master, main or dev and create a new branch named (<release- v <major>. <minor>. <build>) then edit it.
For example: `release-v1.1.5`.
And that’s it, implement the changes, pay to github and watch the flutter project create a new version.
Include
First, follow the local setup section given in “Local Setup” to make sure the process is running before migrating to a cloud.
The main thing to keep in mind is that since the cloud instances are ephemeral and unreliable, they will not leave your credentials such as your Play Store service account or iTunes distribution certificate on the server.
Continuous integration (CI) systems, such as Cirrus, generally support encrypted environment variables for storing private data.
Be careful not to echo those variable values back into the test script console. These variables are also not available in pull requests until they are combined to ensure that malicious actors cannot create a withdrawal request that prints these secrets. Be careful with these secrets in withdrawal requests that you accept and incorporate.
- Make login credentials ephemeral
– Remove the json_key_file field from Appfile and store the JSON string content in your CI system encoded variable. Json_key_data use the upload_to_play_store argument to read the environment variable directly in the Fastfile file.
– Arrange your upload key (for example, using base64) and save it as an encrypted environment variable. You can deserialize it on your CI system during the installation phase usingecho "$ PLAY_STORE_UPLOAD_KEY | base64 --decode> / home / cirrus / [directory # and filename specified in your gradle]. keystore
- It is recommended to use the Gemfile file instead of using an unspecified gem install fastlane element in a CI system every time to ensure fast lane dependencies are stable and repeatable between on-premise hardware and the cloud. However, this step is optional.
– In both [project] / android folders, create a Gemfile containing the following content:source "https://rubygems.org"
gem "fastlane"
– Run the package update and check both Gemfile and Gemfile.lock in source control.
– When running locally, use the exec package hotline instead of the fast font. - Create a CI test script like .travis.yml or .cirrus.yml in your repository root.
– Refer to Fastlane CI documentation for CI Specific Setup
– During the setup phase, depending on the platform, be sure to:
* Bundler is available with gem fixing tools.
* For Android OS, make sure the Android SDK is available and set the ANDROID_SDK_ROOT path.
* Run the package install in [project] / android.
* Make sure the Flutter SDK is available and set in PATH.
– In the transcript phase of the CI task:
* Run Flutter build an appbundle, depending on the platform.
* cd android.
* Exec fastlane package [Pathname].
Leave a Reply