diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 79d36e39..08cdacbd 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -44,12 +44,6 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - react-native: [0.87.0] - react: [19.2.8] - include: - - os: ubuntu-latest - react-native: 0.82.0 - react: 19.1.1 defaults: run: shell: bash @@ -72,19 +66,11 @@ jobs: path: | node_modules */*/node_modules - key: ${{ runner.os }}-rn-${{ matrix.react-native }}-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - name: Install dependencies run: yarn install --frozen-lockfile - - name: Install React Native ${{ matrix.react-native }} example dependencies - run: yarn add --exact "react@${{ matrix.react }}" "react-native@${{ matrix.react-native }}" + - name: Install example app dependencies + run: yarn install --frozen-lockfile working-directory: example - - name: Use RN 0.82-compatible Gradle - if: matrix.react-native == '0.82.0' - run: sed -i 's/gradle-9.4.1-bin.zip/gradle-9.0.0-bin.zip/' example/android/gradle/wrapper/gradle-wrapper.properties - name: Build Android example app - if: matrix.react-native != '0.82.0' run: ./.github/scripts/build-android.sh - - name: Compile library against the RN floor - if: matrix.react-native == '0.82.0' - run: ./gradlew :react-native-safe-area-context:compileDebugKotlin - working-directory: example/android diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml new file mode 100644 index 00000000..2905f92d --- /dev/null +++ b/.github/workflows/compatibility.yml @@ -0,0 +1,102 @@ +name: Compatibility build + +on: + push: + branches: + - main + paths: + - '.github/workflows/compatibility.yml' + - 'android/**' + - 'babel.config.js' + - 'common/**' + - 'compatibility.json' + - 'ios/**' + - 'package.json' + - 'react-native-safe-area-context.podspec' + - 'react-native.config.js' + - 'scripts/test-project' + - 'src/**' + - 'tsconfig.json' + - 'yarn.lock' + pull_request: + paths: + - '.github/workflows/compatibility.yml' + - 'android/**' + - 'babel.config.js' + - 'common/**' + - 'compatibility.json' + - 'ios/**' + - 'package.json' + - 'react-native-safe-area-context.podspec' + - 'react-native.config.js' + - 'scripts/test-project' + - 'src/**' + - 'tsconfig.json' + - 'yarn.lock' + workflow_dispatch: + +permissions: + contents: read + +jobs: + read-compatibility: + runs-on: ubuntu-latest + outputs: + react-native-versions: ${{ steps.matrix.outputs.versions }} + steps: + - uses: actions/checkout@v4 + - name: Read supported React Native versions + id: matrix + run: | + versions=$(node -e " + const compatibility = require('./compatibility.json'); + process.stdout.write( + JSON.stringify(compatibility['6.x']['react-native']) + ); + ") + echo "versions=$versions" >> "$GITHUB_OUTPUT" + + android: + name: Android (RN ${{ matrix.react-native }}) + needs: read-compatibility + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + react-native: ${{ fromJSON(needs.read-compatibility.outputs.react-native-versions) }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22.13.0 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + - run: yarn install + - name: Build fresh Android app + run: ./scripts/test-project --version ${{ matrix.react-native }} --platforms android + + ios: + name: iOS (RN ${{ matrix.react-native }}) + needs: read-compatibility + runs-on: macos-15 + strategy: + fail-fast: false + matrix: + react-native: ${{ fromJSON(needs.read-compatibility.outputs.react-native-versions) }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22.13.0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2 + - name: Select Xcode 16.4 + run: | + sudo xcode-select --switch /Applications/Xcode_16.4.app + xcodebuild -version + - run: yarn install + - name: Build fresh iOS app + run: ./scripts/test-project --version ${{ matrix.react-native }} --platforms ios diff --git a/compatibility.json b/compatibility.json new file mode 100644 index 00000000..2741f32f --- /dev/null +++ b/compatibility.json @@ -0,0 +1,5 @@ +{ + "6.x": { + "react-native": ["0.82.0", "0.83.0", "0.84.0", "0.85.0", "0.86.0", "0.87.0"] + } +} diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 37403ac5..50ea1c2c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -2128,7 +2128,7 @@ SPEC CHECKSUMS: React-Mapbuffer: acf4ac61f163f15ced7dfad7308957816b2d7abd React-microtasksnativemodule: 512d9f7c6b66574d90832a6b10b6102d4a8fdf30 React-mutationobservernativemodule: 2c5abeb9a4ae316ba6d9420ef8d9baa81faa9d56 - react-native-safe-area-context: 582cd62c1264dccf5fd9fab929d18bfed0391f5c + react-native-safe-area-context: 43b1d80b9c1b48e0f26518bfd4e7ffbc992e69b1 React-NativeModulesApple: 22b2f3e1538ceb1aab1ab182ccb0666ea2ec36ad React-networking: b58b3098d4a626f88bbaeaf6bf5e67b18ff39089 React-oscompat: 72573ceb65b6c6c6bc34e51e0df8f44c91081a6d diff --git a/scripts/test-project b/scripts/test-project new file mode 100755 index 00000000..8eb56ccb --- /dev/null +++ b/scripts/test-project @@ -0,0 +1,220 @@ +#!/bin/bash + +set -euo pipefail +IFS=$'\n\t' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DEFAULT_PROJECT_NAME="SafeAreaContextTest" +DEFAULT_PLATFORMS="android" +RNC_CLI_VERSION="${RNC_CLI_VERSION:-20.2.0}" + +usage() { + cat <<'USAGE' +Create a throwaway React Native app that depends on the current +react-native-safe-area-context checkout, and build it. + +USAGE: + ./scripts/test-project --version [options] + +REQUIRED ARGUMENTS: + --version, -v React Native version to init the test app with + +OPTIONS: + --platforms Comma separated list: android, ios. Default: android + --release Build Release instead of Debug + --project-name Name of the temporary project. Default: SafeAreaContextTest + --keep-project Do not delete the temp project (for debugging failures) + -h, --help Print this message + +ENVIRONMENT: + RNC_CLI_VERSION @react-native-community/cli version used for `init`. + Default: 20.2.0. +USAGE +} + +RN_VERSION="" +PLATFORMS="$DEFAULT_PLATFORMS" +PROJECT_NAME="$DEFAULT_PROJECT_NAME" +KEEP_PROJECT=0 +BUILD_CONFIG="Debug" + +while [[ $# -gt 0 ]]; do + case "$1" in + --version|-v) + RN_VERSION=${2:-} + if [[ -z "$RN_VERSION" ]]; then + echo "Error! --version requires a value." >&2 + usage + exit 1 + fi + shift 2 + ;; + --platforms) + PLATFORMS=${2:-} + if [[ -z "$PLATFORMS" ]]; then + echo "Error! --platforms requires a value." >&2 + usage + exit 1 + fi + shift 2 + ;; + --project-name) + PROJECT_NAME=${2:-} + if [[ -z "$PROJECT_NAME" ]]; then + echo "Error! --project-name requires a value." >&2 + usage + exit 1 + fi + shift 2 + ;; + --release) + BUILD_CONFIG="Release" + shift + ;; + --keep-project) + KEEP_PROJECT=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Error! Unknown argument: $1" >&2 + usage + exit 1 + ;; + esac +done + +if [[ -z "$RN_VERSION" ]]; then + echo "Error! Missing required --version argument." >&2 + usage + exit 1 +fi + +RUN_ANDROID=0 +RUN_IOS=0 +IFS=',' read -r -a PLATFORM_ARRAY <<< "$PLATFORMS" +for PLATFORM in "${PLATFORM_ARRAY[@]}"; do + case "${PLATFORM// }" in + android) RUN_ANDROID=1 ;; + ios) RUN_IOS=1 ;; + "") ;; + *) + echo "Error! Unknown platform: ${PLATFORM}" >&2 + exit 1 + ;; + esac +done +IFS=$'\n\t' + +if [[ $RUN_ANDROID -eq 0 && $RUN_IOS -eq 0 ]]; then + echo "Error! At least one platform must be selected." >&2 + exit 1 +fi + +TMP_DIR="$(mktemp -d)" +PROJECT_DIR="$TMP_DIR/$PROJECT_NAME" + +cleanup() { + if [[ $KEEP_PROJECT -eq 1 ]]; then + echo "Temporary project preserved at: $PROJECT_DIR" + return + fi + if [[ -d "$TMP_DIR" ]]; then + rm -rf "$TMP_DIR" + fi +} +trap cleanup EXIT + +cd "$REPO_ROOT" + +echo "==> Packing react-native-safe-area-context" +PACK_OUTPUT="$(npm pack --pack-destination "$TMP_DIR")" +TARBALL_FILENAME="$(echo "$PACK_OUTPUT" | tail -n 1 | tr -d '\r\n')" +TARBALL_PATH="$TMP_DIR/$TARBALL_FILENAME" + +echo "==> Creating React Native $RN_VERSION project ($PROJECT_NAME) in $TMP_DIR" +cd "$TMP_DIR" +npx "@react-native-community/cli@$RNC_CLI_VERSION" init "$PROJECT_NAME" \ + --version "$RN_VERSION" \ + --skip-git-init \ + --install-pods false + +echo "==> Installing local tarball" +cd "$PROJECT_DIR" +npm install "file:$TARBALL_PATH" + +echo "==> Writing smoke-test App.tsx" +cat > App.tsx <<'APP' +import React from 'react'; +import { Text } from 'react-native'; +import { + SafeAreaProvider, + SafeAreaView, + useSafeAreaInsets, +} from 'react-native-safe-area-context'; + +function Inner() { + const insets = useSafeAreaInsets(); + return ( + + {`top: ${insets.top}`} + + ); +} + +export default function App() { + return ( + + + + ); +} +APP + +if [[ $RUN_ANDROID -eq 1 ]]; then + echo "==> Bundling JavaScript for Android" + npx react-native bundle \ + --entry-file index.js \ + --platform android \ + --dev false \ + --bundle-output "$TMP_DIR/main.android.jsbundle" + + echo "==> Building Android ($BUILD_CONFIG)" + ( + cd android + ./gradlew "assemble$BUILD_CONFIG" --console=plain + ) +fi + +if [[ $RUN_IOS -eq 1 ]]; then + echo "==> Bundling JavaScript for iOS" + npx react-native bundle \ + --entry-file index.js \ + --platform ios \ + --dev false \ + --bundle-output "$TMP_DIR/main.ios.jsbundle" + + echo "==> Installing iOS dependencies" + bundle install + ( + cd ios + bundle exec pod install + + echo "==> Building iOS ($BUILD_CONFIG)" + xcodebuild \ + -workspace "$PROJECT_NAME.xcworkspace" \ + -configuration "$BUILD_CONFIG" \ + -scheme "$PROJECT_NAME" \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath "$TMP_DIR/DerivedData" \ + CODE_SIGNING_ALLOWED=NO \ + ONLY_ACTIVE_ARCH=NO \ + -quiet + ) +fi + +echo "==> All requested builds finished successfully."