Skip to content

Commit 4b53a83

Browse files
authored
chore: Add Android target support to CI (#1131)
* Add UE docker image build with Android support * Trigger * Revert * Test * Temp disable Linux arm64 * Test * Test * Add dokerfile for ue 4.27 * Try use latest ue4-docker * Fix typo * Try reduce build time * Test arm64 exclude for ue 4.27 * Test * Add Android packaging to ci * Add 5.1 dockerfile * Test * Test * Test * Test * Test * Test * Test * Test * 5.3 build * test * Test * Test * Test * Test * Test * Test * Test * Test * Test * Test * Test * Clean up * Clean up * Remove consolidated docker file * Add UE 5.6 Android * Try larger runner * Add DDC caching for Android * Reorder jobs * Revert * Inherit secrets in Android CI workflow * Clean up comment
1 parent bd53c08 commit 4b53a83

10 files changed

+650
-0
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@ jobs:
162162
with:
163163
unreal-version: ${{ matrix.unreal }}
164164

165+
test-android:
166+
needs: [package-preparation]
167+
name: Android UE ${{ matrix.unreal }}
168+
secrets: inherit
169+
strategy:
170+
fail-fast: false
171+
matrix:
172+
unreal: ['4.27', '5.1', '5.2', '5.3', '5.4', '5.5', '5.6']
173+
uses: ./.github/workflows/test-android.yml
174+
with:
175+
unreal-version: ${{ matrix.unreal }}
176+
165177
integration-test-linux:
166178
needs: [test-linux]
167179
name: Linux UE ${{ matrix.unreal }}

.github/workflows/test-android.yml

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
on:
2+
workflow_call:
3+
inputs:
4+
unreal-version:
5+
required: true
6+
type: string
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
11+
jobs:
12+
test:
13+
name: Test
14+
runs-on: ubuntu-latest-4-cores
15+
16+
steps:
17+
- name: Free disk space
18+
run: |
19+
# time df -h
20+
sudo time swapoff -a
21+
sudo time rm -f /swapfile
22+
sudo time rm -rf /usr/local/lib/android
23+
sudo time rm -rf /usr/share/dotnet
24+
sudo time rm -rf /usr/share/swift
25+
sudo time rm -rf /usr/local/share/powershell
26+
sudo time rm -rf /usr/local/.ghcup
27+
sudo time rm -rf /usr/local/lib/node_modules
28+
sudo time rm -rf /usr/local/share/boost
29+
sudo time rm -rf /usr/lib/google-cloud-sdk
30+
sudo time rm -rf /usr/lib/jvm
31+
sudo time rm -rf /opt/pipx
32+
sudo time rm -rf /opt/ghc
33+
sudo time rm -rf "$AGENT_TOOLSDIRECTORY"
34+
sudo time apt-get clean
35+
sudo time rm -rf /var/lib/apt/lists/*
36+
# time docker rmi $(docker image ls -aq)
37+
# time du --max-depth=3 --threshold=100M -h /usr /opt /var 2>/dev/null | sort -hr
38+
df -h
39+
40+
- name: Log in to GitHub package registry
41+
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
42+
with:
43+
registry: ${{ env.REGISTRY }}
44+
username: ${{ github.actor }}
45+
password: ${{ secrets.GITHUB_TOKEN }}
46+
47+
- name: Start Docker container
48+
env:
49+
WORKSPACE_PATH: ${{ github.workspace }}
50+
UNREAL_VERSION: ${{ inputs.unreal-version }}
51+
DISALLOW_RAW_POINTERS: ${{ inputs.unreal-version == '4.27' && 'false' || 'true' }}
52+
run: |
53+
# We start the container with the user ID of the parent GH action user to avoid permission issues on volume.
54+
# For UE 5.4 we have to enable ipv6 to fix container startup issues. See https://github.com/adamrehn/ue4-docker/issues/357
55+
uid=$(id -u) # the GH action user ID
56+
gid=1000 # the ue4 group in the docker container
57+
user='gh'
58+
set -x
59+
docker network create --ipv6 --subnet 2001:0DB8::/112 ip6net
60+
docker run -td \
61+
--name unreal \
62+
--volume "$WORKSPACE_PATH:/workspace" \
63+
--workdir /workspace \
64+
--user $uid:$gid \
65+
--env HOME="/home/$user" \
66+
--env PATH="/home/$user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
67+
--env DISALLOW_RAW_POINTERS=$DISALLOW_RAW_POINTERS \
68+
--network ip6net -p 80:80 \
69+
ghcr.io/getsentry/unreal-docker:"$UNREAL_VERSION"-android
70+
docker logout ghcr.io
71+
# Add the user so it has a home directory (needed to run tests later on)
72+
docker exec --user root unreal useradd -u $uid -g $gid --create-home $user
73+
# Ensure the gh user owns their home directory (needed for clang++ to write temp files)
74+
docker exec --user root unreal chown -R $uid:$gid /home/$user
75+
# Ensure CA certs are in the right directory (needed for running tests)
76+
docker exec --user root unreal bash -c "
77+
mkdir -p /etc/pki/tls/certs ;
78+
cp /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt "
79+
80+
# Chown some paths to the GH user to make UE5 work properly. We can't just chown the whole UnrealEngine or
81+
# docker would implicitly have to copy it to the container and we would run out of space on the GH runner.
82+
- name: Chown Docker container paths
83+
env:
84+
ENGINE_PATH: ${{ inputs.unreal-version == '4.27' && 'Programs/UnrealPak/Saved' || 'Binaries/ThirdParty/DotNet' }}
85+
run: |
86+
uid=$(id -u) # the GH action user ID
87+
docker exec --user root unreal bash -c "
88+
chown -R $uid /home/ue4/UnrealEngine/Engine/Binaries/ThirdParty/Mono/Linux ;
89+
chown -R $uid /home/ue4/UnrealEngine/Engine/\"$ENGINE_PATH\" ;
90+
chown -R $uid /home/ue4/UnrealEngine/Engine/Binaries/ThirdParty/USD/UsdResources/Linux ;
91+
chown -R $uid /home/ue4/UnrealEngine/Engine/Programs/AutomationTool ;
92+
chown -R $uid /home/ue4/android-sdk ;
93+
mkdir -p /home/ue4/UnrealEngine/Epic/UnrealEngine && chown -R $uid /home/ue4/UnrealEngine/Epic ;
94+
mkdir -p /home/ue4/UnrealEngine/Engine/Source/Epic/UnrealEngine && chown -R $uid /home/ue4/UnrealEngine/Engine/Source/Epic ;
95+
mkdir -p /home/ue4/UnrealEngine/Engine/Intermediate/Build/BuildCookRun && chown -R $uid /home/ue4/UnrealEngine/Engine/Intermediate/Build/BuildCookRun ;
96+
mkdir -p /home/ue4/.config/Epic/UnrealEngine && chown -R $uid /home/ue4/.config ;
97+
mkdir -p /home/ue4/UnrealEngine/UnrealTrace && chown -R $uid /home/ue4/UnrealEngine/UnrealTrace ;
98+
mkdir -p /home/ue4/.gradle && chown -R $uid /home/ue4/.gradle ;
99+
mkdir -p /home/gh/.cache/tmp && chown -R $uid /home/gh/.cache ;
100+
mkdir -p /home/gh/Library/Logs && chown -R $uid /home/gh/Library "
101+
102+
- name: Download package
103+
uses: actions/download-artifact@v4
104+
with:
105+
name: ${{ github.sha }}
106+
107+
- uses: actions/checkout@v4
108+
with:
109+
path: checkout
110+
submodules: recursive
111+
112+
- name: Extract package to sample/Plugins
113+
env:
114+
UNREAL_VERSION: ${{ inputs.unreal-version }}
115+
run: unzip sentry-unreal-*-engine"$UNREAL_VERSION".zip -d checkout/sample/Plugins/sentry
116+
117+
- name: Compute DDC cache key
118+
id: ddc-cache-key
119+
run: |
120+
HASH="${{ hashFiles('checkout/sample/Content/**', 'checkout/sample/Config/**/*.ini', 'checkout/sample/*.uproject') }}"
121+
KEY="ue-${{ inputs.unreal-version }}-android-ddc-${HASH}"
122+
echo "key=${KEY}" >> $GITHUB_OUTPUT
123+
echo "DDC cache key: ${KEY}"
124+
125+
- name: Configure project-local DDC
126+
shell: pwsh
127+
run: ./checkout/scripts/configure-local-ddc.ps1 -ProjectPath checkout/sample
128+
129+
- name: Restore cached DDC
130+
id: cache-ddc
131+
uses: actions/cache/restore@v4
132+
with:
133+
path: checkout/sample/DerivedDataCache
134+
key: ${{ steps.ddc-cache-key.outputs.key }}
135+
restore-keys: |
136+
ue-${{ inputs.unreal-version }}-android-ddc
137+
138+
- name: Set permissions for sample
139+
# sentry-native requires write access to sample project directory in order to initialize itself properly
140+
run: docker exec -w /workspace/checkout unreal chmod -R +x sample
141+
142+
- name: Set execute permission for Python3
143+
# Python3 is needed for post-build symbol upload script
144+
run: docker exec --user root unreal chmod +x /home/ue4/UnrealEngine/Engine/Binaries/ThirdParty/Python3/Linux/bin/python3
145+
146+
- name: Update engine's build configuration
147+
run: |
148+
docker exec unreal bash -c "
149+
mkdir -p ~/.config/Unreal\ Engine/UnrealBuildTool ;
150+
cp /workspace/checkout/.github/BuildConfiguration.xml ~/.config/Unreal\ Engine/UnrealBuildTool/ "
151+
152+
- name: Build Android package
153+
id: build-android
154+
env:
155+
SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY: true
156+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
157+
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
158+
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
159+
run: |
160+
docker exec -w /workspace/checkout/sample \
161+
-e TMPDIR=/home/gh/.cache/tmp \
162+
-e SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY="$SENTRY_UPLOAD_SYMBOLS_AUTOMATICALLY" \
163+
-e SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN" \
164+
-e SENTRY_ORG="$SENTRY_ORG" \
165+
-e SENTRY_PROJECT="$SENTRY_PROJECT" \
166+
unreal /home/ue4/UnrealEngine/Engine/Build/BatchFiles/RunUAT.sh BuildCookRun \
167+
-project=/workspace/checkout/sample/SentryPlayground.uproject \
168+
-archivedirectory=/workspace/checkout/sample/Builds \
169+
-platform=Android \
170+
-clientconfig=Development \
171+
-nop4 \
172+
-cook \
173+
-iterate \
174+
-build \
175+
-stage \
176+
-prereqs \
177+
-package \
178+
-archive
179+
180+
- name: Save DDC to cache
181+
if: ${{ success() && steps.cache-ddc.outputs.cache-hit != 'true' }}
182+
uses: actions/cache/save@v4
183+
with:
184+
path: checkout/sample/DerivedDataCache
185+
key: ${{ steps.ddc-cache-key.outputs.key }}
186+
187+
- name: Collect build logs on failure
188+
if: ${{ always() && steps.build-android.outcome == 'failure' }}
189+
uses: actions/upload-artifact@v4
190+
with:
191+
name: UE ${{ inputs.unreal-version }} Android build logs
192+
path: |
193+
checkout/sample/Saved/Logs
194+
195+
- name: Upload Android build
196+
if: ${{ success() && steps.build-android.outcome == 'success' }}
197+
uses: actions/upload-artifact@v4
198+
with:
199+
name: UE ${{ inputs.unreal-version }} sample build (Android)
200+
path: checkout/sample/Builds/Android/
201+
retention-days: 1
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: Build UE Android Docker image
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
ue_version:
7+
description: Select Unreal Engine version
8+
required: true
9+
type: choice
10+
options:
11+
- 4.27
12+
- 5.1
13+
- 5.2
14+
- 5.3
15+
- 5.4
16+
- 5.5
17+
- 5.6
18+
ue_repo:
19+
description: Set Unreal Engine repository
20+
required: true
21+
type: string
22+
default: 'https://github.com/getsentry/UnrealEngine.git'
23+
clean_disk:
24+
description: Clean up disk space before Docker build
25+
required: true
26+
type: boolean
27+
default: true
28+
29+
env:
30+
REGISTRY: ghcr.io
31+
32+
jobs:
33+
build:
34+
name: 'Build for UE ${{ inputs.ue_version }} (Android)'
35+
runs-on: ubuntu-latest-32-cores
36+
37+
permissions:
38+
contents: read
39+
packages: write
40+
41+
steps:
42+
- name: Checkout
43+
uses: actions/checkout@v4
44+
45+
# Building docker images for Android requires extra disk space for SDK/NDK
46+
- name: Clean up disk space before Docker build
47+
if: ${{ inputs.clean_disk == true }}
48+
run: |
49+
# time df -h
50+
sudo time swapoff -a
51+
sudo time rm -f /swapfile
52+
sudo time rm -rf /usr/local/lib/android
53+
sudo time rm -rf /usr/share/dotnet
54+
sudo time rm -rf /usr/share/swift
55+
sudo time rm -rf /usr/local/share/powershell
56+
sudo time rm -rf /usr/local/.ghcup
57+
sudo time rm -rf /usr/local/lib/node_modules
58+
sudo time rm -rf /usr/local/share/boost
59+
sudo time rm -rf /usr/lib/google-cloud-sdk
60+
sudo time rm -rf /usr/lib/jvm
61+
sudo time rm -rf /opt/pipx
62+
sudo time rm -rf /opt/ghc
63+
sudo time rm -rf "$AGENT_TOOLSDIRECTORY"
64+
sudo time apt-get clean
65+
sudo time rm -rf /var/lib/apt/lists/*
66+
# time docker rmi $(docker image ls -aq)
67+
# time du --max-depth=3 --threshold=100M -h /usr /opt /var 2>/dev/null | sort -hr
68+
df -h
69+
70+
- name: Set up Python
71+
uses: actions/setup-python@v4
72+
with:
73+
python-version: '3.12.8'
74+
architecture: 'x64'
75+
76+
- name: Install latest ue4-docker from PyPI
77+
run: pip install ue4-docker
78+
79+
- name: Configure unreal-docker
80+
run: |
81+
ue4-docker setup
82+
83+
- name: Set Linux ARM platform name based on UE version
84+
id: set_linux_arm_platform
85+
env:
86+
UE_VERSION: ${{ inputs.ue_version }}
87+
run: |
88+
# UE 4.27 uses "LinuxAArch64", UE 5.x uses "LinuxArm64"
89+
if [[ "$UE_VERSION" == "4.27" ]]; then
90+
echo "platform_name=LinuxAArch64" >> $GITHUB_OUTPUT
91+
else
92+
echo "platform_name=LinuxArm64" >> $GITHUB_OUTPUT
93+
fi
94+
95+
- name: Build Unreal Engine Docker image with Android support
96+
env:
97+
UE_REPO: ${{ inputs.ue_repo }}
98+
UE_VERSION: ${{ inputs.ue_version }}
99+
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
100+
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
101+
LINUX_ARM_PLATFORM: ${{ steps.set_linux_arm_platform.outputs.platform_name }}
102+
run: |
103+
ue4-docker build custom -repo="$UE_REPO" -branch="$UE_VERSION" \
104+
-basetag ubuntu22.04 \
105+
-suffix "$UE_VERSION" \
106+
-username="$DOCKER_USERNAME" \
107+
-password="$DOCKER_TOKEN" \
108+
--linux \
109+
--target minimal \
110+
--exclude debug \
111+
--exclude templates \
112+
--exclude ddc \
113+
--prerequisites-dockerfile="./docker/ue-android-prerequisites-$UE_VERSION.dockerfile" \
114+
--opt gitdependencies_args="--exclude=Mac --exclude=Win32 --exclude=Win64 --exclude=$LINUX_ARM_PLATFORM" \
115+
--opt buildgraph_args="-set:HostPlatformOnly=false -set:WithAndroid=true -set:With${LINUX_ARM_PLATFORM}=false -set:WithClient=false -set:WithServer=false"
116+
117+
- name: Log in to GitHub package registry
118+
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
119+
with:
120+
registry: ${{ env.REGISTRY }}
121+
username: ${{ github.actor }}
122+
password: ${{ secrets.GITHUB_TOKEN }}
123+
124+
- name: Tag and push Docker image with pre-built Unreal Engine
125+
env:
126+
UE_VERSION: ${{ inputs.ue_version }}
127+
run: |
128+
docker tag "adamrehn/ue4-minimal:custom-$UE_VERSION" "$REGISTRY/getsentry/unreal-docker:$UE_VERSION-android"
129+
docker push "$REGISTRY/getsentry/unreal-docker:$UE_VERSION-android"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
ARG NAMESPACE
2+
ARG PREREQS_TAG
3+
FROM ${NAMESPACE}/ue4-base-build-prerequisites:${PREREQS_TAG}
4+
5+
# Switch to root to install additional packages
6+
USER root
7+
8+
# Install Java 11 (required for UE 4.27 Android builds)
9+
RUN apt-get update && apt-get install -y --no-install-recommends \
10+
openjdk-11-jdk \
11+
wget \
12+
unzip && \
13+
rm -rf /var/lib/apt/lists/*
14+
15+
# Set up environment variables for Android SDK/NDK
16+
# Unreal Engine checks multiple environment variable names, so we set all of them
17+
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
18+
ENV ANDROID_HOME=/home/ue4/android-sdk
19+
ENV ANDROID_SDK_ROOT=/home/ue4/android-sdk
20+
ENV ANDROID_NDK=/home/ue4/android-sdk/ndk/21.1.6352462
21+
ENV ANDROID_NDK_ROOT=/home/ue4/android-sdk/ndk/21.1.6352462
22+
ENV NDKROOT=/home/ue4/android-sdk/ndk/21.1.6352462
23+
ENV NDK_ROOT=/home/ue4/android-sdk/ndk/21.1.6352462
24+
ENV PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools
25+
26+
# Switch to ue4 user for SDK installation (to ensure correct permissions)
27+
USER ue4
28+
29+
# Download and install Android command-line tools
30+
RUN mkdir -p ${ANDROID_HOME}/cmdline-tools && \
31+
cd ${ANDROID_HOME}/cmdline-tools && \
32+
wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip && \
33+
unzip -q commandlinetools-linux-9477386_latest.zip && \
34+
rm commandlinetools-linux-9477386_latest.zip && \
35+
mv cmdline-tools latest
36+
37+
# Accept licenses and install Android SDK components
38+
# UE 4.27 requires: API Level 29, Build Tools 29.0.2, NDK r21b (21.1.6352462)
39+
RUN yes | ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --licenses && \
40+
${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager \
41+
"platform-tools" \
42+
"platforms;android-29" \
43+
"build-tools;29.0.2" \
44+
"ndk;21.1.6352462"

0 commit comments

Comments
 (0)