The author | a senior android development engineer Pizza is the
The introduction
In the development process of individual push SDK, generally speaking, a complete development and launch process is as follows: put forward requirements -> requirements development -> package test -> problem repair -> package delivery test verification -> test pass -> product launch.
In this process, it is not hard to find that packaging is a repetitive effort, and we often go through the problem fixing phase repeatedly, which means that we have to do multiple packaging processes repeatedly in a development live cycle. If you can optimize this, you can dramatically improve your development efficiency.
In addition, manual packaging tends to introduce some risks, such as inconsistent packaging environment, signature file leakage, low efficiency, difficult traceability management of packages, etc., so we need a continuous integration solution to reduce the repetitive work and standardize the packaging process. As a continuous integration solution, Jenkins has rich plug-in support. Below, we will introduce the practical experience of building based on Jenkins.
Jenkins profile
Jenkins is an open source CI&CD software designed to automate a variety of development tasks, including building, testing, and deploying software. Jenkins supports a variety of running methods, such as through system packages, Docker, or standalone Java programs. For more information about Jenkins building Android, please refer to this tutorial “Building Android Apps with Jenkins” written by Xiao:
Jenkins – useful. Cn/tutorial/be…
A developer can create a PipeLine build task by selecting a PipeLine:
Create Jenkinsfile for version control as follows:
Jenkins Pipeline allows you to manage your build scripts as if you were writing code. We can often iterate better by creating Jenkinsfile control versions. The basic structure of a declarative pipelining syntax is as follows:
pipeline { agent any stages { stage('Build') { steps { // } } stage('Test') { steps { // } } stage('Deploy') { steps { //}}}}Copy the code
Pipeline and Agent are specific syntax for declarative pipelines, the latter of which specifies a specific workspace for the pipeline. Stages are composed of a number of different stages, which can be shown in a stage view and are used to represent the different stages of a construction process. Steps can be understood as the different steps involved in each build phase. Usually our build instructions can be written here.
Next, this paper will introduce the practice of using Jenkins CONTINUOUS integration solution (this paper is based on Jenkins 2.19 and constructed using Jenkins Pipeline).
Demand analysis
Based on the analysis of practical experience, it is better to have a mechanism to control the risk of code in the process of packaging. This mechanism can automatically control the risky code into the packaging process, and interrupt the packaging process, and give a risk warning. In addition, the modular dependencies of medium and large projects are often complex, and we should provide a way to rely on the combination on demand. Developers can also introduce automated tests to ensure code quality. To sum up, the requirement analysis of a packaging solution is as follows:
-
Code detection: In multiplayer development, in addition to code review, we also need to introduce some code detection mechanism during the construction phase, scanning for risky code such as memory leaks, non-exit loops, etc., to avoid such code packaging.
-
Module combination: The SDK has many different functional business modules, but some modules are not necessary for packaging, so in the packaging process, the r&d personnel need to package the corresponding module combination according to different requirements, and output products.
-
Unit testing: To prevent problematic code from going live to some extent, we need to unit test the code before building it. Only after passing the unit tests can you proceed with SDK building.
-
SDK building: SDK often has some customization requirements, and these customization requirements have similar functions, so we can choose to compile different code according to different customization requirements, combined with pre-compiled plug-ins of SDK, to reduce the development cost.
-
Jar/AAR file compliance verification: For an SDK, the build output is typically an AAR or Jar file. In order to ensure the compliance of output files, we need to check the format of output products (including version number, domain name and other information).
-
Automated Testing on the real machine (Optional) : This step is optional if we want to generate an SDK that can simulate running tests on the real machine.
-
Archive: Since our final output contains integration documents, demos, and so on, at the end of the build, we need to archive these resource files and put them in the specified directory.
-
Inform the builder: Sometimes the build may take a certain amount of time, and the builder will work on other things asynchronously. When the build is complete, we need to notify the relevant builders.
Based on the analysis of the above requirements, a complete continuous integration flow chart is shown as follows:
First, the system enters the prepare stage. In this stage, preparations are made before packaging, such as environment preparation. This is followed by parsing and compiling the package parameters (parse jenkinsConfig) for subsequent package builds, including support for module-dependent composition, and so on.
Then there is the pull related package code phase. It then moves into the Code Testing phase (Android Lint) and Unit Testing. After passing the previous unit test and code inspection, we can enter our Build SDK stage. In this stage, we can select the corresponding module combination or select the corresponding function code to compile on demand with various pre-compiled plug-ins and related package environment variable parameters.
Once compiled, we need to format the associated output (JAR/AAR) (CheckJar phase). After the detection is passed, a real machine simulation test (Automated Testing phase, optional) can be carried out, and then the build product (PrintSDK phase) can be output and the relevant builder can be notified by Email (Email Notification phase). At this point, a complete packaging process is complete.
Android build environment management
The process of packaging a build was described above, but in practice, we find that as we build more and more tasks, the built environment becomes more and more complex and difficult to manage.
Pain point analysis: When we rely on the host organization to build Android, different projects have different Gradle environments. As Gradle upgrades and projects iterate, as the number of different build projects becomes larger and larger, the host’s Gradle environment becomes more and more prone to contamination. In addition, since the build environment depends on the host’s build environment, any change in the host’s build environment can easily affect the build project.
To solve this problem, we can put the different Android Gradle build environments into a Docker container. Docker is an open source application container engine that can be virtualized or packaged by developers into a lightweight, portable container and distributed to different machines. Containers are completely sandbogged, have no interfaces with each other (like iPhone apps), and most importantly, have very low performance overhead.
In each compilation and construction, we rely on the environment of a Docker container. In this way, the compilation environment between tasks and the Docker container between the host machine can be isolated, so as to ensure that the environment change of the host machine has no impact on the compilation task and ensure the clean construction environment. Later, with gradle version upgrade, we need to upgrade and release the corresponding Docker image version, so as to be compatible with the compilation environment of higher version and do the corresponding environment version management.
Jenkins Pipeline provides the function of using a Docker image as a build environment with the following code:
Pipeline {agent {docker {image 'AllBears/Jenkins - Android :1.0.1'}}}Copy the code
Maintenance and extension
When building with a Pipeline, developers can version the packaging functionality by maintaining jenkinsfiles. This way of building is more convenient, and developers are free to go back to historical versions for packaging. The rough structure template for Jenkinsfile is as follows.
Pipeline {agent {docker {image 'allBears/Jenkins-Android :1.0.1' // Specify build environment}} stages {stage('Prepare'){steps {echo Steps {echo "Jenkins build parameters Parse "}} stage('Checkout Code'){steps {echo "Build code check out"}} stage('Android Lint'){steps {echo "code static check"}} stage('Unit Testing') {steps {echo "Unit Testing"}} Stage ('Clean') {steps {echo "Build SDK"}} stage('Build SDK') {steps {echo" Build SDK"}} stage('Check JAR') {steps { Steps ('Print SDK') {steps {echo "Jar package compliance analysis "}} stage('Automated Testing') {steps {echo "Jar package compliance analysis "}} stage('Print SDK') {steps {echo" }} stage('Email Notification') {steps {echo "Email Notification"}}}}Copy the code
From the Jenkinsfile mentioned above, it is not difficult to know that each assembly line is composed of different stages, and each stage can be used as an independent small functional module. Developers can extend it by permutations and combinations of different stages.
conclusion
The manual build process is tedious, time-consuming, and introduces some risks into the manual packaging process. Jenkins automated construction eliminates the tedious manual operation process and fully liberates the productivity of r&d personnel. In addition, the use of Pipeline “continuous integration” construction, so that r & D personnel management, iterative construction project more convenient. In the future, Getur will also expand into the area of continuous integration and share the latest practices with developers.