Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
dabffac
Add UE docker image build with Android support
tustanivsky Oct 30, 2025
1b44b84
Trigger
tustanivsky Oct 30, 2025
50418d1
Revert
tustanivsky Oct 30, 2025
5973587
Test
tustanivsky Oct 30, 2025
c547465
Temp disable Linux arm64
tustanivsky Oct 30, 2025
ede89b9
Test
tustanivsky Oct 30, 2025
58a8105
Test
tustanivsky Oct 31, 2025
d80f463
Add dokerfile for ue 4.27
tustanivsky Oct 31, 2025
3f8215f
Try use latest ue4-docker
tustanivsky Oct 31, 2025
ac3ddc7
Fix typo
tustanivsky Oct 31, 2025
19a02a0
Try reduce build time
tustanivsky Nov 1, 2025
6bf6306
Test arm64 exclude for ue 4.27
tustanivsky Nov 1, 2025
bb1fd49
Test
tustanivsky Nov 1, 2025
a45578d
Add Android packaging to ci
tustanivsky Nov 1, 2025
7469af1
Add 5.1 dockerfile
tustanivsky Nov 1, 2025
9053b17
Test
tustanivsky Nov 1, 2025
9e65bbc
Test
tustanivsky Nov 1, 2025
c9b89d2
Test
tustanivsky Nov 1, 2025
5a83eec
Test
tustanivsky Nov 1, 2025
4c376b9
Test
tustanivsky Nov 1, 2025
d525c1b
Test
tustanivsky Nov 1, 2025
bb2d1c2
Test
tustanivsky Nov 1, 2025
6a767cd
Test
tustanivsky Nov 2, 2025
ddc7d11
5.3 build
tustanivsky Nov 2, 2025
df9742f
test
tustanivsky Nov 2, 2025
b03abf8
Test
tustanivsky Nov 2, 2025
6af507c
Test
tustanivsky Nov 2, 2025
74617b5
Test
tustanivsky Nov 2, 2025
04af865
Test
tustanivsky Nov 2, 2025
5b3725d
Test
tustanivsky Nov 2, 2025
a9f15a4
Test
tustanivsky Nov 3, 2025
b2d92a5
Merge branch 'main' into ci/android-docker
tustanivsky Nov 3, 2025
bcff453
Test
tustanivsky Nov 3, 2025
09929a7
Test
tustanivsky Nov 3, 2025
4c202a0
Test
tustanivsky Nov 3, 2025
2523ac2
Test
tustanivsky Nov 3, 2025
adc95ad
Test
tustanivsky Nov 3, 2025
82f43c6
Clean up
tustanivsky Nov 3, 2025
1fd35b1
Clean up
tustanivsky Nov 3, 2025
76b9a0a
Remove consolidated docker file
tustanivsky Nov 3, 2025
28958d4
Add UE 5.6 Android
tustanivsky Nov 3, 2025
12bf1e8
Try larger runner
tustanivsky Nov 4, 2025
6e2c9a0
Merge branch 'main' into ci/android-docker
tustanivsky Nov 4, 2025
942d160
Add DDC caching for Android
tustanivsky Nov 4, 2025
92025bb
Reorder jobs
tustanivsky Nov 4, 2025
720f87c
Revert
tustanivsky Nov 4, 2025
3ee1cf1
Inherit secrets in Android CI workflow
tustanivsky Nov 4, 2025
ce6943d
Clean up comment
tustanivsky Nov 4, 2025
a816a23
Merge branch 'ci/android-docker' of github.com:getsentry/sentry-unrea…
tustanivsky Nov 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,18 @@ jobs:
with:
unreal-version: ${{ matrix.unreal }}

test-android:
needs: [package-preparation]
name: Android UE ${{ matrix.unreal }}
secrets: inherit
strategy:
fail-fast: false
matrix:
unreal: ['4.27', '5.1', '5.2', '5.3', '5.4', '5.5', '5.6']
uses: ./.github/workflows/test-android.yml
with:
unreal-version: ${{ matrix.unreal }}

integration-test-linux:
needs: [test-linux]
name: Linux UE ${{ matrix.unreal }}
Expand Down
201 changes: 201 additions & 0 deletions .github/workflows/test-android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
on:
workflow_call:
inputs:
unreal-version:
required: true
type: string

env:
REGISTRY: ghcr.io

jobs:
test:
name: Test
runs-on: ubuntu-latest-4-cores

steps:
- name: Free disk space
run: |
# time df -h
sudo time swapoff -a
sudo time rm -f /swapfile
sudo time rm -rf /usr/local/lib/android
sudo time rm -rf /usr/share/dotnet
sudo time rm -rf /usr/share/swift
sudo time rm -rf /usr/local/share/powershell
sudo time rm -rf /usr/local/.ghcup
sudo time rm -rf /usr/local/lib/node_modules
sudo time rm -rf /usr/local/share/boost
sudo time rm -rf /usr/lib/google-cloud-sdk
sudo time rm -rf /usr/lib/jvm
sudo time rm -rf /opt/pipx
sudo time rm -rf /opt/ghc
sudo time rm -rf "$AGENT_TOOLSDIRECTORY"
sudo time apt-get clean
sudo time rm -rf /var/lib/apt/lists/*
# time docker rmi $(docker image ls -aq)
# time du --max-depth=3 --threshold=100M -h /usr /opt /var 2>/dev/null | sort -hr
df -h

- name: Log in to GitHub package registry
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Start Docker container
env:
WORKSPACE_PATH: ${{ github.workspace }}
UNREAL_VERSION: ${{ inputs.unreal-version }}
DISALLOW_RAW_POINTERS: ${{ inputs.unreal-version == '4.27' && 'false' || 'true' }}
run: |
# We start the container with the user ID of the parent GH action user to avoid permission issues on volume.
# For UE 5.4 we have to enable ipv6 to fix container startup issues. See https://github.com/adamrehn/ue4-docker/issues/357
uid=$(id -u) # the GH action user ID
gid=1000 # the ue4 group in the docker container
user='gh'
set -x
docker network create --ipv6 --subnet 2001:0DB8::/112 ip6net
docker run -td \
--name unreal \
--volume "$WORKSPACE_PATH:/workspace" \
--workdir /workspace \
--user $uid:$gid \
--env HOME="/home/$user" \
--env PATH="/home/$user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
--env DISALLOW_RAW_POINTERS=$DISALLOW_RAW_POINTERS \
--network ip6net -p 80:80 \
ghcr.io/getsentry/unreal-docker:"$UNREAL_VERSION"-android
docker logout ghcr.io
# Add the user so it has a home directory (needed to run tests later on)
docker exec --user root unreal useradd -u $uid -g $gid --create-home $user
# Ensure the gh user owns their home directory (needed for clang++ to write temp files)
docker exec --user root unreal chown -R $uid:$gid /home/$user
# Ensure CA certs are in the right directory (needed for running tests)
docker exec --user root unreal bash -c "
mkdir -p /etc/pki/tls/certs ;
cp /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt "

# Chown some paths to the GH user to make UE5 work properly. We can't just chown the whole UnrealEngine or
# docker would implicitly have to copy it to the container and we would run out of space on the GH runner.
- name: Chown Docker container paths
env:
ENGINE_PATH: ${{ inputs.unreal-version == '4.27' && 'Programs/UnrealPak/Saved' || 'Binaries/ThirdParty/DotNet' }}
run: |
uid=$(id -u) # the GH action user ID
docker exec --user root unreal bash -c "
chown -R $uid /home/ue4/UnrealEngine/Engine/Binaries/ThirdParty/Mono/Linux ;
chown -R $uid /home/ue4/UnrealEngine/Engine/\"$ENGINE_PATH\" ;
chown -R $uid /home/ue4/UnrealEngine/Engine/Binaries/ThirdParty/USD/UsdResources/Linux ;
chown -R $uid /home/ue4/UnrealEngine/Engine/Programs/AutomationTool ;
chown -R $uid /home/ue4/android-sdk ;
mkdir -p /home/ue4/UnrealEngine/Epic/UnrealEngine && chown -R $uid /home/ue4/UnrealEngine/Epic ;
mkdir -p /home/ue4/UnrealEngine/Engine/Source/Epic/UnrealEngine && chown -R $uid /home/ue4/UnrealEngine/Engine/Source/Epic ;
mkdir -p /home/ue4/UnrealEngine/Engine/Intermediate/Build/BuildCookRun && chown -R $uid /home/ue4/UnrealEngine/Engine/Intermediate/Build/BuildCookRun ;
mkdir -p /home/ue4/.config/Epic/UnrealEngine && chown -R $uid /home/ue4/.config ;
mkdir -p /home/ue4/UnrealEngine/UnrealTrace && chown -R $uid /home/ue4/UnrealEngine/UnrealTrace ;
mkdir -p /home/ue4/.gradle && chown -R $uid /home/ue4/.gradle ;
mkdir -p /home/gh/.cache/tmp && chown -R $uid /home/gh/.cache ;
mkdir -p /home/gh/Library/Logs && chown -R $uid /home/gh/Library "

- name: Download package
uses: actions/download-artifact@v4
with:
name: ${{ github.sha }}

- uses: actions/checkout@v4
with:
path: checkout
submodules: recursive

- name: Extract package to sample/Plugins
env:
UNREAL_VERSION: ${{ inputs.unreal-version }}
run: unzip sentry-unreal-*-engine"$UNREAL_VERSION".zip -d checkout/sample/Plugins/sentry

- name: Compute DDC cache key
id: ddc-cache-key
run: |
HASH="${{ hashFiles('checkout/sample/Content/**', 'checkout/sample/Config/**/*.ini', 'checkout/sample/*.uproject') }}"
KEY="ue-${{ inputs.unreal-version }}-android-ddc-${HASH}"
echo "key=${KEY}" >> $GITHUB_OUTPUT
echo "DDC cache key: ${KEY}"

- name: Configure project-local DDC
shell: pwsh
run: ./checkout/scripts/configure-local-ddc.ps1 -ProjectPath checkout/sample

- name: Restore cached DDC
id: cache-ddc
uses: actions/cache/restore@v4
with:
path: checkout/sample/DerivedDataCache
key: ${{ steps.ddc-cache-key.outputs.key }}
restore-keys: |
ue-${{ inputs.unreal-version }}-android-ddc

- name: Set permissions for sample
# sentry-native requires write access to sample project directory in order to initialize itself properly
run: docker exec -w /workspace/checkout unreal chmod -R +x sample

- name: Set execute permission for Python3
# Python3 is needed for post-build symbol upload script
run: docker exec --user root unreal chmod +x /home/ue4/UnrealEngine/Engine/Binaries/ThirdParty/Python3/Linux/bin/python3

- name: Update engine's build configuration
run: |
docker exec unreal bash -c "
mkdir -p ~/.config/Unreal\ Engine/UnrealBuildTool ;
cp /workspace/checkout/.github/BuildConfiguration.xml ~/.config/Unreal\ Engine/UnrealBuildTool/ "

- name: Build Android package
id: build-android
env:
SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY: true
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
run: |
docker exec -w /workspace/checkout/sample \
-e TMPDIR=/home/gh/.cache/tmp \
-e SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY="$SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY" \
-e SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN" \
-e SENTRY_ORG="$SENTRY_ORG" \
-e SENTRY_PROJECT="$SENTRY_PROJECT" \
unreal /home/ue4/UnrealEngine/Engine/Build/BatchFiles/RunUAT.sh BuildCookRun \
-project=/workspace/checkout/sample/SentryPlayground.uproject \
-archivedirectory=/workspace/checkout/sample/Builds \
-platform=Android \
-clientconfig=Development \
-nop4 \
-cook \
-iterate \
-build \
-stage \
-prereqs \
-package \
-archive

- name: Save DDC to cache
if: ${{ success() && steps.cache-ddc.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: checkout/sample/DerivedDataCache
key: ${{ steps.ddc-cache-key.outputs.key }}

- name: Collect build logs on failure
if: ${{ always() && steps.build-android.outcome == 'failure' }}
uses: actions/upload-artifact@v4
with:
name: UE ${{ inputs.unreal-version }} Android build logs
path: |
checkout/sample/Saved/Logs

- name: Upload Android build
if: ${{ success() && steps.build-android.outcome == 'success' }}
uses: actions/upload-artifact@v4
with:
name: UE ${{ inputs.unreal-version }} sample build (Android)
path: checkout/sample/Builds/Android/
retention-days: 1
129 changes: 129 additions & 0 deletions .github/workflows/ue-docker-android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Build UE Android Docker image

on:
workflow_dispatch:
inputs:
ue_version:
description: Select Unreal Engine version
required: true
type: choice
options:
- 4.27
- 5.1
- 5.2
- 5.3
- 5.4
- 5.5
- 5.6
ue_repo:
description: Set Unreal Engine repository
required: true
type: string
default: 'https://github.com/getsentry/UnrealEngine.git'
clean_disk:
description: Clean up disk space before Docker build
required: true
type: boolean
default: true

env:
REGISTRY: ghcr.io

jobs:
build:
name: 'Build for UE ${{ inputs.ue_version }} (Android)'
runs-on: ubuntu-latest-32-cores

permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v4

# Building docker images for Android requires extra disk space for SDK/NDK
- name: Clean up disk space before Docker build
if: ${{ inputs.clean_disk == true }}
run: |
# time df -h
sudo time swapoff -a
sudo time rm -f /swapfile
sudo time rm -rf /usr/local/lib/android
sudo time rm -rf /usr/share/dotnet
sudo time rm -rf /usr/share/swift
sudo time rm -rf /usr/local/share/powershell
sudo time rm -rf /usr/local/.ghcup
sudo time rm -rf /usr/local/lib/node_modules
sudo time rm -rf /usr/local/share/boost
sudo time rm -rf /usr/lib/google-cloud-sdk
sudo time rm -rf /usr/lib/jvm
sudo time rm -rf /opt/pipx
sudo time rm -rf /opt/ghc
sudo time rm -rf "$AGENT_TOOLSDIRECTORY"
sudo time apt-get clean
sudo time rm -rf /var/lib/apt/lists/*
# time docker rmi $(docker image ls -aq)
# time du --max-depth=3 --threshold=100M -h /usr /opt /var 2>/dev/null | sort -hr
df -h
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12.8'
architecture: 'x64'

- name: Install latest ue4-docker from PyPI
run: pip install ue4-docker

- name: Configure unreal-docker
run: |
ue4-docker setup
- name: Set Linux ARM platform name based on UE version
id: set_linux_arm_platform
env:
UE_VERSION: ${{ inputs.ue_version }}
run: |
# UE 4.27 uses "LinuxAArch64", UE 5.x uses "LinuxArm64"
if [[ "$UE_VERSION" == "4.27" ]]; then
echo "platform_name=LinuxAArch64" >> $GITHUB_OUTPUT
else
echo "platform_name=LinuxArm64" >> $GITHUB_OUTPUT
fi
- name: Build Unreal Engine Docker image with Android support
env:
UE_REPO: ${{ inputs.ue_repo }}
UE_VERSION: ${{ inputs.ue_version }}
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
LINUX_ARM_PLATFORM: ${{ steps.set_linux_arm_platform.outputs.platform_name }}
run: |
ue4-docker build custom -repo="$UE_REPO" -branch="$UE_VERSION" \
-basetag ubuntu22.04 \
-suffix "$UE_VERSION" \
-username="$DOCKER_USERNAME" \
-password="$DOCKER_TOKEN" \
--linux \
--target minimal \
--exclude debug \
--exclude templates \
--exclude ddc \
--prerequisites-dockerfile="./docker/ue-android-prerequisites-$UE_VERSION.dockerfile" \
--opt gitdependencies_args="--exclude=Mac --exclude=Win32 --exclude=Win64 --exclude=$LINUX_ARM_PLATFORM" \
--opt buildgraph_args="-set:HostPlatformOnly=false -set:WithAndroid=true -set:With${LINUX_ARM_PLATFORM}=false -set:WithClient=false -set:WithServer=false"
- name: Log in to GitHub package registry
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Tag and push Docker image with pre-built Unreal Engine
env:
UE_VERSION: ${{ inputs.ue_version }}
run: |
docker tag "adamrehn/ue4-minimal:custom-$UE_VERSION" "$REGISTRY/getsentry/unreal-docker:$UE_VERSION-android"
docker push "$REGISTRY/getsentry/unreal-docker:$UE_VERSION-android"
44 changes: 44 additions & 0 deletions docker/ue-android-prerequisites-4.27.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
ARG NAMESPACE
ARG PREREQS_TAG
FROM ${NAMESPACE}/ue4-base-build-prerequisites:${PREREQS_TAG}

# Switch to root to install additional packages
USER root

# Install Java 11 (required for UE 4.27 Android builds)
RUN apt-get update && apt-get install -y --no-install-recommends \
openjdk-11-jdk \
wget \
unzip && \
rm -rf /var/lib/apt/lists/*

# Set up environment variables for Android SDK/NDK
# Unreal Engine checks multiple environment variable names, so we set all of them
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
ENV ANDROID_HOME=/home/ue4/android-sdk
ENV ANDROID_SDK_ROOT=/home/ue4/android-sdk
ENV ANDROID_NDK=/home/ue4/android-sdk/ndk/21.1.6352462
ENV ANDROID_NDK_ROOT=/home/ue4/android-sdk/ndk/21.1.6352462
ENV NDKROOT=/home/ue4/android-sdk/ndk/21.1.6352462
ENV NDK_ROOT=/home/ue4/android-sdk/ndk/21.1.6352462
ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools

# Switch to ue4 user for SDK installation (to ensure correct permissions)
USER ue4

# Download and install Android command-line tools
RUN mkdir -p ${ANDROID_HOME}/cmdline-tools && \
cd ${ANDROID_HOME}/cmdline-tools && \
wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip && \
unzip -q commandlinetools-linux-9477386_latest.zip && \
rm commandlinetools-linux-9477386_latest.zip && \
mv cmdline-tools latest

# Accept licenses and install Android SDK components
# UE 4.27 requires: API Level 29, Build Tools 29.0.2, NDK r21b (21.1.6352462)
RUN yes | ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --licenses && \
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager \
"platform-tools" \
"platforms;android-29" \
"build-tools;29.0.2" \
"ndk;21.1.6352462"
Loading