Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
68f9046
feat(ios): headers-spec layout + ReactNativeHeaders compose
chrfalch Jun 18, 2026
705b310
refactor(ios): remove clang VFS overlay, resolve headers via frameworks
chrfalch Jun 18, 2026
9ee4199
fix(ios): serve the react/ namespace as a module for SPM consumers
chrfalch Jun 21, 2026
18735a0
fix(cocoapods): install prebuilt RNCore pods as header-less facades
chrfalch Jun 22, 2026
02f3500
style: apply prettier to ios-prebuild scripts and docs
chrfalch Jun 22, 2026
977f1ae
ci(ios): include ReactNativeHeaders.xcframework in the prebuilt core …
chrfalch Jun 22, 2026
ec979d3
feat(ios): expose allowlisted private React headers in the React modu…
chrfalch Jun 23, 2026
556abab
feat(ios): emit per-namespace umbrella for React_RCTAppDelegate (R10)
chrfalch Jun 23, 2026
e53e6b2
fix(ios): re-vend RCTFabricComponentsPlugins.h from the React-RCTFabr…
chrfalch Jun 24, 2026
42d8310
fix(ios-prebuild): fail closed when a deps namespace is missing from …
chrfalch Jun 24, 2026
51d4e7e
fix(ios-prebuild): stage deps headers in compose-xcframework + sort t…
chrfalch Jun 25, 2026
7b3be97
fix(ios): harden prebuilt header layout consumption (review findings)
chrfalch Jul 3, 2026
cd67dee
feat(ios-prebuild): generator-time headers gate + drift hardening (R1…
chrfalch Jul 3, 2026
e6ab638
style: prettier-format headers-rules.md (format-check lints md too)
chrfalch Jul 3, 2026
6648f90
style: add language tags to headers-rules.md fenced blocks (markdownl…
chrfalch Jul 3, 2026
dcb5ad8
style: sort requires in headers-inventory.js (eslint sort-imports, ma…
chrfalch Jul 3, 2026
b4b1a94
fix(ios-prebuild): do not relocate SocketRocket headers into ReactNat…
chrfalch Jul 3, 2026
405adbd
feat(ios-prebuild): embed React.framework's non-header resources for …
chrfalch Jun 22, 2026
562985d
fix(cocoapods): define podspec_dir in RNCoreFacades.generate
chrfalch Jun 25, 2026
f661037
fix(cocoapods): harden prebuilt-deps header search paths and artifact…
chrfalch Jul 6, 2026
14d3282
feat(cocoapods): dependency-only facades for third-party pods in preb…
chrfalch Jul 6, 2026
4330477
feat(ios-prebuild): SocketRocket privacy manifest + Xcode 26 header l…
chrfalch Jul 6, 2026
017ca51
chore: prettier formatting for prebuilt-deps doc and configuration.js
chrfalch Jul 6, 2026
6917845
feat(ios-prebuild): emit ReactNativeDependenciesHeaders.xcframework s…
chrfalch Jul 6, 2026
a6a3c04
feat(ios-prebuild)!: make ReactNativeHeaders pure-RN
chrfalch Jul 6, 2026
2e489f4
ci: cover rn-tester with prebuilt artifacts + dynamic frameworks
chrfalch Jul 6, 2026
49c3e7e
feat(releases): publish ReactNativeHeaders + ReactNativeDependenciesH…
chrfalch Jul 6, 2026
0c44552
test: update verifyArtifactsAreOnMaven test for classifier HEAD-checks
chrfalch Jul 6, 2026
12ddc13
feat(spm): SwiftPM package generation tooling
chrfalch Jun 20, 2026
59033d3
feat(spm): rn-tester + helloworld SPM consumption & test library
chrfalch Jun 20, 2026
95a79da
feat(spm): drop consumer-side headers compose; don't ship build-only …
chrfalch Jun 22, 2026
3158684
feat(spm): redesign `react-native spm` to add/update/deinit; drop fro…
chrfalch Jun 25, 2026
b587ece
fix(spm): Flow/ESLint/Prettier compliance for the SPM tooling
chrfalch Jun 25, 2026
3c0248c
chore(spm): drop in-repo SPM example xcodeprojs from rn-tester/hellow…
chrfalch Jun 25, 2026
3167024
feat(spm): wire ReactNativeDependenciesHeaders as the 5th binaryTarget
chrfalch Jul 6, 2026
19609e1
fix(spm): migration fixes surfaced by rn-tester + helloworld SPM builds
chrfalch Jul 6, 2026
f05129b
fix(spm): harden shell usage + hashing flagged by CodeQL
chrfalch Jul 6, 2026
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
9 changes: 9 additions & 0 deletions .github/actions/build-npm-package/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ runs:
pattern: ReactCore*
path: ./packages/react-native/ReactAndroid/external-artifacts/artifacts
merge-multiple: true
# ReactNativeDependenciesHeaders* is already covered by the
# ReactNativeDependencies* pattern above; ReactNativeHeaders* needs its own.
- name: Download ReactNativeHeaders artifacts
if: ${{ inputs.skip-apple-prebuilts != 'true' }}
uses: actions/download-artifact@v7
with:
pattern: ReactNativeHeaders*
path: ./packages/react-native/ReactAndroid/external-artifacts/artifacts
merge-multiple: true
- name: Print Artifacts Directory
if: ${{ inputs.skip-apple-prebuilts != 'true' }}
shell: bash
Expand Down
37 changes: 30 additions & 7 deletions .github/actions/test-ios-rntester/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,18 @@ inputs:
required: false
default: false
use-frameworks:
description: Whether we have to build with Dynamic Frameworks. If this is set to true, it builds from source
description: Whether we have to build with Dynamic Frameworks.
required: false
default: false
use-prebuilds:
description: >-
Whether to consume the prebuilt ReactCore/ReactNativeDependencies
artifacts. 'auto' (default) keeps the historical coupling: prebuilds for
static, source for dynamic frameworks. Pass 'true' with
use-frameworks:true for the prebuilt + dynamic-frameworks lane (the
config of the 2026-07-03 SocketRocket dual-copy regression).
required: false
default: auto

runs:
using: composite
Expand All @@ -41,33 +50,47 @@ runs:
- name: Prepare IOS Tests
if: ${{ inputs.run-unit-tests == 'true' }}
uses: ./.github/actions/prepare-ios-tests
- name: Resolve prebuilds mode
id: prebuilds
shell: bash
run: |
if [[ "${{ inputs.use-prebuilds }}" == "auto" ]]; then
# Historical coupling: prebuilds for static, source for dynamic frameworks.
if [[ "${{ inputs.use-frameworks }}" == "true" ]]; then
echo "enabled=false" >> "$GITHUB_OUTPUT"
else
echo "enabled=true" >> "$GITHUB_OUTPUT"
fi
else
echo "enabled=${{ inputs.use-prebuilds }}" >> "$GITHUB_OUTPUT"
fi
- name: Download ReactNativeDependencies
if: ${{ inputs.use-frameworks == 'false' }}
if: ${{ steps.prebuilds.outputs.enabled == 'true' }}
uses: actions/download-artifact@v7
with:
name: ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/third-party/
- name: Print third-party folder
if: ${{ inputs.use-frameworks == 'false' }}
if: ${{ steps.prebuilds.outputs.enabled == 'true' }}
shell: bash
run: ls -lR /tmp/third-party
- name: Download React Native Prebuilds
if: ${{ inputs.use-frameworks == 'false' }}
if: ${{ steps.prebuilds.outputs.enabled == 'true' }}
uses: actions/download-artifact@v7
with:
name: ReactCore${{ inputs.flavor }}.xcframework.tar.gz
path: /tmp/ReactCore
- name: Print ReactCore folder
if: ${{ inputs.use-frameworks == 'false' }}
if: ${{ steps.prebuilds.outputs.enabled == 'true' }}
shell: bash
run: ls -lR /tmp/ReactCore
- name: Install CocoaPods dependencies
shell: bash
run: |
if [[ ${{ inputs.use-frameworks }} == "true" ]]; then
export USE_FRAMEWORKS=dynamic
else
# If use-frameworks is false, let's use prebuilds
fi
if [[ "${{ steps.prebuilds.outputs.enabled }}" == "true" ]]; then
export RCT_USE_LOCAL_RN_DEP="/tmp/third-party/ReactNativeDependencies${{ inputs.flavor }}.xcframework.tar.gz"
export RCT_TESTONLY_RNCORE_TARBALL_PATH="/tmp/ReactCore/ReactCore${{ inputs.flavor }}.xcframework.tar.gz"
fi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,47 @@ jest.mock('../utils.js', () => ({
process.exit = mockExit;
global.fetch = mockFetch;

const BASE_URL =
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts';

// The verifier HEAD-checks the POM plus every classifier tarball attached to
// the react-native-artifacts publication (external-artifacts/build.gradle.kts).
const expectedUrls = version => [
`${BASE_URL}/${version}/react-native-artifacts-${version}.pom`,
...[
'reactnative-core-debug',
'reactnative-core-release',
'reactnative-dependencies-debug',
'reactnative-dependencies-release',
'reactnative-headers-debug',
'reactnative-headers-release',
'reactnative-dependencies-headers-debug',
'reactnative-dependencies-headers-release',
].map(
classifier =>
`${BASE_URL}/${version}/react-native-artifacts-${version}-${classifier}.tar.gz`,
),
];

describe('#verifyArtifactsAreOnMaven', () => {
beforeEach(jest.clearAllMocks);

it('waits for the packages to be published on maven when version has no v', async () => {
mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => {
throw new Error('Should not be called again!');
});
// First attempt: the POM is not there yet. Second attempt: every URL is.
mockFetch
.mockReturnValueOnce(Promise.resolve({status: 404}))
.mockReturnValueOnce(Promise.resolve({status: 200}));
.mockReturnValue(Promise.resolve({status: 200}));

const version = '0.78.1';
await verifyArtifactsAreOnMaven(version);

expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
for (const url of expectedUrls('0.78.1')) {
expect(mockFetch).toHaveBeenCalledWith(url, {method: 'HEAD'});
}
});

it('waits for the packages to be published on maven, when version starts with v', async () => {
Expand All @@ -48,27 +71,46 @@ describe('#verifyArtifactsAreOnMaven', () => {
});
mockFetch
.mockReturnValueOnce(Promise.resolve({status: 404}))
.mockReturnValueOnce(Promise.resolve({status: 200}));
.mockReturnValue(Promise.resolve({status: 200}));

const version = 'v0.78.1';
await verifyArtifactsAreOnMaven(version);

expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
for (const url of expectedUrls('0.78.1')) {
expect(mockFetch).toHaveBeenCalledWith(url, {method: 'HEAD'});
}
});

it('passes immediately if packages are already on Maven', async () => {
mockFetch.mockReturnValueOnce(Promise.resolve({status: 200}));
mockFetch.mockReturnValue(Promise.resolve({status: 200}));

const version = '0.78.1';
await verifyArtifactsAreOnMaven(version);

expect(mockSleep).toHaveBeenCalledTimes(0);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
);
// All nine URLs (POM + 8 classifier tarballs) are verified in one pass.
expect(mockFetch).toHaveBeenCalledTimes(9);
for (const url of expectedUrls('0.78.1')) {
expect(mockFetch).toHaveBeenCalledWith(url, {method: 'HEAD'});
}
});

it('waits when a classifier artifact is missing even though the POM exists', async () => {
mockSleep.mockReturnValueOnce(Promise.resolve()).mockImplementation(() => {
throw new Error('Should not be called again!');
});
// First attempt: POM ok, first classifier missing. Second attempt: all ok.
mockFetch
.mockReturnValueOnce(Promise.resolve({status: 200}))
.mockReturnValueOnce(Promise.resolve({status: 404}))
.mockReturnValue(Promise.resolve({status: 200}));

const version = '0.78.1';
await verifyArtifactsAreOnMaven(version);

expect(mockSleep).toHaveBeenCalledTimes(1);
expect(mockExit).not.toHaveBeenCalled();
});

it('tries 90 times and then exits', async () => {
Expand All @@ -82,6 +124,7 @@ describe('#verifyArtifactsAreOnMaven', () => {
expect(mockExit).toHaveBeenCalledWith(1);
expect(mockFetch).toHaveBeenCalledWith(
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/0.78.1/react-native-artifacts-0.78.1.pom',
{method: 'HEAD'},
);
});
});
45 changes: 36 additions & 9 deletions .github/workflow-scripts/verifyArtifactsAreOnMaven.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @format
*/

// @flow
const {log, sleep} = require('./utils');

const SLEEP_S = 60; // 1 minute
Expand All @@ -15,23 +16,49 @@ const ARTIFACT_URL =
'https://repo1.maven.org/maven2/com/facebook/react/react-native-artifacts/';
const ARTIFACT_NAME = 'react-native-artifacts-';

// The classifier-suffixed tarballs attached to the react-native-artifacts
// publication (external-artifacts/build.gradle.kts). The POM check alone
// would pass even when a classifier artifact never made it to Maven.
const ARTIFACT_CLASSIFIERS = [
'reactnative-core-debug',
'reactnative-core-release',
'reactnative-dependencies-debug',
'reactnative-dependencies-release',
'reactnative-headers-debug',
'reactnative-headers-release',
'reactnative-dependencies-headers-debug',
'reactnative-dependencies-headers-release',
];

async function verifyArtifactsAreOnMaven(version, retries = MAX_RETRIES) {
if (version.startsWith('v')) {
version = version.substring(1);
}

const artifactUrl = `${ARTIFACT_URL}${version}/${ARTIFACT_NAME}${version}.pom`;
const urls = [
`${ARTIFACT_URL}${version}/${ARTIFACT_NAME}${version}.pom`,
...ARTIFACT_CLASSIFIERS.map(
classifier =>
`${ARTIFACT_URL}${version}/${ARTIFACT_NAME}${version}-${classifier}.tar.gz`,
),
];
for (let currentAttempt = 1; currentAttempt <= retries; currentAttempt++) {
const response = await fetch(artifactUrl);

if (response.status !== 200) {
log(
`${currentAttempt}) Artifact's for version ${version} are not on maven yet.\nURL: ${artifactUrl}\nLet's wait a minute and try again.\n`,
);
await sleep(SLEEP_S);
} else {
let missingUrl = null;
for (const url of urls) {
const response = await fetch(url, {method: 'HEAD'});
if (response.status !== 200) {
missingUrl = url;
break;
}
}

if (missingUrl == null) {
return;
}
log(
`${currentAttempt}) Artifact's for version ${version} are not on maven yet.\nURL: ${missingUrl}\nLet's wait a minute and try again.\n`,
);
await sleep(SLEEP_S);
}

log(
Expand Down
48 changes: 47 additions & 1 deletion .github/workflows/prebuild-ios-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,24 @@ jobs:
pattern: prebuild-ios-core-headers-${{ matrix.flavor }}-*
path: packages/react-native/.build/headers
merge-multiple: true
- name: Download ReactNativeDependencies
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
uses: actions/download-artifact@v7
with:
name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
path: /tmp/third-party/
- name: Extract ReactNativeDependencies
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
shell: bash
run: |
# ReactNativeHeaders.xcframework is pure-RN (the deps namespaces ship
# in the ReactNativeDependenciesHeaders sidecar built by the deps
# prebuild), but the headers-verify compile gates still need the deps
# headers on their include path (folly/glog/... reached from RN's
# public headers), so the deps artifact is staged here too.
tar -xzf /tmp/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz -C /tmp/third-party/
mkdir -p packages/react-native/third-party/
mv /tmp/third-party/packages/react-native/third-party/ReactNativeDependencies.xcframework packages/react-native/third-party/ReactNativeDependencies.xcframework
- name: Setup Keychain
if: ${{ steps.restore-ios-xcframework.outputs.cache-hit != 'true' && env.REACT_ORG_CODE_SIGNING_P12_CERT != '' }}
uses: apple-actions/import-codesign-certs@v3 # https://github.com/marketplace/actions/import-code-signing-certificates
Expand All @@ -173,16 +191,38 @@ jobs:
run: |
cd packages/react-native
node scripts/ios-prebuild -c -f "${{ matrix.flavor }}" -i "React Org"
- name: Verify composed headers
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
run: |
# Generator-time header gate: include-health ratchet, structural
# byte-compare of module maps/umbrellas against the spec render, and
# compile smokes (React module + every namespace module + the
# privileged-consumer/Expo fixtures). Catches consumer-facing header
# regressions here instead of in downstream builds.
cd packages/react-native
node scripts/ios-prebuild/headers-verify.js --flavor "${{ matrix.flavor }}"
- name: Compress and Rename XCFramework
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}
tar -cz -f ../ReactCore${{matrix.flavor}}.xcframework.tar.gz React.xcframework
# Ship BOTH xcframeworks: React-Core-prebuilt's prepare_command flattens
# ReactNativeHeaders.xcframework's Headers (incl. module.modulemap) into the
# pod. Omitting it leaves consumers without React-Core-prebuilt/Headers/module.modulemap.
tar -cz -f ../ReactCore${{matrix.flavor}}.xcframework.tar.gz React.xcframework ReactNativeHeaders.xcframework
- name: Compress and Rename dSYM
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
run: |
cd packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}/Symbols
tar -cz -f ../../ReactCore${{ matrix.flavor }}.framework.dSYM.tar.gz .
- name: Rename ReactNativeHeaders XCFramework tarball
if: steps.restore-ios-xcframework.outputs.cache-hit != 'true'
run: |
# The compose step already tars ReactNativeHeaders.xcframework standalone;
# published as its own Maven artifact (classifier reactnative-headers-*)
# so SwiftPM consumers can wire it as a separate binaryTarget. It also
# ships inside the ReactCore tarball for the CocoaPods pod.
cp packages/react-native/.build/output/xcframeworks/${{matrix.flavor}}/ReactNativeHeaders.xcframework.tar.gz \
packages/react-native/.build/output/xcframeworks/ReactNativeHeaders${{matrix.flavor}}.xcframework.tar.gz
- name: Upload XCFramework Artifact
uses: actions/upload-artifact@v6
with:
Expand All @@ -193,11 +233,17 @@ jobs:
with:
name: ReactCore${{ matrix.flavor }}.framework.dSYM.tar.gz
path: packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
- name: Upload ReactNativeHeaders XCFramework Artifact
uses: actions/upload-artifact@v6
with:
name: ReactNativeHeaders${{ matrix.flavor }}.xcframework.tar.gz
path: packages/react-native/.build/output/xcframeworks/ReactNativeHeaders${{matrix.flavor}}.xcframework.tar.gz
- name: Save cache if present
if: ${{ github.ref == 'refs/heads/main' }} # To avoid that the cache explode
uses: actions/cache/save@v5
with:
path: |
packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.xcframework.tar.gz
packages/react-native/.build/output/xcframeworks/ReactCore${{matrix.flavor}}.framework.dSYM.tar.gz
packages/react-native/.build/output/xcframeworks/ReactNativeHeaders${{matrix.flavor}}.xcframework.tar.gz
key: v2-ios-core-xcframework-${{ matrix.flavor }}-${{ hashFiles('packages/react-native/Package.swift', 'packages/react-native/scripts/ios-prebuild/*.js', 'packages/react-native/scripts/ios-prebuild.js', 'packages/react-native/React/**/*', 'packages/react-native/ReactCommon/**/*', 'packages/react-native/Libraries/**/*') }}
18 changes: 15 additions & 3 deletions .github/workflows/prebuild-ios-dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ jobs:
with:
path: |
packages/react-native/third-party/
key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v4-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js', 'scripts/releases/ios-prebuild/compose-framework.js') }}
# If cache hit, we already have our binary. We don't need to do anything.
- name: Yarn Install
if: steps.restore-xcframework.outputs.cache-hit != 'true'
Expand Down Expand Up @@ -164,7 +164,13 @@ jobs:
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: |
tar -cz -f packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz \
packages/react-native/third-party/ReactNativeDependencies.xcframework
packages/react-native/third-party/ReactNativeDependencies.xcframework \
packages/react-native/third-party/ReactNativeDependenciesHeaders.xcframework
- name: Compress Headers Sidecar XCFramework
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: |
tar -cz -f packages/react-native/third-party/ReactNativeDependenciesHeaders${{ matrix.flavor }}.xcframework.tar.gz \
packages/react-native/third-party/ReactNativeDependenciesHeaders.xcframework
- name: Show Symbol folder content
if: steps.restore-xcframework.outputs.cache-hit != 'true'
run: ls -lR packages/react-native/third-party/Symbols
Expand All @@ -179,6 +185,11 @@ jobs:
with:
name: ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
path: packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
- name: Upload Headers Sidecar XCFramework Artifact
uses: actions/upload-artifact@v6
with:
name: ReactNativeDependenciesHeaders${{ matrix.flavor }}.xcframework.tar.gz
path: packages/react-native/third-party/ReactNativeDependenciesHeaders${{ matrix.flavor }}.xcframework.tar.gz
- name: Upload dSYM Artifact
uses: actions/upload-artifact@v6
with:
Expand All @@ -191,5 +202,6 @@ jobs:
with:
path: |
packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.xcframework.tar.gz
packages/react-native/third-party/ReactNativeDependenciesHeaders${{ matrix.flavor }}.xcframework.tar.gz
packages/react-native/third-party/ReactNativeDependencies${{ matrix.flavor }}.framework.dSYM.tar.gz
key: v3-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js') }}
key: v4-ios-dependencies-xcframework-${{ matrix.flavor }}-${{ hashfiles('scripts/releases/ios-prebuild/configuration.js', 'scripts/releases/ios-prebuild/compose-framework.js') }}
Loading
Loading