Skip to content

multi arch

multi arch #22

name: Build Multi Platform
permissions:
contents: write
on:
workflow_dispatch:
push:
branches: ["master"]
tags: ["v*"]
jobs:
build-desktop:
name: Build ${{ matrix.platform.name }} (${{ matrix.platform.arch }})
runs-on: ${{ matrix.platform.os }}
strategy:
fail-fast: false
matrix:
platform:
- name: linux
arch: amd64
os: ubuntu-latest
build_command: flutter build linux --release --target-platform linux-x64
bundle_dir: x64
artifact_base: ailurus-linux
package_extension: AppImage
- name: linux
arch: arm64
os: ubuntu-24.04-arm
build_command: flutter build linux --release --target-platform linux-arm64
bundle_dir: arm64
artifact_base: ailurus-linux
package_extension: AppImage
- name: windows
arch: amd64
os: windows-latest
build_command: flutter build windows --release
artifact_base: ailurus-windows
package_extension: zip
- name: macos
arch: amd64
os: macos-15-intel
build_command: flutter build macos --release
artifact_base: ailurus-macos
package_extension: dmg
- name: macos
arch: arm64
os: macos-15
build_command: flutter build macos --release
artifact_base: ailurus-macos
package_extension: dmg
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Flutter (x64)
if: matrix.platform.arch != 'arm64'
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- name: Setup Flutter (arm64)
if: matrix.platform.arch == 'arm64'
shell: bash
run: |
git clone https://github.com/flutter/flutter.git --depth 1 -b stable "$HOME/flutter"
echo "$HOME/flutter/bin" >> "$GITHUB_PATH"
export PATH="$HOME/flutter/bin:$PATH"
flutter --disable-analytics
flutter --version
- name: Install Linux dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev
- name: Enable Linux desktop target
if: runner.os == 'Linux'
run: |
flutter config --enable-linux-desktop
- name: Enable Windows desktop target
if: runner.os == 'Windows'
shell: pwsh
run: |
flutter config --enable-windows-desktop
- name: Enable macOS desktop target
if: runner.os == 'macOS'
run: |
flutter config --enable-macos-desktop
- name: Get dependencies
run: flutter pub get
- name: Resolve package name
id: package_meta
shell: bash
run: |
APP_VERSION=$(grep '^version:' pubspec.yaml | sed 's/version:[[:space:]]*//' | cut -d+ -f1)
echo "name=${{ matrix.platform.artifact_base }}-${APP_VERSION}-${{ matrix.platform.arch }}.${{ matrix.platform.package_extension }}" >> "$GITHUB_OUTPUT"
- name: Resolve package checksum name
id: package_hash_meta
shell: bash
run: |
echo "name=${{ steps.package_meta.outputs.name }}.sha256" >> "$GITHUB_OUTPUT"
- name: Build desktop app
run: ${{ matrix.platform.build_command }}
- name: Package Linux AppImage
if: runner.os == 'Linux'
run: |
sudo apt-get install -y desktop-file-utils wget
rm -rf AppDir dist
mkdir -p AppDir/usr dist
cp build/linux/${{ matrix.platform.bundle_dir }}/release/bundle/ailurus AppDir/usr/
cp -r build/linux/${{ matrix.platform.bundle_dir }}/release/bundle/lib AppDir/usr/
cp -r build/linux/${{ matrix.platform.bundle_dir }}/release/bundle/data AppDir/usr/
cp assets/icons/app_icon_source.png AppDir/ailurus.png
cat > AppDir/AppRun <<'EOF'
#!/bin/sh
HERE="$(dirname "$(readlink -f "$0")")"
exec "$HERE/usr/ailurus" "$@"
EOF
chmod +x AppDir/AppRun
cat > AppDir/ailurus.desktop <<'EOF'
[Desktop Entry]
Type=Application
Name=Ailurus
Exec=ailurus
Icon=ailurus
Categories=Utility;
Terminal=false
EOF
desktop-file-validate AppDir/ailurus.desktop
if [ "${{ matrix.platform.arch }}" = "arm64" ]; then
APPIMAGE_TOOL_URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-aarch64.AppImage"
APPIMAGE_ARCH="aarch64"
else
APPIMAGE_TOOL_URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
APPIMAGE_ARCH="x86_64"
fi
wget -q "$APPIMAGE_TOOL_URL" -O appimagetool.AppImage
chmod +x appimagetool.AppImage
ARCH="$APPIMAGE_ARCH" ./appimagetool.AppImage --appimage-extract-and-run AppDir "dist/${{ steps.package_meta.outputs.name }}"
- name: Package Windows ZIP
if: runner.os == 'Windows'
shell: pwsh
run: |
if (Test-Path dist) { Remove-Item dist -Recurse -Force }
New-Item -ItemType Directory -Path dist | Out-Null
Compress-Archive -Path build/windows/x64/runner/Release/* -DestinationPath "dist/${{ steps.package_meta.outputs.name }}"
- name: Package macOS DMG
if: runner.os == 'macOS'
run: |
rm -rf dist
mkdir -p dist
hdiutil create -volname "Ailurus" -srcfolder "build/macos/Build/Products/Release/ailurus.app" -ov -format UDZO "dist/${{ steps.package_meta.outputs.name }}"
- name: Upload desktop artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform.name }}-${{ matrix.platform.arch }}-package
path: dist/${{ steps.package_meta.outputs.name }}
if-no-files-found: error
- name: Generate desktop checksum
shell: bash
run: |
sha256sum "dist/${{ steps.package_meta.outputs.name }}" > "dist/${{ steps.package_hash_meta.outputs.name }}"
- name: Upload desktop checksum artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform.name }}-${{ matrix.platform.arch }}-package-sha256
path: dist/${{ steps.package_hash_meta.outputs.name }}
if-no-files-found: error
- name: Upload desktop release asset
if: startsWith(github.ref, 'refs/tags/v')
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1 || gh release create "${GITHUB_REF_NAME}" --generate-notes >/dev/null 2>&1 || true
gh release upload "${GITHUB_REF_NAME}" \
"dist/${{ steps.package_meta.outputs.name }}" \
"dist/${{ steps.package_hash_meta.outputs.name }}" \
--clobber
build-android-release:
name: Build signed android apk
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
environment: release
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
cache: true
- name: Get dependencies
run: flutter pub get
- name: Resolve Android package names
id: android_meta
shell: bash
run: |
APP_VERSION=$(grep '^version:' pubspec.yaml | sed 's/version:[[:space:]]*//' | cut -d+ -f1)
echo "apk_arm64=ailurus-android-${APP_VERSION}-arm64.apk" >> "$GITHUB_OUTPUT"
echo "apk_arm64_sha=ailurus-android-${APP_VERSION}-arm64.apk.sha256" >> "$GITHUB_OUTPUT"
echo "apk_amd64=ailurus-android-${APP_VERSION}-amd64.apk" >> "$GITHUB_OUTPUT"
echo "apk_amd64_sha=ailurus-android-${APP_VERSION}-amd64.apk.sha256" >> "$GITHUB_OUTPUT"
- name: Restore Android keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > android/release-keystore.jks
- name: Create key.properties
run: |
cat > android/key.properties <<EOF
storePassword=${{ secrets.ANDROID_STORE_PASSWORD }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
storeFile=release-keystore.jks
EOF
- name: Build signed Android APKs
run: flutter build apk --release --target-platform android-arm64,android-x64 --split-per-abi
- name: Verify APK signature
run: |
BUILD_TOOLS_VERSION=$(ls "$ANDROID_HOME/build-tools" | sort -V | tail -n 1)
"$ANDROID_HOME/build-tools/$BUILD_TOOLS_VERSION/apksigner" verify --print-certs build/app/outputs/flutter-apk/app-arm64-v8a-release.apk
"$ANDROID_HOME/build-tools/$BUILD_TOOLS_VERSION/apksigner" verify --print-certs build/app/outputs/flutter-apk/app-x86_64-release.apk
- name: Generate checksums
shell: bash
run: |
cp build/app/outputs/flutter-apk/app-arm64-v8a-release.apk "build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64 }}"
cp build/app/outputs/flutter-apk/app-x86_64-release.apk "build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64 }}"
sha256sum "build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64 }}" > "build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64_sha }}"
sha256sum "build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64 }}" > "build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64_sha }}"
- name: Upload Android artifact
uses: actions/upload-artifact@v4
with:
name: ailurus-android-signed
path: |
build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64 }}
build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64_sha }}
build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64 }}
build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64_sha }}
if-no-files-found: error
- name: Upload Android release assets
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1 || gh release create "${GITHUB_REF_NAME}" --generate-notes >/dev/null 2>&1 || true
gh release upload "${GITHUB_REF_NAME}" \
"build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64 }}" \
"build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_arm64_sha }}" \
"build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64 }}" \
"build/app/outputs/flutter-apk/${{ steps.android_meta.outputs.apk_amd64_sha }}" \
--clobber