Skip to content

Commit e483f5b

Browse files
committed
Upload built applications
Turn `android-build.yml` and `ios-build.yml` into reusable workflows driven by new `android.yml` / `ios.yml` entry points, and have them upload the app they built. Builds now run in Release for the simulator/emulator ABI, so the uploaded APK / .app bundle is exactly what a later job can install instead of building the app a second time.
1 parent 35a0aea commit e483f5b

4 files changed

Lines changed: 194 additions & 57 deletions

File tree

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
1-
name: Test Android build
1+
name: Build Android app
22

3+
# Reusable: builds one example app in Release and uploads the APK, so
4+
# `android-e2e.yml` can install that exact APK instead of building the app a
5+
# second time. Called by `android.yml`.
36
on:
4-
pull_request:
5-
paths:
6-
- .github/workflows/android-build.yml
7-
- packages/react-native-gesture-handler/android/**
8-
- apps/basic-example/android/**
9-
- apps/basic-example/package.json
10-
- rnrepo.config.json
11-
- yarn.lock
12-
push:
13-
branches:
14-
- main
15-
workflow_dispatch:
7+
workflow_call:
8+
inputs:
9+
app:
10+
description: Directory under apps/ holding the example app to build.
11+
required: true
12+
type: string
13+
artifact-name:
14+
description: Name to upload the built APK under.
15+
required: true
16+
type: string
17+
abi:
18+
description: ABI to build. Must match the emulator the e2e job installs the APK on.
19+
required: true
20+
type: string
1621

1722
jobs:
1823
build:
19-
if: github.repository == 'software-mansion/react-native-gesture-handler'
20-
2124
runs-on: ubuntu-latest
22-
strategy:
23-
matrix:
24-
working-directory: [apps/basic-example, apps/expo-example]
25-
concurrency:
26-
group: android-${{ matrix.working-directory }}-${{ github.ref }}
27-
cancel-in-progress: true
25+
timeout-minutes: 60
2826

2927
steps:
3028
- name: checkout
@@ -43,9 +41,18 @@ jobs:
4341
cache: yarn
4442

4543
- name: Install node dependencies
46-
working-directory: ${{ matrix.working-directory }}
44+
working-directory: apps/${{ inputs.app }}
4745
run: yarn install --immutable
4846

49-
- name: Build app
50-
working-directory: ${{ matrix.working-directory }}/android
51-
run: ./gradlew :app:assembleDebug --console=plain -PreactNativeArchitectures=arm64-v8a
47+
- name: Build app in Release mode
48+
working-directory: apps/${{ inputs.app }}/android
49+
run: ./gradlew :app:assembleRelease --console=plain -PreactNativeArchitectures=${{ inputs.abi }}
50+
51+
- name: Upload APK artifact
52+
uses: actions/upload-artifact@v4
53+
with:
54+
name: ${{ inputs.artifact-name }}
55+
path: apps/${{ inputs.app }}/android/app/build/outputs/apk/release/*.apk
56+
if-no-files-found: error
57+
compression-level: 0
58+
retention-days: 3

‎.github/workflows/android.yml‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Test Android
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- .github/workflows/android.yml
7+
- .github/workflows/android-build.yml
8+
- packages/react-native-gesture-handler/android/**
9+
- packages/react-native-gesture-handler/shared/**
10+
- packages/react-native-gesture-handler/src/specs/**
11+
- apps/basic-example/android/**
12+
- apps/basic-example/package.json
13+
- apps/expo-example/android/**
14+
- apps/expo-example/package.json
15+
- rnrepo.config.json
16+
- yarn.lock
17+
push:
18+
branches:
19+
- main
20+
workflow_dispatch:
21+
22+
concurrency:
23+
group: android-${{ github.ref }}
24+
cancel-in-progress: true
25+
26+
jobs:
27+
build:
28+
if: github.repository == 'software-mansion/react-native-gesture-handler'
29+
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
app: [basic-example, expo-example]
34+
35+
uses: ./.github/workflows/android-build.yml
36+
with:
37+
app: ${{ matrix.app }}
38+
artifact-name: android-apk-${{ matrix.app }}
39+
abi: x86_64

‎.github/workflows/ios-build.yml‎

Lines changed: 78 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,52 @@
1-
name: Test iOS build
1+
name: Build iOS app
22

3+
# Reusable: builds one example app for the simulator in Release and uploads the
4+
# .app bundle, so `ios-e2e.yml` can install that exact binary instead of
5+
# building the app a second time. Called by `ios.yml`.
36
on:
4-
pull_request:
5-
paths:
6-
- .github/workflows/ios-build.yml
7-
- packages/react-native-gesture-handler/RNGestureHandler.podspec
8-
- packages/react-native-gesture-handler/apple/**
9-
- apps/basic-example/ios/**
10-
- apps/basic-example/package.json
11-
- rnrepo.config.json
12-
- yarn.lock
13-
push:
14-
branches:
15-
- main
16-
workflow_dispatch:
7+
workflow_call:
8+
inputs:
9+
app:
10+
description: Directory under apps/ holding the example app to build.
11+
required: true
12+
type: string
13+
scheme:
14+
description: Xcode scheme of the app (also the workspace name).
15+
required: true
16+
type: string
17+
artifact-name:
18+
description: Name to upload the packaged .app bundle under.
19+
required: true
20+
type: string
21+
xcode-version:
22+
description: Xcode version to build with.
23+
required: true
24+
type: string
1725

1826
jobs:
1927
build:
20-
if: github.repository == 'software-mansion/react-native-gesture-handler'
21-
2228
runs-on: macos-26
23-
strategy:
24-
matrix:
25-
working-directory: [apps/basic-example, apps/expo-example]
26-
concurrency:
27-
group: ios-${{ matrix.working-directory }}-${{ github.ref }}
28-
cancel-in-progress: true
29+
timeout-minutes: 60
2930

3031
steps:
3132
- name: checkout
3233
uses: actions/checkout@v4
3334

34-
- name: Use latest stable Xcode
35-
uses: maxim-lobanov/setup-xcode@v1
36-
with:
37-
xcode-version: '26.4.1'
35+
- name: Select Xcode
36+
env:
37+
XCODE_VERSION: ${{ inputs.xcode-version }}
38+
run: |
39+
XCODE_APP="/Applications/Xcode_${XCODE_VERSION}.app"
40+
if [ ! -d "$XCODE_APP" ]; then
41+
echo "Xcode ${XCODE_VERSION} is not installed on this runner. Available:" >&2
42+
ls -d /Applications/Xcode*.app >&2
43+
XCODE_APP=$(ls -d /Applications/Xcode_*.app 2>/dev/null | sort -V | tail -1)
44+
[ -n "$XCODE_APP" ] || XCODE_APP=/Applications/Xcode.app
45+
echo "Falling back to $XCODE_APP" >&2
46+
fi
47+
echo "Using $XCODE_APP"
48+
echo "DEVELOPER_DIR=$XCODE_APP/Contents/Developer" >> "$GITHUB_ENV"
49+
DEVELOPER_DIR="$XCODE_APP/Contents/Developer" xcodebuild -version
3850
3951
- name: Use Node.js 24
4052
uses: actions/setup-node@v6
@@ -43,14 +55,48 @@ jobs:
4355
cache: yarn
4456

4557
- name: Install node dependencies
46-
working-directory: ${{ matrix.working-directory }}
58+
working-directory: apps/${{ inputs.app }}
4759
run: yarn install --immutable
4860

61+
# expo-example runs `expo prebuild` on postinstall, which installs its pods.
4962
- name: Install pods
50-
if: ${{ matrix.working-directory == 'apps/basic-example' }}
51-
working-directory: ${{ matrix.working-directory }}/ios
63+
if: ${{ inputs.app == 'basic-example' }}
64+
working-directory: apps/${{ inputs.app }}/ios
5265
run: bundle install && NO_FLIPPER=1 bundle exec pod install
5366

54-
- name: Build app
55-
working-directory: ${{ matrix.working-directory }}
56-
run: npx react-native run-ios
67+
- name: Build app in Release mode
68+
working-directory: apps/${{ inputs.app }}/ios
69+
run: |
70+
xcodebuild \
71+
-workspace ${{ inputs.scheme }}.xcworkspace \
72+
-scheme ${{ inputs.scheme }} \
73+
-configuration Release \
74+
-sdk iphonesimulator \
75+
-destination 'generic/platform=iOS Simulator' \
76+
-derivedDataPath build \
77+
CODE_SIGNING_ALLOWED=NO \
78+
build
79+
80+
# Artifact zips drop POSIX permissions and symlinks, which would leave the
81+
# .app with a non-executable binary — tar the bundle to keep it installable.
82+
- name: Package app bundle
83+
working-directory: apps/${{ inputs.app }}/ios
84+
run: |
85+
APP_PATH=$(find build/Build/Products/Release-iphonesimulator -maxdepth 1 -name '*.app' -type d | head -1)
86+
if [ -z "$APP_PATH" ]; then
87+
echo "Could not find built .app" >&2
88+
exit 1
89+
fi
90+
echo "Packaging $APP_PATH"
91+
mkdir -p "$RUNNER_TEMP/artifact"
92+
tar -czf "$RUNNER_TEMP/artifact/app.tar.gz" \
93+
-C "$(dirname "$APP_PATH")" "$(basename "$APP_PATH")"
94+
95+
- name: Upload app artifact
96+
uses: actions/upload-artifact@v4
97+
with:
98+
name: ${{ inputs.artifact-name }}
99+
path: ${{ runner.temp }}/artifact/app.tar.gz
100+
if-no-files-found: error
101+
compression-level: 0
102+
retention-days: 3

‎.github/workflows/ios.yml‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Test iOS
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- .github/workflows/ios.yml
7+
- .github/workflows/ios-build.yml
8+
- packages/react-native-gesture-handler/RNGestureHandler.podspec
9+
- packages/react-native-gesture-handler/apple/**
10+
- packages/react-native-gesture-handler/shared/**
11+
- packages/react-native-gesture-handler/src/specs/**
12+
- apps/basic-example/ios/**
13+
- apps/basic-example/package.json
14+
- apps/expo-example/ios/**
15+
- apps/expo-example/package.json
16+
- rnrepo.config.json
17+
- yarn.lock
18+
push:
19+
branches:
20+
- main
21+
workflow_dispatch:
22+
23+
concurrency:
24+
group: ios-${{ github.ref }}
25+
cancel-in-progress: true
26+
27+
jobs:
28+
build:
29+
if: github.repository == 'software-mansion/react-native-gesture-handler'
30+
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
include:
35+
- app: basic-example
36+
scheme: BasicExample
37+
- app: expo-example
38+
scheme: ExpoExample
39+
40+
uses: ./.github/workflows/ios-build.yml
41+
with:
42+
app: ${{ matrix.app }}
43+
scheme: ${{ matrix.scheme }}
44+
artifact-name: ios-app-${{ matrix.app }}
45+
xcode-version: '26.4.1'

0 commit comments

Comments
 (0)