ci: consolidate Android verification #46
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Android | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| workflow_dispatch: | |
| inputs: | |
| publish_release: | |
| description: Publish a GitHub release | |
| required: true | |
| type: boolean | |
| default: false | |
| tag_name: | |
| description: Release tag | |
| required: true | |
| default: v1.1.1 | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: android-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| CI: true | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| JAVA_TOOL_OPTIONS: -Djava.awt.headless=true | |
| GRADLE_OPTS: -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=4 -Djava.awt.headless=true | |
| ANDROID_HOME: /opt/android-sdk | |
| ANDROID_SDK_ROOT: /opt/android-sdk | |
| JAVA_HOME: /usr/lib/jvm/java-26-openjdk | |
| jobs: | |
| prepare-sdk: | |
| runs-on: [self-hosted, Linux, X64, arko, android] | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Install Android SDK platform | |
| run: | | |
| platform="$ANDROID_HOME/platforms/android-37.0" | |
| ( | |
| flock 9 | |
| if [ ! -f "$platform/android.jar" ]; then | |
| rm -rf "$platform" | |
| "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" \ | |
| --sdk_root="$ANDROID_HOME" \ | |
| "platforms;android-37.0" | |
| fi | |
| test -f "$platform/android.jar" | |
| ) 9>"$ANDROID_HOME/.platform-install.lock" | |
| verify: | |
| needs: prepare-sdk | |
| runs-on: [self-hosted, Linux, X64, arko, android] | |
| timeout-minutes: 30 | |
| env: | |
| GRADLE_USER_HOME: ${{ github.workspace }}/../.gradle-user-home | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Verify Android project | |
| timeout-minutes: 25 | |
| run: | | |
| ./gradlew --no-daemon --build-cache --stacktrace \ | |
| :player:testDebugUnitTest \ | |
| :app:testDebugUnitTest \ | |
| :player:lintDebug \ | |
| :app:lintDebug \ | |
| :app:assembleDebug | |
| - name: Upload debug APK | |
| if: ${{ github.ref != 'refs/heads/main' }} | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: typetype-debug-apk | |
| path: app/build/outputs/apk/debug/*.apk | |
| if-no-files-found: error | |
| retention-days: 14 | |
| - name: Upload lint report | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: lint-report | |
| path: | | |
| app/build/reports/lint-results-debug.html | |
| player/build/reports/lint-results-debug.html | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| release: | |
| needs: verify | |
| if: ${{ github.ref == 'refs/heads/main' && (github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.publish_release)) }} | |
| runs-on: [self-hosted, Linux, X64, arko, android] | |
| timeout-minutes: 35 | |
| env: | |
| GRADLE_USER_HOME: ${{ github.workspace }}/../.gradle-user-home | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Prepare release tag | |
| env: | |
| INPUT_TAG_NAME: ${{ inputs.tag_name }} | |
| run: | | |
| if [ -n "$INPUT_TAG_NAME" ]; then | |
| echo "RELEASE_TAG=$INPUT_TAG_NAME" >> "$GITHUB_ENV" | |
| else | |
| echo "RELEASE_TAG=v1.1.1" >> "$GITHUB_ENV" | |
| fi | |
| - name: Prepare signing | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} | |
| ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| run: | | |
| test -n "$ANDROID_KEYSTORE_BASE64" | |
| test -n "$ANDROID_KEYSTORE_PASSWORD" | |
| test -n "$ANDROID_KEY_ALIAS" | |
| test -n "$ANDROID_KEY_PASSWORD" | |
| printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > release.keystore | |
| { | |
| printf 'storeFile=%s\n' "$PWD/release.keystore" | |
| printf 'storePassword=%s\n' "$ANDROID_KEYSTORE_PASSWORD" | |
| printf 'keyAlias=%s\n' "$ANDROID_KEY_ALIAS" | |
| printf 'keyPassword=%s\n' "$ANDROID_KEY_PASSWORD" | |
| } > keystore.properties | |
| - name: Build release APK | |
| timeout-minutes: 25 | |
| run: ./gradlew --no-daemon --build-cache --stacktrace :app:assembleRelease | |
| - name: Prepare APK artifact | |
| run: | | |
| mkdir -p artifacts | |
| apk="$(find app/build/outputs/apk/release -name '*.apk' | head -n 1)" | |
| test -n "$apk" | |
| cp "$apk" "artifacts/TypeType-$RELEASE_TAG.apk" | |
| - name: Upload release APK | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: typetype-release-apk | |
| path: artifacts/*.apk | |
| if-no-files-found: error | |
| retention-days: 30 | |
| - name: Publish GitHub release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ env.RELEASE_TAG }} | |
| name: ${{ env.RELEASE_TAG }} | |
| body: | | |
| TypeType for Android 1.1.1 is a production hotfix focused on player wake stability. | |
| This version fixes the gray screen that could appear after turning the phone screen off and back on while a video was still playing. Playback now keeps the media session alive and restores the video surface when Android resumes the app. | |
| Changes: | |
| - Recreate the player surface after screen wake and unlock events. | |
| - Reattach the active Media3 player view when the activity resumes. | |
| - Avoid pausing the player view lifecycle while playback continues in the background. | |
| - Show the startup loader if the app is still resolving its first route. | |
| - Build and publish a signed production APK from main. | |
| files: artifacts/*.apk | |
| fail_on_unmatched_files: true |