Flutter项目在Github Actions中使用唯一签名打包

最近学了下flutter相关的内容,在项目打包的时候发现一个问题,在不同的电脑以及github actions打包出来的apk,在安装到手机时,都会提示(使用adb命令安装可以看到log)package 签名不一致的问题,导致需要先卸载才能安装。

原因

项目打包会使用到签名,不同的电脑、环境都会默认使用不同的debug签名导致每次打包出来的akp都不能直接升级安装。

使用环境

  • 环境: MacOS
  • keytool path: /Applications/Android\ Studio.app/Contents/jre/jdk/Contents/Home/jre/bin/keytool

官方文档

参考:https://flutterchina.club/android-release/

通过keytool创建一个签名,并且在项目配置中使用这个固定的签名,防止更换环境时签名的变化。

使用到的 keytool 工具目录写在上方了, Windows系统应该也在Androidstudio目录内。

缺陷

创建的签名存在一个 password 的内容,这个配置文件在项目下是被gitignore的,如果更换电脑、环境打包这个文件又需要重新创建,所以干脆将这个打包流程在github actions中完成,实现自动发布。

与Github Actions集成

参考: https://dev.to/cddelta/signing-flutter-android-apps-for-release-in-github-actions-2892

这篇文章在官方的文档基础上进行了兼容Github Actions打包的配置,按照文中所述,不出意外,不会出问题,我这边只是做一下复读机。

先不废话上项目实践 release.yml

自动打包多个abi的apk,并且输出web版本然后发布到release以及gh-page

name: "pre-release"
on:
workflow_dispatch:
inputs:
description:
description: 'Manual triggers'
push:
branches: [ main ]

jobs:
release-to-gitHub:
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
java-version: '12.x'
- run: echo $SIGNING_KEY | base64 -d > android/app/key.jks
env:
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
- uses: subosito/flutter-action@v1
with:
channel: beta
- run: flutter config --enable-web
- run: flutter pub get
- run: flutter build apk --split-per-abi
env:
KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
ALIAS: ${{ secrets.ALIAS }}
KEY_PATH: key.jks
- run: flutter build web
- run: zip -r web.zip ./build/web

- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build/web

- uses: benjlevesque/short-sha@v1.1
id: short-sha
with:
length: 6
- run: echo $SHA
env:
SHA: ${{ steps.short-sha.outputs.sha }}

- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "latest"
prerelease: true
title: "latest-develop"
files: |
build/app/outputs/flutter-apk/*.apk
web.zip

由于存在 password 这块的配置,所以将这块相关的内容都通过Github actions的secrets形式配置为环境变量。

需要配置的就是

  • SIGNING_KEY
  • KEY_STORE_PASSWORD
  • KEY_PASSWORD
  • ALIAS

后面三个就是官方文档中的storePassword、keyPassword、keyAlias, 一一对应配置好就行。

SIGNING_KEY 需要通过

openssl base64 -A -in <location of the key store file, such as /Users/<user name>/key.jks>

进行Base64化, 然后将数据填入 SIGNING_KEY , 这里注意base64结尾一般位数不够会补 「=」,如果复制的内容是以 「%」结尾,那就多余了,这应该是终端下文本内容结束的标示

更新 /android/app/gradle.build

def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
} else {
keystoreProperties.setProperty('storePassword', System.getenv('KEY_STORE_PASSWORD'));
keystoreProperties.setProperty('keyPassword', System.getenv('KEY_PASSWORD'));
keystoreProperties.setProperty('keyAlias', System.getenv('ALIAS'));
keystoreProperties.setProperty('storeFile', System.getenv('KEY_PATH'));
}

如果这个签名的 password 忘记了

这里有个验证密码的方法

keytool -list -keystore <path/to/key.jks> -storepass <pwd>

如果密码正确,会输出如下内容

密钥库类型: jks
密钥库提供方: SUN

您的密钥库包含 1 个条目

key, 2020-9-11, PrivateKeyEntry,
证书指纹 (SHA1): **********************

Warning:
JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore /Users/shenyu/key.jks -destkeystore /Users/shenyu/key.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。

如果你彻底忘了,那就重复一下官方文档的操作步骤喽。

其他

其实之前还做过electron多平台的打包。方法也是类似。需要将 apple 证书输出base64文本存在网盘,将该地址作为环境变量。但是当时屁事太多,没能记录下来,一些细节问题也都忘了。这个坑先留着,下次出问题了我再记录一下。

参考: https://www.electron.build/code-signing.html#travis-appveyor-and-other-ci-servers