diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 643d8abdb..575f5ec17 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,17 +89,11 @@ jobs: name: Build (Android) runs-on: ubuntu-latest if: ${{ github.event_name == 'push' }} - strategy: - fail-fast: false - matrix: - configuration: [Release] - platform: [Android] - channel: [foss, play] - env: - CONFIGURATION: ${{ matrix.configuration }} - TARGET_PLATFORM: ${{ matrix.platform }} - TARGET_CHANNEL: ${{ matrix.channel }} + CONFIGURATION: Release + TARGET_PLATFORM: Android + PROJECT_ROOT: ${{ github.workspace }} + UNITY_PROJECT_EXPORT_PATH: Release/Android/MajdataPlay steps: - name: Checkout the repository @@ -132,8 +126,15 @@ jobs: restore-keys: | Library-${{ runner.os }}-${{ env.TARGET_PLATFORM }}- - - name: Build APKs Release - if: ${{ env.TARGET_CHANNEL == 'foss' }} + - name: Setup Ruby and Fastlane + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + + - name: Install Fastlane + run: gem install fastlane + + - name: Export Android Project uses: game-ci/unity-builder@v4 with: unityVersion: ${{ env.UNITY_VERSION }} @@ -143,65 +144,182 @@ jobs: androidVersionCode: ${{ env.BUNDLE_VERSION_CODE_FOR_APK }} buildName: MajdataPlay buildsPath: ${{ env.CONFIGURATION }} - androidTargetSdkVersion: 29 - androidKeystoreName: android-publish.keystore - androidKeystoreBase64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} - androidKeystorePass: ${{ secrets.ANDROID_KEYSTORE_PASS }} - androidKeyaliasName: ${{ secrets.ANDROID_KEYALIAS_NAME }} - androidKeyaliasPass: ${{ secrets.ANDROID_KEYALIAS_PASS }} - - - name: Build AAB Release - if: ${{ env.TARGET_CHANNEL == 'play' }} - uses: game-ci/unity-builder@v4 + androidExportType: androidStudioProject + + - name: Fix Directory Permissions + run: sudo chown -R $USER:$USER ${{ env.CONFIGURATION }}/${{ env.TARGET_PLATFORM }} + + - name: Setup Java & Gradle Cache + uses: actions/setup-java@v5 with: - unityVersion: ${{ env.UNITY_VERSION }} - targetPlatform: ${{ env.TARGET_PLATFORM }} - versioning: Custom - version: ${{ env.BUNDLE_VERSION_WITH_HASH }} - androidVersionCode: ${{ env.BUNDLE_VERSION_CODE }} - buildName: MajdataPlay - buildsPath: ${{ env.CONFIGURATION }} - androidExportType: androidAppBundle - androidTargetSdkVersion: 36 - androidKeystoreName: android-publish.keystore - androidKeystoreBase64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} - androidKeystorePass: ${{ secrets.ANDROID_KEYSTORE_PASS }} - androidKeyaliasName: ${{ secrets.ANDROID_KEYALIAS_NAME }} - androidKeyaliasPass: ${{ secrets.ANDROID_KEYALIAS_PASS }} + distribution: 'zulu' + java-version: '17' + cache: 'gradle' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + gradle-version: '9.1.0' + + - name: Install Android NDK via SDK Manager + run: | + echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install "ndk;23.1.7779620" + + - name: Fix Android SDK and NDK paths + run: | + cd ${{ env.UNITY_PROJECT_EXPORT_PATH }} + + BAD_NDK="/opt/unity/Editor/Data/PlaybackEngines/AndroidPlayer/NDK" + BAD_SDK="/opt/unity/Editor/Data/PlaybackEngines/AndroidPlayer/SDK" + + GOOD_NDK="$ANDROID_HOME/ndk/23.1.7779620" + GOOD_SDK="$ANDROID_HOME" + + find . -type f \( -name "*.gradle" -o -name "*.properties" \) -exec sed -i "s|$BAD_NDK|$GOOD_NDK|g" {} + + find . -type f \( -name "*.gradle" -o -name "*.properties" \) -exec sed -i "s|$BAD_SDK|$GOOD_SDK|g" {} + + + echo "sdk.dir=$GOOD_SDK" > local.properties + echo "ndk.dir=$GOOD_NDK" >> local.properties + + - name: Generate Gradle Wrapper + run: | + cd ${{ env.UNITY_PROJECT_EXPORT_PATH }} + gradle wrapper + + - name: Prepare Keystore + run: | + echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 --decode > android-publish.keystore + echo "KEYSTORE_PATH=$(pwd)/android-publish.keystore" >> $GITHUB_ENV + + - name: Create Fastfile + run: | + mkdir -p fastlane + cat << 'EOF' > fastlane/Fastfile + default_platform(:android) + + platform :android do + + before_all do + gradle_path = File.join( + ENV['PROJECT_ROOT'], + ENV['UNITY_PROJECT_EXPORT_PATH'], + 'launcher', + 'build.gradle' + ) + content = File.read(gradle_path) + + content = content.gsub(/versionCode\s+\d+/, "versionCode #{ENV['BUNDLE_VERSION_CODE']}") + content = content.gsub(/versionName\s+['"].*?['"]/, "versionName '#{ENV['BUNDLE_VERSION_WITH_HASH']}'") + + signing_block = <<-GRADLE + + // --- Injected by Fastlane --- + android { + signingConfigs { + release { + storeFile file("#{ENV['KEYSTORE_PATH']}") + storePassword "#{ENV['ANDROID_KEYSTORE_PASS']}" + keyAlias "#{ENV['ANDROID_KEYALIAS_NAME']}" + keyPassword "#{ENV['ANDROID_KEYALIAS_PASS']}" + } + } + buildTypes { + release { + signingConfig signingConfigs.release + } + } + } + GRADLE + + File.open(gradle_path, 'w') { |file| file.puts(content + signing_block) } + end + + desc "Build foss version (APK)" + lane :build_foss do + gradle( + project_dir: ENV['UNITY_PROJECT_EXPORT_PATH'], + task: "assemble", + build_type: "Release", + flags: "--build-cache" + ) + end + + desc "Build Play version (AAB)" + lane :build_play do + gradle( + project_dir: ENV['UNITY_PROJECT_EXPORT_PATH'], + task: "bundle", + build_type: "Release", + flags: "--build-cache" + ) + end + end + EOF + + - name: Build foss (APK) + env: + ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }} + ANDROID_KEYALIAS_NAME: ${{ secrets.ANDROID_KEYALIAS_NAME }} + ANDROID_KEYALIAS_PASS: ${{ secrets.ANDROID_KEYALIAS_PASS }} + run: | + find ${{ env.UNITY_PROJECT_EXPORT_PATH }} -name "build.gradle" -exec sed -i 's/targetSdkVersion [0-9]*/targetSdkVersion 29/g' {} + + fastlane build_foss - name: Collect Android APKs - if: ${{ env.TARGET_CHANNEL == 'foss' }} run: | set -euo pipefail mkdir -p out - cp "${{ env.CONFIGURATION }}/Android/MajdataPlay.apk/MajdataPlay.armeabi-v7a.apk" "out/MajdataPlay-Android-nightly.armeabi-v7a.apk" - cp "${{ env.CONFIGURATION }}/Android/MajdataPlay.apk/MajdataPlay.arm64-v8a.apk" "out/MajdataPlay-Android-nightly.arm64-v8a.apk" + OUTPUT_DIR="${{ env.UNITY_PROJECT_EXPORT_PATH }}/launcher/build/outputs/apk/release" + for file in "$OUTPUT_DIR"/*.apk; do + if [[ "$file" == *"v7a"* ]]; then + cp "$file" "out/MajdataPlay-Android-${{ env.BUNDLE_VERSION_WITH_HASH }}-nightly.armeabi-v7a.apk" + elif [[ "$file" == *"v8a"* ]]; then + cp "$file" "out/MajdataPlay-Android-${{ env.BUNDLE_VERSION_WITH_HASH }}-nightly.arm64-v8a.apk" + else + cp "$file" "out/MajdataPlay-Android-${{ env.BUNDLE_VERSION_WITH_HASH }}-nightly.apk" + fi + done ls -la out + - name: Build Play (AAB) + env: + ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }} + ANDROID_KEYALIAS_NAME: ${{ secrets.ANDROID_KEYALIAS_NAME }} + ANDROID_KEYALIAS_PASS: ${{ secrets.ANDROID_KEYALIAS_PASS }} + run: | + find ${{ env.UNITY_PROJECT_EXPORT_PATH }} -name "build.gradle" -exec sed -i 's/targetSdkVersion [0-9]*/targetSdkVersion 36/g' {} + + fastlane build_play + - name: Collect Android AAB - if: ${{ env.TARGET_CHANNEL == 'play' }} run: | set -euo pipefail mkdir -p out - cp "${{ env.CONFIGURATION }}/Android/MajdataPlay.aab" "out/MajdataPlay-Android-nightly.aab" + cp "${{ env.UNITY_PROJECT_EXPORT_PATH }}/launcher/build/outputs/bundle/release/launcher-release.aab" "out/MajdataPlay-Android-${{ env.BUNDLE_VERSION_WITH_HASH }}-nightly.aab" ls -la out - - name: Upload build outputs as workflow artifact + - name: Upload foss APK outputs as workflow artifact uses: actions/upload-artifact@v4 with: - name: out-${{ env.TARGET_PLATFORM }}-${{ env.TARGET_CHANNEL }} - path: out/* + name: MajdataPlay-Android-foss-APK + path: out/*.apk + if-no-files-found: error + retention-days: 7 + + - name: Upload Play AAB outputs as workflow artifact + uses: actions/upload-artifact@v4 + with: + name: MajdataPlay-Android-Play-AAB + path: out/*.aab if-no-files-found: error retention-days: 7 - name: Upload to Google Play uses: r0adkll/upload-google-play@v1 - if: ${{ env.TARGET_CHANNEL == 'play' }} continue-on-error: true with: serviceAccountJsonPlainText: ${{ secrets.PLAY_DEPLOY_ACCOUNT_JSON }} packageName: net.majdata.majdataplay - releaseFiles: ${{ env.CONFIGURATION }}/Android/MajdataPlay.aab + releaseFiles: out/MajdataPlay-Android-${{ env.BUNDLE_VERSION_WITH_HASH }}-nightly.aab track: internal status: completed