Flutter web pipeline

最近在不断将自己的那些见不得人的react项目以及天地不容的swing项目用flutter重写。就纯摸着石头过河,或者更准确的说法,在河底找石头。

我就一个后端的菜逼dev,既不懂前端,又不懂devops,求轻喷。


实现目标

总的来说,我pipeline的目标是,完成自动的测试、打包和生成docker image。

打包:除了生成web的html之类的东西之外,打出Android的apk包。而这个apk包应当能够通过web端直接下载,并且要能基本保证web的版本和apk包总是对应的。

构建环境:由于已经完全没有长期保留的Jenkins agent,显然连gralde都懒得装的agent是肯定不会默认带一套Android sdk的。同时,由于agent和我自己的prod环境是共享资源,因此agent的资源会受到严格限制(2核4G)。

构建时间:考虑到又穷又菜,构建时间就不限了。这个再限制一下就没法玩了。

安全:经典不信任社区。个人维护的,或者以个人为主社区参与的image,不论是做好的还是半成品的,都是肯定不用的。即使只是一个中间构建过程的工具,除非这个人是我,否则鬼知道他会挖什么坑,或者鬼知道他什么时候弃坑?(其实我个人从这个点出发的立场来说,我其实是坚定不移的相信,这些由个人发挥主要作用的东西一定存在恶意攻击)

最后,虽然会显得虎头蛇尾,但是这里我先只把CI的部分放进目标里,而CD暂时选择不提。理由是,CI最终产生的是一个image,因此CD的部分过于显然,没必要因为我rancher那一套东西分散注意力。


思路和解法

Docker提供构建环境这个,个人理解是基本操作不解释。至于具体怎么做的思路就是摸着石头过河,坑死一个是一个。

显然,两件事情,一个是提供flutter环境,一个是提供Android构建环境。总的来说就是安装好flutter和Android之后再合并到一个docker image就算完事。

Dockerfile分三份。先看flutter的部分:

FROM ubuntu AS flutter-downloader

ENV FLUTTER_VERSION=1.22.6

ENV DEBIAN_FRONTEND="noninteractive"
RUN apt-get update &&\
    apt-get upgrade -y &&\
    apt-get install -y curl xz-utils git unzip

RUN curl -o flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz
RUN tar -xvf flutter.tar.xz

ENV PATH="/flutter/bin:${PATH}"
RUN flutter channel beta && \
    flutter upgrade

这里其实就是下载一个flutter,然后升级到beta版本。其理由是:虽然当前的实现是升级到beta版本,但随着flutter的发展,相信很快就能删掉最后三行。

然后是Android的部分:

FROM openjdk:8 AS android-downloader

ENV SDK_TOOLS "6858069_latest"
ENV BUILD_TOOLS "30.0.3"
ENV TARGET_SDK "30"

ENV DEBIAN_FRONTEND="noninteractive"
RUN apt-get update &&\
    apt-get upgrade -y &&\
    apt-get install -y curl xz-utils git unzip

RUN curl -o commandlinetools.zip https://dl.google.com/android/repository/commandlinetools-linux-${SDK_TOOLS}.zip
RUN unzip commandlinetools.zip

ENV PATH="/cmdline-tools/bin:${PATH}"

RUN yes | sdkmanager --sdk_root=/android/sdk --licenses && \
    sdkmanager --sdk_root=/android/sdk --update && \
    sdkmanager --sdk_root=/android/sdk "build-tools;${BUILD_TOOLS}" "platforms;android-${TARGET_SDK}"

就意图明显,就下载commandline tool,然后下载sdk。

最后,合并两个image:

FROM openjdk:8

COPY --from=flutter-downloader /flutter /flutter
COPY --from=android-downloader /cmdline-tools /cmdline-tools
COPY --from=android-downloader /android /android

RUN apt-get update &&\
    apt-get upgrade -y &&\
    apt-get install -y git unzip

ENV PATH="/flutter/bin:/cmdline-tools/bin:${PATH}"
ENV ANDROID_HOME="/android/sdk"

RUN flutter config --enable-web

就纯复制粘贴,然后导出环境变量。


坑,和未来的改进

完全没有真机自动测试的考量。如果一定要考量的话,大概是两个方向:1、走volume看怎么把usb链接的真实设备连进container,然后用avd manager。2、走网络,通过avd连接设备。两个方向各有优劣吧,也可能都无法实现。

版本控制也是个问题。因为其本质是整合了flutter和Android,而且地下还是jdk8。于是问题就在于,对于不同的codebase,一旦需要的版本不一样,那基本就是灾难。我没啥改进的意见,主要我的依赖版本的策略比较激进,始终要求使用最新的版本,因此这个问题对我来说还能接受。


最后,求轻喷的同时,希望各位专家们也分享一点自己的做法,让我学习学习。