Github Action 自动构建 Flutter Android Apk

前言

这段时间用 Flutter 做了一个开源的项目 VVEX, 因为需要打包 apk,在此之前一直是手动 flutter build apk,再把文件上传到 release,每次发布新版本确实有点繁琐。趁着有空来使用 Github Action 做个持续化集成,自动打包 apk。

最后完成的自动化构建脚本如下:

更新: 5月谷歌发布了Flutter stable 3.10.0 版本,可能会出现插件不兼容情况,需要将 yml 文件中flutter对应 channel 改为 anyflutter-version需要指定为某一版本,以确保打包环境正常。

为了方便阅读,部分 step 的 name 都使用了中文命名

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
name: build_apk

# action事件触发
on:
push:
# push tag时触发
tag:
- v*

# 可以有多个jobs
jobs:
build_apk:
# 运行环境 ubuntu-latest window-latest mac-latest
runs-on: ubuntu-latest

# 每个jobs中可以有多个steps
steps:
- name: 代码迁出
uses: actions/checkout@v3

- name: 构建Java环境
uses: actions/setup-java@v3
with:
distribution: "zulu"
java-version: "17"
token: ${{secrets.GIT_TOKEN}}

- name: 检查缓存
uses: actions/cache@v2
id: cache-flutter
with:
path: /root/flutter-sdk # Flutter SDK 的路径
key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}

- name: 安装Flutter
if: steps.cache-flutter.outputs.cache-hit != 'true'
uses: subosito/flutter-action@v2
with:
flutter-version: 3.7.7
channel: any

- name: 下载项目依赖
run: flutter pub get

- name: 解码生成 jks
run: echo $KEYSTORE_BASE64 | base64 -di > android/app/vvex.jks
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}

- name: flutter build apk
# 对应 android/app/build.gradle signingConfigs中的配置项
run: flutter build apk --release --split-per-abi
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}

- name: 发布
uses: ncipollo/release-action@v1
with:
artifacts: "build/app/outputs/flutter-apk/app-*.apk"
token: ${{ secrets.GIT_TOKEN }}
allowUpdates: true

在此处有两点需要特别注意一下:

  • 无签名打包
  • 带签名打包

无签名打包

在使用 GitHub 完成自动化构建之前,一直使用的是无签名打包,很简单,不需要额外配置什么
无签名打包的脚本需要去掉上面的这部分内容

COPY
1
2
3
4
5
6
7
8
9
10
11
- name: 解码生成 jks
run: echo $KEYSTORE_BASE64 | base64 -di > android/app/vvex.jks
env:
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}

- name: flutter build apk
run: flutter build apk --release --split-per-abi
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}

以下部分需要保留

COPY
1
2
- name: flutter build apk
run: flutter build apk --release --split-per-abi

带签名打包

签名文件 xxx.js 跟 xxx.properties 文件不要提交至公共仓库
主要分下面几步

  • 生成签名 jks 文件:比如 vvex.jks
  • 创建 key.properties 文件
  • 修改 build.gradle 文件
  • Github 配置 action secrets

生成签名文件

此处及以下以 VVEX 举例 Mac 环境

COPY
1
2
3
4
5
6
7
# 移动至桌面
cd desktop
# 创建 jks文件夹
mkdir jks
cd jks
# 生成jks
keytool -genkeypair -alias vvex -keyalg RSA -keysize 2048 -keypass password -keystore vvex.jks -storepass password -validity 10000

说明:

  • -alias vvex 此处的 vvex 可以自定义修改为任意
  • -keystore vvex.jks 此处的 vvex 可以自定义修改为任,建议与别名相同
  • 建议以上 vvex 为相同内容
  • -keypass password 此处的 password 设置密钥密码
  • -storepass password 此处的 password 设置密钥库密码
  • 建议以上 password 为相同内容

vvex.jks 文件生成完成后,复制至 android/app 目录下

至此,第一步完成


创建 key.properties 文件
COPY
1
2
3
4
5
6
7
8
9

# -storepass password 处的password
storePassword = password
# -keypass password 处的password
keyPassword = password
# 别名
keyAlias = vvex
# 此处注意 直接写xxxx.jks就可以,不需要写其他路径
storeFile = vvex.jks

key.properties 文件生成完成后,复制至 android 目录下

至此,第一步完成


修改 build.gradle 文件

android/app 目录下的 build.gradle 文件增加以下内容

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//  引用 key.properties 文件
def keystorePropertiesFile = rootProject.file('key.properties')
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

def _storeFile = file(System.getenv("KEYSTORE") ?: keystoreProperties["storeFile"] ?: "vvex.jks")
def _storePassword = System.getenv("KEYSTORE_PASSWORD") ?: keystoreProperties["storePassword"]
def _keyAlias = System.getenv("KEY_ALIAS") ?: keystoreProperties["keyAlias"]
def _keyPassword = System.getenv("KEY_PASSWORD") ?: keystoreProperties["keyPassword"]

android {
...
...
signingConfigs {
// 添加签名配置
release {
// 配置密钥库文件的位置、别名、密码等信息
storeFile _storeFile
storePassword _storePassword
keyAlias _keyAlias
keyPassword _keyPassword
v1SigningEnabled true
v2SigningEnabled true
}
}

buildTypes {
release {
signingConfig signingConfigs.release
}
}
}

其中 大写字符 KEYSTORE_PASSWORDKEY_ALIASKEY_PASSWORD 在 github 设置secrets时会用到

Github 配置 action secrets
  • 打开远程仓库的设置页面(用户名及仓库名记得替换为自己的)
    COPY
    1
    https://github.com/guozhigq/flutter_test/settings/secrets/actions
  • 点击右上方 【New repository secret】
  • 依次创建 Actions secrets
name Secret 说明
KEYSTORE_BASE64 base64 vvex.jks base64 编码
KEY_ALIAS vvex -alias vvex处的 vvex
KEY_PASSWORD password -keypass password处的 password
KEYSTORE_PASSWORD password -storepass password处的 password
KEY_PROPERTIES base64 key.properties base64 编码
GIT_TOKEN 字符串 github 设置中生成

如何对 vvex.jks、key.properties 进行 base64 编码
方便起见,将 key.properties 复制到 desktop/jks 文件夹下

COPY
1
2
3
# 自动生成base64并复制到了粘贴板,直接到github复制即可
base64 vvex.jks | pbcopy
base64 key.properties | pbcopy

如何生成 GIT_TOKEN
打开 tokens 设置页面

作者: 果汁
文章链接: https://guozhigq.github.io/post/25ae93b9.html
版权声明: All posts on this blog are licensed under the CC BY-NC-SA 4.0 license unless otherwise stated. Please cite 果汁来一杯 !