使用docker编译Android源码(支持Jenkins)

思考

采用docker编译我们可以在本地不配置任何环境,只要安装docker,并下载docker镜像就好了。我在其他机器想编译,那我只需要把镜像pull下来,运行就好了。如果没有我们想要的镜像,我们可以自己配置,然后上传到docker hub,留着以后什么时候需要就下载。

构建docker环境

这里使用dockerfile来构建android的编译环境。如果不想自己构建,也可以直接用我构建好的镜像:registry.cn-hangzhou.aliyuncs.com/lm93129/android_env:v1

FROM ubuntu:18.10

MAINTAINER Yang zixi

ENV ANDROID_HOME="/opt/android-sdk" \
    JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/

# 获取最新版本的sdktools地址:https://developer.android.com/studio/index.html
ENV ANDROID_SDK_TOOLS_VERSION="4333796"

# 设置本地语言
ENV LANG="en_US.UTF-8" \
    LANGUAGE="en_US.UTF-8" \
    LC_ALL="en_US.UTF-8"

RUN apt-get clean && apt-get update -qq && apt-get install -qq -y apt-utils locales && locale-gen $LANG

ENV DEBIAN_FRONTEND="noninteractive" \
    TERM=dumb \
    DEBIAN_FRONTEND=noninteractive

# 设置android环境变量
ENV ANDROID_SDK_HOME="$ANDROID_HOME"

ENV PATH="$PATH:$ANDROID_SDK_HOME/emulator:$ANDROID_SDK_HOME/tools/bin:$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform-tools:$ANDROID_NDK:$FLUTTER_HOME/bin:$FLUTTER_HOME/bin/cache/dart-sdk/bin"

WORKDIR /tmp

# 安装一些依赖包,这里由于我个人需要,所以多安装了一些,可以根据自己的实际情况,少安装一些包
RUN apt-get update -qq > /dev/null && \
    apt-get install -qq locales > /dev/null && \
    locale-gen "$LANG" > /dev/null && \
    apt-get install -qq --no-install-recommends \
        build-essential \
        autoconf \
        curl \
        git \
        lib32stdc++6 \
        lib32z1 \
        lib32z1-dev \
        libc6-dev \
        libgmp-dev \
        libmpc-dev \
        libmpfr-dev \
        libxslt-dev \
        libxml2-dev \
        m4 \
        ncurses-dev \
        ocaml \
        openjdk-8-jdk \
        openssh-client \
        pkg-config \
        software-properties-common \
        unzip \
        wget \
        zip \
        zlib1g-dev > /dev/null

# 安装SDK
RUN echo "Installing sdk tools ${ANDROID_SDK_TOOLS_VERSION}" && \
    wget --quiet --output-document=sdk-tools.zip \
        "https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS_VERSION}.zip" && \
    mkdir --parents "$ANDROID_HOME" && \
    unzip -q sdk-tools.zip -d "$ANDROID_HOME" && \
    rm --force sdk-tools.zip && \
# 安装sdk中的组件,可以根据需要自行修改
    mkdir --parents "$ANDROID_HOME/.android/" && \
    echo '### User Sources for Android SDK Manager' > \
        "$ANDROID_HOME/.android/repositories.cfg" && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager --licenses > /dev/null && \
    echo "Installing platforms" && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "platforms;android-28" \
        "platforms;android-27" \
        "platforms;android-26" \
        "platforms;android-25" > /dev/null && \
    echo "Installing platform tools " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "platform-tools" > /dev/null && \
    echo "Installing build tools " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "build-tools;28.0.3" "build-tools;28.0.2" > /dev/null && \
    echo "Installing extras " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "extras;android;m2repository" \
        "extras;google;m2repository" > /dev/null && \
    echo "Installing play services " && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "extras;google;google_play_services" \
        "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2" > /dev/null && \
    echo "Installing Google APIs" && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager \
        "add-ons;addon-google_apis-google-24" \
        "add-ons;addon-google_apis-google-23" > /dev/null && \
    yes | "$ANDROID_HOME"/tools/bin/sdkmanager --licenses

# 设置Jenkins的环境
RUN mkdir -p /var/lib/jenkins/workspace
RUN mkdir -p /home/jenkins
RUN chmod 777 /home/jenkins
RUN chmod 777 /var/lib/jenkins/workspace
RUN chmod 777 $ANDROID_HOME/.android

保存上面的代码为Dockerfile,然后运行docker build -t android_builder:v1 . 就可以构建镜像。构建过程,需要下载谷歌的东西,所以国内网络可能会有问题,请注意网络,或者自行再构建过程中加入代理,我这里使用国外的服务器构建的,所以没有该问题。
这个镜像可以根据需要自己进行扩展,比如我这里只有android25-28的。如果你需要其他的,也可以自己再加。

使用方法

直接使用镜像

我们可以将android项目目录挂载到容器中,然后运行命令即可。例如:

docker run -it --rm -v /home/android:/home/builder/workdir -u 0:0 android_builder:v1 /bin/bash

然后进入/home/builder/workdir中运行构建命令即可,上面使用了--rm命令,所以再容器关闭后会自动销毁。

Jenkins中使用镜像

直接贴上pipeline的代码,其中镜像可以挂载/root/.gradle目录,可以实现不需要每次都下载依赖。然后关于蒲公英的上传,这里只是做了一个示例。这个脚本里面还可以再扩展下,比如构建完成之后钉钉通知下载app之类的

pipeline {
    environment {
        CI = 'true'
    }
    agent {
        docker {
            image 'registry.cn-hangzhou.aliyuncs.com/lm93129/android_env:v1'
            args  '-v /docker/ci-cache/.gradle:/root/.gradle'
        }
    }
    parameters {
        listGitBranches branchFilter: '*', credentialsId: 'gitlab', defaultValue: 'master', name: 'prj_tag', quickFilterEnabled: false, remoteURL: 'http://gitlab.com.cn/asoco/xxxx.git', selectedValue: 'NONE', sortMode: 'DESCENDING_SMART', tagFilter: '*', type: 'PT_BRANCH'
    }
    stages {
        stage('构建') {
            steps {
                echo '开始构建'
                git credentialsId: 'gitlab', url: 'http://gitlab.com.cn/asoco/xxxx.git'
                sh 'git checkout ${prj_tag}'
                sh '/bin/bash gradlew assembleRelease'
                echo '构建成功'
            }
        }
        stage('代码扫描') {
            steps {
                echo '开始代码扫描'
                sh './gradlew sonarqube'
                echo '代码扫描结束'
            }
        }
        stage('apk上传') {
            steps {
                echo '上传代码到蒲公英'
                sh "curl -F "file=@/tmp/*.apk" -F "uKey=" -F "_api_key=" https://qiniu-storage.pgyer.com/apiv1/app/upload "
            }
        }
    }
    post {
        failure {
            echo '失败'
        }
        success {
            archiveArtifacts artifacts: 'app/build/outputs/apk/release/*.apk', fingerprint: true
        }
    }
}