forked from mirrors/rustdesk
454 lines
19 KiB
YAML
454 lines
19 KiB
YAML
name: Build RustDesk Android
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
upload-artifact:
|
|
type: boolean
|
|
default: true
|
|
description: "Upload APK artifacts"
|
|
upload-tag:
|
|
type: string
|
|
default: "nightly"
|
|
description: "Release tag name"
|
|
|
|
env:
|
|
RUST_VERSION: "1.75"
|
|
CARGO_NDK_VERSION: "3.1.2"
|
|
FLUTTER_VERSION: "3.24.5"
|
|
ANDROID_FLUTTER_VERSION: "3.24.5"
|
|
TAG_NAME: "${{ inputs.upload-tag }}"
|
|
VCPKG_BINARY_SOURCES: "clear;files,/opt/vcpkg-cache,readwrite"
|
|
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
|
VERSION: "1.4.6"
|
|
NDK_VERSION: "r27c"
|
|
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
|
|
UPLOAD_ARTIFACT: "${{ inputs.upload-artifact }}"
|
|
|
|
jobs:
|
|
# -------------------------------------------------------
|
|
# Step 1: Generate flutter-rust bridge bindings
|
|
# Runs on: ubuntu-22.04
|
|
# -------------------------------------------------------
|
|
generate-bridge:
|
|
uses: ./.github/workflows/custom-bridge.yml
|
|
runs-on: ubuntu-22.04
|
|
|
|
# -------------------------------------------------------
|
|
# Step 2: Build per-arch Android APKs
|
|
# Runs on: ubuntu-24.04
|
|
# Targets: aarch64, armv7, x86_64
|
|
# -------------------------------------------------------
|
|
build-rustdesk-android:
|
|
needs: [generate-bridge]
|
|
name: build rustdesk android apk ${{ matrix.job.target }}
|
|
runs-on: ${{ matrix.job.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
job:
|
|
- { arch: aarch64, target: aarch64-linux-android, os: ubuntu-24.04, reltype: release, suffix: "" }
|
|
- { arch: armv7, target: armv7-linux-androideabi, os: ubuntu-24.04, reltype: release, suffix: "" }
|
|
- { arch: x86_64, target: x86_64-linux-android, os: ubuntu-24.04, reltype: release, suffix: "" }
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
uses: https://github.com/jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: false
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: false
|
|
docker-images: true
|
|
swap-storage: false
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
clang \
|
|
cmake \
|
|
curl \
|
|
gcc-multilib \
|
|
git \
|
|
g++ \
|
|
g++-multilib \
|
|
libayatana-appindicator3-dev \
|
|
libasound2-dev \
|
|
libc6-dev \
|
|
libclang-dev \
|
|
libunwind-dev \
|
|
libgstreamer1.0-dev \
|
|
libgstreamer-plugins-base1.0-dev \
|
|
libgtk-3-dev \
|
|
libpam0g-dev \
|
|
libpulse-dev \
|
|
libva-dev \
|
|
libxcb-randr0-dev \
|
|
libxcb-shape0-dev \
|
|
libxcb-xfixes0-dev \
|
|
libxdo-dev \
|
|
libxfixes-dev \
|
|
llvm-dev \
|
|
nasm \
|
|
ninja-build \
|
|
openjdk-17-jdk-headless \
|
|
pkg-config \
|
|
tree \
|
|
wget
|
|
|
|
- name: Checkout source code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Install flutter
|
|
uses: https://github.com/subosito/flutter-action@v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}
|
|
|
|
- name: Patch flutter
|
|
run: |
|
|
cd $(dirname $(dirname $(which flutter)))
|
|
[[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
|
|
|
|
- uses: https://github.com/nttld/setup-ndk@v1
|
|
id: setup-ndk
|
|
with:
|
|
ndk-version: ${{ env.NDK_VERSION }}
|
|
add-to-path: true
|
|
|
|
# vcpkg 빌드 바이너리 캐시 — 첫 실행 이후 수시간 절약
|
|
# 캐시 키: VCPKG_COMMIT_ID + target arch 조합 → arch별 독립 캐시
|
|
- name: Cache vcpkg binary cache
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: /opt/vcpkg-cache
|
|
key: vcpkg-android-${{ matrix.job.target }}-${{ env.VCPKG_COMMIT_ID }}
|
|
|
|
- name: Setup vcpkg
|
|
uses: https://github.com/lukka/run-vcpkg@v11
|
|
with:
|
|
vcpkgDirectory: /opt/artifacts/vcpkg
|
|
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
|
doNotCache: false
|
|
|
|
- name: Install vcpkg dependencies
|
|
shell: bash
|
|
env:
|
|
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
run: |
|
|
mkdir -p /opt/vcpkg-cache
|
|
case ${{ matrix.job.target }} in
|
|
aarch64-linux-android) ANDROID_TARGET=arm64-v8a ;;
|
|
armv7-linux-androideabi) ANDROID_TARGET=armeabi-v7a ;;
|
|
x86_64-linux-android) ANDROID_TARGET=x86_64 ;;
|
|
i686-linux-android) ANDROID_TARGET=x86 ;;
|
|
esac
|
|
if ! ./flutter/build_android_deps.sh "${ANDROID_TARGET}"; then
|
|
find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do
|
|
echo "$_1:"; echo "======"; cat "$_1"; echo "======"; echo ""
|
|
done
|
|
exit 1
|
|
fi
|
|
|
|
- name: Restore bridge files
|
|
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
|
with:
|
|
name: bridge-artifact
|
|
path: ./
|
|
|
|
- name: Install Rust toolchain
|
|
uses: https://github.com/dtolnay/rust-toolchain@v1
|
|
with:
|
|
toolchain: ${{ env.RUST_VERSION }}
|
|
components: "rustfmt"
|
|
|
|
- uses: https://github.com/Swatinem/rust-cache@v2
|
|
with:
|
|
prefix-key: rustdesk-lib-cache-android
|
|
key: ${{ matrix.job.target }}
|
|
|
|
# cargo-ndk 바이너리 캐시 — 버전 고정이므로 거의 항상 hit
|
|
- name: Cache cargo-ndk binary
|
|
uses: actions/cache@v3
|
|
with:
|
|
path: ~/.cargo/bin/cargo-ndk
|
|
key: cargo-ndk-${{ env.CARGO_NDK_VERSION }}-${{ runner.os }}
|
|
|
|
- name: Build rustdesk lib
|
|
env:
|
|
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
run: |
|
|
rustup target add ${{ matrix.job.target }}
|
|
# 캐시 hit 시 재설치 생략
|
|
command -v cargo-ndk &>/dev/null || cargo install cargo-ndk --version ${{ env.CARGO_NDK_VERSION }} --locked
|
|
case ${{ matrix.job.target }} in
|
|
aarch64-linux-android)
|
|
./flutter/ndk_arm64.sh
|
|
mkdir -p ./flutter/android/app/src/main/jniLibs/arm64-v8a
|
|
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
|
|
;;
|
|
armv7-linux-androideabi)
|
|
./flutter/ndk_arm.sh
|
|
mkdir -p ./flutter/android/app/src/main/jniLibs/armeabi-v7a
|
|
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
|
|
;;
|
|
x86_64-linux-android)
|
|
./flutter/ndk_x64.sh
|
|
mkdir -p ./flutter/android/app/src/main/jniLibs/x86_64
|
|
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
|
|
;;
|
|
esac
|
|
|
|
- name: Upload Rustdesk library to Artifacts
|
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
|
with:
|
|
name: librustdesk.so.${{ matrix.job.target }}
|
|
path: ./target/${{ matrix.job.target }}/release/liblibrustdesk.so
|
|
|
|
- name: Setup Android SDK
|
|
uses: https://github.com/android-actions/setup-android@v3
|
|
|
|
- name: Patch Android package name
|
|
run: bash ./patch_package_name.sh
|
|
|
|
- name: Build rustdesk APK
|
|
shell: bash
|
|
env:
|
|
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
|
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
run: |
|
|
export PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH
|
|
# Increase Gradle JVM memory for CI builds
|
|
sed -i "s/org.gradle.jvmargs=-Xmx1024M/org.gradle.jvmargs=-Xmx2g/g" ./flutter/android/gradle.properties
|
|
# temporary use debug sign config
|
|
sed -i "s/signingConfigs.release/signingConfigs.debug/g" ./flutter/android/app/build.gradle
|
|
case ${{ matrix.job.target }} in
|
|
aarch64-linux-android)
|
|
mkdir -p ./flutter/android/app/src/main/jniLibs/arm64-v8a
|
|
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/
|
|
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
|
|
# build flutter
|
|
pushd flutter
|
|
flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-arm64 --split-per-abi
|
|
mv build/app/outputs/flutter-apk/app-arm64-v8a-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
|
|
;;
|
|
armv7-linux-androideabi)
|
|
mkdir -p ./flutter/android/app/src/main/jniLibs/armeabi-v7a
|
|
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/
|
|
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
|
|
# build flutter
|
|
pushd flutter
|
|
flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-arm --split-per-abi
|
|
mv build/app/outputs/flutter-apk/app-armeabi-v7a-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
|
|
;;
|
|
x86_64-linux-android)
|
|
mkdir -p ./flutter/android/app/src/main/jniLibs/x86_64
|
|
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/x86_64/
|
|
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
|
|
# build flutter
|
|
pushd flutter
|
|
flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-x64 --split-per-abi
|
|
mv build/app/outputs/flutter-apk/app-x86_64-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
|
|
;;
|
|
esac
|
|
popd
|
|
mkdir -p signed-apk
|
|
mv ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk signed-apk/ 2>/dev/null || \
|
|
mv ./rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk signed-apk/
|
|
|
|
- name: Setup sign tool version variable
|
|
shell: bash
|
|
run: |
|
|
BUILD_TOOL_VERSION=$(ls "$ANDROID_SDK_ROOT/build-tools/" | tail -n 1)
|
|
echo "ANDROID_SIGN_TOOL_VERSION=$BUILD_TOOL_VERSION" >> $GITHUB_ENV
|
|
|
|
- uses: https://github.com/r0adkll/sign-android-release@v1
|
|
name: Sign app APK
|
|
if: env.ANDROID_SIGNING_KEY != null
|
|
id: sign-rustdesk
|
|
with:
|
|
releaseDirectory: ./signed-apk
|
|
signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }}
|
|
alias: ${{ secrets.ANDROID_ALIAS }}
|
|
keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }}
|
|
keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
env:
|
|
BUILD_TOOLS_VERSION: ${{ env.ANDROID_SIGN_TOOL_VERSION }}
|
|
|
|
- name: Upload signed APK
|
|
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
|
with:
|
|
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
|
|
path: ${{ steps.sign-rustdesk.outputs.signedReleaseFile }}
|
|
|
|
- name: Upload unsigned APK
|
|
if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
|
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
|
with:
|
|
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
|
|
path: signed-apk/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
|
|
|
|
# -------------------------------------------------------
|
|
# Step 3: Build universal APK (all ABIs combined)
|
|
# Runs on: ubuntu-24.04
|
|
# Needs: build-rustdesk-android (all 3 arch .so files)
|
|
# -------------------------------------------------------
|
|
build-rustdesk-android-universal:
|
|
needs: [build-rustdesk-android]
|
|
name: build rustdesk android universal apk
|
|
runs-on: ubuntu-24.04
|
|
env:
|
|
reltype: release
|
|
suffix: ""
|
|
steps:
|
|
- name: Free Disk Space (Ubuntu)
|
|
uses: https://github.com/jlumbroso/free-disk-space@main
|
|
with:
|
|
tool-cache: false
|
|
android: false
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: false
|
|
docker-images: true
|
|
swap-storage: false
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
clang cmake curl gcc-multilib git g++ g++-multilib \
|
|
libayatana-appindicator3-dev libasound2-dev libc6-dev \
|
|
libclang-dev libunwind-dev libgstreamer1.0-dev \
|
|
libgstreamer-plugins-base1.0-dev libgtk-3-dev \
|
|
libpam0g-dev libpulse-dev libva-dev \
|
|
libxcb-randr0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
|
|
libxdo-dev libxfixes-dev llvm-dev nasm ninja-build \
|
|
openjdk-17-jdk-headless pkg-config tree wget
|
|
|
|
- name: Checkout source code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Install flutter
|
|
uses: https://github.com/subosito/flutter-action@v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}
|
|
|
|
- name: Patch flutter
|
|
run: |
|
|
cd $(dirname $(dirname $(which flutter)))
|
|
[[ "3.24.5" == ${{env.ANDROID_FLUTTER_VERSION}} ]] && git apply ${{ github.workspace }}/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff
|
|
|
|
- uses: https://github.com/nttld/setup-ndk@v1
|
|
id: setup-ndk
|
|
with:
|
|
ndk-version: ${{ env.NDK_VERSION }}
|
|
add-to-path: true
|
|
|
|
- name: Restore bridge files
|
|
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
|
with:
|
|
name: bridge-artifact
|
|
path: ./
|
|
|
|
- name: Install Rust toolchain
|
|
uses: https://github.com/dtolnay/rust-toolchain@v1
|
|
with:
|
|
toolchain: ${{ env.RUST_VERSION }}
|
|
|
|
- name: Download arm64 library
|
|
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
|
with:
|
|
name: librustdesk.so.aarch64-linux-android
|
|
path: ./flutter/android/app/src/main/jniLibs/arm64-v8a
|
|
|
|
- name: Download armv7 library
|
|
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
|
with:
|
|
name: librustdesk.so.armv7-linux-androideabi
|
|
path: ./flutter/android/app/src/main/jniLibs/armeabi-v7a
|
|
|
|
- name: Download x86_64 library
|
|
uses: https://code.forgejo.org/forgejo/download-artifact@v4
|
|
with:
|
|
name: librustdesk.so.x86_64-linux-android
|
|
path: ./flutter/android/app/src/main/jniLibs/x86_64
|
|
|
|
- name: Setup Android SDK
|
|
uses: https://github.com/android-actions/setup-android@v3
|
|
|
|
- name: Patch Android package name
|
|
run: bash ./patch_package_name.sh
|
|
|
|
- name: Build universal APK
|
|
shell: bash
|
|
env:
|
|
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
|
|
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
|
run: |
|
|
export PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH
|
|
sed -i "s/org.gradle.jvmargs=-Xmx1024M/org.gradle.jvmargs=-Xmx2g/g" ./flutter/android/gradle.properties
|
|
sed -i "s/signingConfigs.release/signingConfigs.debug/g" ./flutter/android/app/build.gradle
|
|
|
|
mv ./flutter/android/app/src/main/jniLibs/arm64-v8a/liblibrustdesk.so \
|
|
./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
|
|
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so \
|
|
./flutter/android/app/src/main/jniLibs/arm64-v8a/
|
|
|
|
mv ./flutter/android/app/src/main/jniLibs/armeabi-v7a/liblibrustdesk.so \
|
|
./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
|
|
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so \
|
|
./flutter/android/app/src/main/jniLibs/armeabi-v7a/
|
|
|
|
mv ./flutter/android/app/src/main/jniLibs/x86_64/liblibrustdesk.so \
|
|
./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
|
|
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so \
|
|
./flutter/android/app/src/main/jniLibs/x86_64/
|
|
|
|
pushd flutter
|
|
flutter build apk "--${{ env.reltype }}" --target-platform android-arm64,android-arm,android-x64
|
|
popd
|
|
mkdir -p signed-apk
|
|
mv ./flutter/build/app/outputs/flutter-apk/app-${{ env.reltype }}.apk \
|
|
signed-apk/rustdesk-${{ env.VERSION }}-universal${{ env.suffix }}.apk
|
|
|
|
- name: Setup sign tool version variable
|
|
shell: bash
|
|
run: |
|
|
BUILD_TOOL_VERSION=$(ls "$ANDROID_SDK_ROOT/build-tools/" | tail -n 1)
|
|
echo "ANDROID_SIGN_TOOL_VERSION=$BUILD_TOOL_VERSION" >> $GITHUB_ENV
|
|
|
|
- uses: https://github.com/r0adkll/sign-android-release@v1
|
|
name: Sign universal APK
|
|
if: env.ANDROID_SIGNING_KEY != null
|
|
id: sign-rustdesk
|
|
with:
|
|
releaseDirectory: ./signed-apk
|
|
signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }}
|
|
alias: ${{ secrets.ANDROID_ALIAS }}
|
|
keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }}
|
|
keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
|
env:
|
|
BUILD_TOOLS_VERSION: ${{ env.ANDROID_SIGN_TOOL_VERSION }}
|
|
|
|
- name: Upload signed universal APK
|
|
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
|
with:
|
|
name: rustdesk-${{ env.VERSION }}-universal.apk
|
|
path: ${{ steps.sign-rustdesk.outputs.signedReleaseFile }}
|
|
|
|
- name: Upload unsigned universal APK
|
|
if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
|
|
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
|
|
with:
|
|
name: rustdesk-${{ env.VERSION }}-universal.apk
|
|
path: signed-apk/rustdesk-${{ env.VERSION }}-universal${{ env.suffix }}.apk
|