1name: Android Client 2 3on: 4 workflow_dispatch: 5 inputs: 6 releaseAPK: 7 description: 'type "release-apk" to confirm upload to S3' 8 required: false 9 releaseGooglePlay: 10 description: 'type "release-google-play" to confirm release to Google Play' 11 required: false 12 schedule: 13 - cron: '20 5 * * 1,3,5' # 5:20 AM UTC time on every Monday, Wednesday and Friday 14 pull_request: 15 paths: 16 - .github/workflows/client-android.yml 17 - secrets/** 18 - android/** 19 - fastlane/** 20 - Gemfile.lock 21 - .ruby-version 22 - yarn.lock 23 push: 24 branches: [main, sdk-*] 25 paths: 26 - .github/workflows/client-android.yml 27 - secrets/** 28 - android/** 29 - fastlane/** 30 - Gemfile.lock 31 - .ruby-version 32 - yarn.lock 33 34concurrency: 35 group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} 36 cancel-in-progress: true 37 38jobs: 39 build: 40 runs-on: ubuntu-20.04 41 env: 42 GRADLE_OPTS: -Dorg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m 43 steps: 44 - name: Checkout 45 uses: actions/checkout@v3 46 with: 47 submodules: true 48 - name: Use JDK 11 49 uses: actions/setup-java@v3 50 with: 51 distribution: 'temurin' 52 java-version: '11' 53 - name: ♻️ Restore workspace node modules 54 uses: actions/cache@v2 55 id: node-modules-cache 56 with: 57 path: | 58 # See "workspaces" → "packages" in the root package.json for the source of truth of 59 # which node_modules are affected by the root yarn.lock 60 node_modules 61 apps/*/node_modules 62 home/node_modules 63 packages/*/node_modules 64 packages/@expo/*/node_modules 65 packages/@unimodules/*/node_modules 66 react-native-lab/react-native/node_modules 67 key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} 68 - run: echo "$(pwd)/bin" >> $GITHUB_PATH 69 - name: ♻️ Restore node modules in tools 70 uses: actions/cache@v2 71 with: 72 path: tools/node_modules 73 key: ${{ runner.os }}-tools-modules-${{ hashFiles('tools/yarn.lock') }} 74 - name: Yarn install 75 run: yarn install --frozen-lockfile 76 - name: Setup Ruby and install gems 77 uses: ruby/setup-ruby@v1 78 with: 79 bundler-cache: true 80 - name: Install git-crypt 81 run: sudo apt-get install git-crypt 82 - name: Decrypt secrets if possible 83 env: 84 GIT_CRYPT_KEY_BASE64: ${{ secrets.GIT_CRYPT_KEY_BASE64 }} 85 run: | 86 if [ -z "${GIT_CRYPT_KEY_BASE64}" ]; then 87 echo 'git-crypt key not present in environment' 88 else 89 git crypt unlock <(echo $GIT_CRYPT_KEY_BASE64 | base64 --decode) 90 fi 91 - name: ♻️ Restore Gradle caches 92 uses: actions/cache@v2 93 with: 94 path: ~/.gradle/caches 95 key: ${{ runner.os }}-gradle-${{ hashFiles('android/*.gradle*') }} 96 restore-keys: | 97 ${{ runner.os }}-gradle- 98 - name: Check which flavor to build 99 id: flavor 100 uses: dorny/paths-filter@v2 101 with: 102 # this action fails when base is not set on schedule event 103 base: ${{ github.ref }} 104 filters: | 105 versioned: 106 - android/versioned-abis/** 107 - android/versioned-react-native/** 108 - android/expoview/src/versioned/** 109 - android/expoview/src/main/java/versioned/** 110 - android/**/*.gradle 111 - name: Build APK 112 env: 113 ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }} 114 ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} 115 ANDROID_KEY_ALIAS: ExponentKey 116 ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} 117 IS_APP_BUNDLE: ${{ github.event.inputs.releaseGooglePlay == 'release-google-play' }} 118 IS_RELEASE_BUILD: ${{ github.event.inputs.releaseAPK == 'release-apk' || github.event.inputs.releaseGooglePlay == 'release-google-play' }} 119 IS_VERSIONED_FLAVOR: ${{ github.event_name == 'schedule' || steps.flavor.outputs.versioned == 'true' }} 120 run: | 121 if [ "$IS_RELEASE_BUILD" == "false" ]; then 122 export ORG_GRADLE_PROJECT_reactNativeArchitectures="x86_64" 123 BUILD_TYPE="Debug" 124 echo "Using ABI filters: $ORG_GRADLE_PROJECT_reactNativeArchitectures" 125 else 126 BUILD_TYPE="Release" 127 fi 128 [[ "$IS_VERSIONED_FLAVOR" == "true" ]] && FLAVOR="Versioned" || FLAVOR="Unversioned" 129 echo "Building with $FLAVOR flavor" 130 if [ -z "$ANDROID_KEYSTORE_B64" ]; then 131 echo "External build detected, APK will not be signed" 132 bin/fastlane android build build_type:$BUILD_TYPE flavor:$FLAVOR sign:false 133 else 134 echo "Internal build detected, APK will be signed" 135 echo $ANDROID_KEYSTORE_B64 | base64 -d > android/app/release-key.jks 136 bin/fastlane android build build_type:$BUILD_TYPE flavor:$FLAVOR aab:$IS_APP_BUNDLE 137 fi 138 - name: Upload APK artifact 139 uses: actions/upload-artifact@v3 140 with: 141 name: android-apk 142 path: android/app/build/outputs/apk 143 - name: Store daemon logs for debugging crashes 144 if: failure() 145 uses: actions/upload-artifact@v3 146 with: 147 name: gradle-daemon-logs 148 path: ~/.gradle/daemon 149 - name: Upload APK to S3 and update staging versions endpoint 150 if: ${{ github.event.inputs.releaseAPK == 'release-apk' }} 151 run: bin/expotools client-build --platform android --release 152 env: 153 AWS_ACCESS_KEY_ID: AKIAJ3SWUQ4QLNQC7FXA 154 AWS_SECRET_ACCESS_KEY: ${{ secrets.android_client_build_aws_secret_key }} 155 AWS_DEFAULT_REGION: 'us-east-1' 156 EXPO_VERSIONS_SECRET: ${{ secrets.expo_versions_secret }} 157 - name: Upload APK to Google Play and release to production 158 if: ${{ github.event.inputs.releaseGooglePlay == 'release-google-play' }} 159 run: bin/fastlane android prod_release 160 env: 161 SUPPLY_JSON_KEY_DATA: ${{ secrets.SUPPLY_JSON_KEY_DATA }} 162 - name: Notify on Slack 163 uses: 8398a7/action-slack@v3 164 if: failure() && (github.event.ref == 'refs/heads/main' || startsWith(github.event.ref, 'refs/heads/sdk-')) 165 env: 166 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 167 SLACK_WEBHOOK_URL: ${{ secrets.slack_webhook_android }} 168 with: 169 channel: '#expo-android' 170 status: ${{ job.status }} 171 fields: job,message,ref,eventName,author,took 172 author_name: Expo Go (Android) 173