Skip to content

Android Build

Android Build #236

Workflow file for this run

# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
name: Android Build
on:
pull_request:
schedule:
# Run nightly at midnight UTC
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
local_aar:
description: 'URL to download a local AAR file. When set, the workflow will download the AAR and use it instead of the Maven dependency.'
required: false
type: string
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: LlamaDemo
path: llm/android/LlamaDemo
- name: DeepLabV3Demo
path: dl3/android/DeepLabV3Demo
- name: MV3Demo
path: mv3/android/MV3Demo
- name: YoloDemo
path: Yolo/android
- name: WhisperDemo
path: whisper/android/WhisperApp
require_aar: true
- name: ParakeetDemo
path: parakeet/android/ParakeetApp
require_aar: true
name: Build ${{ matrix.name }}
steps:
- name: Checkout repository
if: ${{ !matrix.require_aar || inputs.local_aar }}
uses: actions/checkout@v4
- name: Set up JDK 17
if: ${{ !matrix.require_aar || inputs.local_aar }}
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
if: ${{ !matrix.require_aar || inputs.local_aar }}
uses: gradle/actions/setup-gradle@v4
- name: Download local AAR
if: ${{ inputs.local_aar && (matrix.name == 'LlamaDemo' || matrix.name == 'YoloDemo' || matrix.name == 'WhisperDemo' || matrix.name == 'ParakeetDemo') }}
run: |
mkdir -p ${{ matrix.path }}/app/libs
curl -fL -o ${{ matrix.path }}/app/libs/executorch.aar "${{ inputs.local_aar }}"
- name: Build with Gradle
if: ${{ !matrix.require_aar || inputs.local_aar }}
working-directory: ${{ matrix.path }}
run: |
if [ -n "${{ inputs.local_aar }}" ] && ([ "${{ matrix.name }}" == "LlamaDemo" ] || [ "${{ matrix.name }}" == "YoloDemo" ] || [ "${{ matrix.name }}" == "WhisperDemo" ] || [ "${{ matrix.name }}" == "ParakeetDemo" ]); then
./gradlew build --no-daemon -PuseLocalAar=true
else
./gradlew build --no-daemon
fi
- name: Rename APKs with demo name
if: ${{ !matrix.require_aar || inputs.local_aar }}
working-directory: ${{ matrix.path }}/app/build/outputs/apk/
run: |
find . -name "*.apk" -type f -print0 | while IFS= read -r -d '' apk; do
dir=$(dirname "$apk")
filename=$(basename "$apk")
new_name=$(echo "$filename" | sed "s/\.apk$/-${{ matrix.name }}.apk/")
echo "Renaming $apk to $dir/$new_name"
mv "$apk" "$dir/$new_name"
done
- name: Upload build artifacts
if: ${{ !matrix.require_aar || inputs.local_aar }}
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}-apk
path: ${{ matrix.path }}/app/build/outputs/apk/
if-no-files-found: warn
create-release:
name: Create Nightly Release
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'schedule'
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4.1.3
with:
path: artifacts
- name: Generate release tag
id: tag
run: |
echo "tag_name=nightly-$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
echo "release_name=Nightly Build $(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
echo "build_date=$(date +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_OUTPUT
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.tag.outputs.tag_name }}
name: ${{ steps.tag.outputs.release_name }}
body: |
Automated nightly build of Android demo applications.
## Apps included:
- LlamaDemo APKs (`app-debug-LlamaDemo.apk`, `app-release-unsigned-LlamaDemo.apk`)
- DeepLabV3Demo APKs (`app-debug-DeepLabV3Demo.apk`, `app-release-unsigned-DeepLabV3Demo.apk`)
- MV3Demo APKs (`app-debug-MV3Demo.apk`, `app-release-unsigned-MV3Demo.apk`)
- YoloDemo APKs (`app-debug-YoloDemo.apk`, `app-release-unsigned-YoloDemo.apk`)
**Build Date:** ${{ steps.tag.outputs.build_date }}
**Commit:** ${{ github.sha }}
files: |
artifacts/*-apk/**/*.apk
prerelease: true
draft: false
- name: Clean up old nightly releases
uses: actions/github-script@v7
with:
script: |
const keep = 7; // Keep last 7 nightly releases
const owner = context.repo.owner;
const repo = context.repo.repo;
// Get all releases
const releases = await github.rest.repos.listReleases({
owner,
repo,
per_page: 100
});
// Filter nightly releases and sort by date (newest first)
const nightlyReleases = releases.data
.filter(release => release.tag_name.startsWith('nightly-'))
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
// Delete releases older than the keep threshold
for (let i = keep; i < nightlyReleases.length; i++) {
const release = nightlyReleases[i];
console.log(`Deleting old nightly release: ${release.tag_name}`);
try {
// Delete the release
await github.rest.repos.deleteRelease({
owner,
repo,
release_id: release.id
});
// Delete the tag
await github.rest.git.deleteRef({
owner,
repo,
ref: `tags/${release.tag_name}`
});
console.log(`Deleted release and tag: ${release.tag_name}`);
} catch (error) {
console.log(`Error deleting ${release.tag_name}: ${error.message}`);
}
}