Repository navigation
Merge pull request #4 from tqmane/copilot/fix-ai-image-test-functiona… #201
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: Flutter Build & Release | |
| on: | |
| push: | |
| branches: [ main, master ] | |
| tags: | |
| - 'v*' | |
| pull_request: | |
| branches: [ main, master ] | |
| workflow_dispatch: | |
| jobs: | |
| build-linux: | |
| runs-on: ubuntu-latest | |
| env: | |
| DESKTOP_GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.DESKTOP_GOOGLE_OAUTH_CLIENT_ID }} | |
| DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.38.3' | |
| channel: 'stable' | |
| - name: Install Linux dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev | |
| - name: Flutter doctor | |
| run: flutter doctor -v | |
| - name: Create Linux platform structure | |
| working-directory: flutter-app | |
| run: | | |
| # 既存のlinuxフォルダを削除して再生成(アイコンは保持) | |
| if [ -f "linux/app_icon.png" ]; then | |
| cp linux/app_icon.png /tmp/app_icon_linux.png | |
| fi | |
| rm -rf linux | |
| flutter create --project-name similarity_quiz --org com.tqmane --platforms=linux . | |
| if [ -f "/tmp/app_icon_linux.png" ]; then | |
| cp /tmp/app_icon_linux.png linux/app_icon.png | |
| fi | |
| - name: Remove Firebase dependencies for desktop | |
| working-directory: flutter-app | |
| run: | | |
| # Firebaseはデスクトップでサポートされていないため削除 | |
| sed -i '/firebase_core:/d' pubspec.yaml | |
| sed -i '/firebase_auth:/d' pubspec.yaml | |
| sed -i '/firebase_database:/d' pubspec.yaml | |
| sed -i '/google_sign_in:/d' pubspec.yaml | |
| # Firebase初期化ファイルをデスクトップ用スタブに置き換え | |
| cp lib/services/firebase_init_desktop.dart lib/services/firebase_init_io.dart | |
| # Firebase同期サービス(デスクトップREST版)に置き換え | |
| cp lib/services/firebase_sync_service_desktop.dart lib/services/firebase_sync_service_platform.dart | |
| # 管理者画面をスタブに置き換え | |
| cp lib/screens/admin_screen_stub.dart lib/screens/admin_screen_mobile.dart | |
| - name: Set Linux app icon | |
| working-directory: flutter-app | |
| run: | | |
| # デスクトップファイル用にアイコンをコピー | |
| if [ -f "assets/icon/app_icon.png" ] && [ -d "linux" ]; then | |
| cp assets/icon/app_icon.png linux/ | |
| # my_application.ccでウィンドウアイコンを設定 | |
| if [ -f "linux/my_application.cc" ]; then | |
| python3 -c " | |
| import os | |
| file_path = 'linux/my_application.cc' | |
| if os.path.exists(file_path): | |
| with open(file_path, 'r') as f: | |
| content = f.read() | |
| target_str = 'gtk_window_set_title(window, "similarity_quiz");' | |
| replacement = 'gtk_window_set_title(window, "判別クイズ");' | |
| # アイコン設定コード | |
| icon_code = ''' | |
| # アプリアイコンを設定 | |
| GError *error = NULL; | |
| gchar *icon_path = g_build_filename(g_get_current_dir(), "data", "flutter_assets", "assets", "icon", "app_icon.png", NULL); | |
| if (g_file_test(icon_path, G_FILE_TEST_EXISTS)) { | |
| gtk_window_set_icon_from_file(window, icon_path, &error); | |
| if (error != NULL) { | |
| g_warning("Failed to set icon: %s", error->message); | |
| g_error_free(error); | |
| } | |
| } | |
| g_free(icon_path);''' | |
| if target_str in content: | |
| new_content = content.replace(target_str, replacement + '\n' + icon_code) | |
| with open(file_path, 'w') as f: | |
| f.write(new_content) | |
| print('Updated my_application.cc') | |
| else: | |
| print('Target string not found in my_application.cc') | |
| " | |
| fi | |
| fi | |
| - name: Clean and get dependencies | |
| working-directory: flutter-app | |
| run: | | |
| flutter clean | |
| flutter pub get | |
| - name: Run tests | |
| working-directory: flutter-app | |
| run: flutter test || echo "No tests found" | |
| - name: Build Linux | |
| working-directory: flutter-app | |
| run: flutter build linux --release --dart-define=DESKTOP_GOOGLE_OAUTH_CLIENT_ID=$DESKTOP_GOOGLE_OAUTH_CLIENT_ID --dart-define=DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET=$DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET | |
| - name: Package Linux build | |
| run: | | |
| cd flutter-app/build/linux/x64/release/bundle | |
| tar -czvf ../../../../../similarity_quiz-linux-x64.tar.gz . | |
| - name: Upload Linux build | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-build | |
| path: flutter-app/similarity_quiz-linux-x64.tar.gz | |
| build-windows: | |
| runs-on: windows-latest | |
| env: | |
| DESKTOP_GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.DESKTOP_GOOGLE_OAUTH_CLIENT_ID }} | |
| DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.38.3' | |
| channel: 'stable' | |
| - name: Flutter doctor | |
| run: flutter doctor -v | |
| - name: Create Windows platform structure | |
| working-directory: flutter-app | |
| run: | | |
| # 既存のwindowsフォルダを削除して再生成(アイコンは保持) | |
| if (Test-Path "windows/runner/resources") { | |
| Copy-Item "windows/runner/resources/*.png" "$env:TEMP\" -ErrorAction SilentlyContinue | |
| } | |
| Remove-Item -Recurse -Force "windows" -ErrorAction SilentlyContinue | |
| flutter create --project-name similarity_quiz --org com.tqmane --platforms=windows . | |
| if (Test-Path "$env:TEMP\app_icon*.png") { | |
| Copy-Item "$env:TEMP\app_icon*.png" "windows/runner/resources\" -ErrorAction SilentlyContinue | |
| } | |
| - name: Remove Firebase dependencies for desktop | |
| working-directory: flutter-app | |
| shell: pwsh | |
| run: | | |
| # Firebaseはデスクトップでサポートされていないため削除 | |
| $content = Get-Content pubspec.yaml -Raw | |
| $content = $content -replace ' firebase_core:.*\n', '' | |
| $content = $content -replace ' firebase_auth:.*\n', '' | |
| $content = $content -replace ' firebase_database:.*\n', '' | |
| $content = $content -replace ' google_sign_in:.*\n', '' | |
| Set-Content pubspec.yaml $content | |
| # Firebase初期化ファイルをデスクトップ用スタブに置き換え | |
| Copy-Item lib/services/firebase_init_desktop.dart lib/services/firebase_init_io.dart -Force | |
| # Firebase同期サービス(デスクトップREST版)に置き換え | |
| Copy-Item lib/services/firebase_sync_service_desktop.dart lib/services/firebase_sync_service_platform.dart -Force | |
| # 管理者画面をスタブに置き換え | |
| Copy-Item lib/screens/admin_screen_stub.dart lib/screens/admin_screen_mobile.dart -Force | |
| - name: Set Windows app icon | |
| working-directory: flutter-app | |
| shell: pwsh | |
| run: | | |
| # Windows用のアイコンを設定 | |
| if ((Test-Path "assets/icon/app_icon.png") -and (Test-Path "windows/runner/resources")) { | |
| # PNGからICOに変換(magickがインストールされていれば) | |
| # windows/runner/resources/app_icon.ico として保存 | |
| Copy-Item "assets/icon/app_icon.png" "windows/runner/resources/app_icon.png" | |
| # Runner.rcのアイコン参照を更新 | |
| $rcFile = "windows/runner/Runner.rc" | |
| if (Test-Path $rcFile) { | |
| (Get-Content $rcFile) -replace 'IDI_APP_ICON\s+ICON\s+"resources\\app_icon.ico"', 'IDI_APP_ICON ICON "resources\app_icon.ico"' | Set-Content $rcFile | |
| } | |
| } | |
| - name: Clean and get dependencies | |
| working-directory: flutter-app | |
| run: | | |
| flutter clean | |
| flutter pub get | |
| - name: Build Windows | |
| working-directory: flutter-app | |
| run: flutter build windows --release --dart-define=DESKTOP_GOOGLE_OAUTH_CLIENT_ID=$env:DESKTOP_GOOGLE_OAUTH_CLIENT_ID --dart-define=DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET=$env:DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET | |
| - name: Package Windows build | |
| run: | | |
| Compress-Archive -Path flutter-app/build/windows/x64/runner/Release/* -DestinationPath flutter-app/similarity_quiz-windows-x64.zip | |
| - name: Upload Windows build | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows-build | |
| path: flutter-app/similarity_quiz-windows-x64.zip | |
| build-macos: | |
| runs-on: macos-latest | |
| env: | |
| DESKTOP_GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.DESKTOP_GOOGLE_OAUTH_CLIENT_ID }} | |
| DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.38.3' | |
| channel: 'stable' | |
| - name: Flutter doctor | |
| run: flutter doctor -v | |
| - name: Create macOS platform structure | |
| working-directory: flutter-app | |
| run: | | |
| # 既存のmacosフォルダを削除して再生成(アイコンは保持) | |
| if [ -d "macos/Runner/Assets.xcassets/AppIcon.appiconset" ]; then | |
| cp -r macos/Runner/Assets.xcassets/AppIcon.appiconset /tmp/macos_icons | |
| fi | |
| rm -rf macos | |
| flutter create --project-name similarity_quiz --org com.tqmane --platforms=macos . | |
| if [ -d "/tmp/macos_icons" ]; then | |
| cp -r /tmp/macos_icons/* macos/Runner/Assets.xcassets/AppIcon.appiconset/ | |
| fi | |
| - name: Remove Firebase dependencies for desktop | |
| working-directory: flutter-app | |
| run: | | |
| # Firebaseはデスクトップでサポートされていないため削除 | |
| sed -i '' '/firebase_core:/d' pubspec.yaml | |
| sed -i '' '/firebase_auth:/d' pubspec.yaml | |
| sed -i '' '/firebase_database:/d' pubspec.yaml | |
| sed -i '' '/google_sign_in:/d' pubspec.yaml | |
| # Firebase初期化ファイルをデスクトップ用スタブに置き換え | |
| cp lib/services/firebase_init_desktop.dart lib/services/firebase_init_io.dart | |
| # Firebase同期サービス(デスクトップREST版)に置き換え | |
| cp lib/services/firebase_sync_service_desktop.dart lib/services/firebase_sync_service_platform.dart | |
| # 管理者画面をスタブに置き換え | |
| cp lib/screens/admin_screen_stub.dart lib/screens/admin_screen_mobile.dart | |
| - name: Clean and get dependencies | |
| working-directory: flutter-app | |
| run: | | |
| flutter clean | |
| flutter pub get | |
| - name: Build macOS | |
| working-directory: flutter-app | |
| run: flutter build macos --release --dart-define=DESKTOP_GOOGLE_OAUTH_CLIENT_ID=$DESKTOP_GOOGLE_OAUTH_CLIENT_ID --dart-define=DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET=$DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET | |
| - name: Package macOS build | |
| run: | | |
| cd flutter-app/build/macos/Build/Products/Release | |
| zip -r ../../../../../similarity_quiz-macos.zip "similarity_quiz.app" | |
| - name: Upload macOS build | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: macos-build | |
| path: flutter-app/similarity_quiz-macos.zip | |
| build-ios: | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.38.3' | |
| channel: 'stable' | |
| - name: Flutter doctor | |
| run: flutter doctor -v | |
| - name: Create iOS platform structure | |
| working-directory: flutter-app | |
| run: | | |
| # 既存のiosフォルダの設定を保持 | |
| if [ -d "ios/Runner/Assets.xcassets/AppIcon.appiconset" ]; then | |
| cp -r ios/Runner/Assets.xcassets/AppIcon.appiconset /tmp/ios_icons | |
| fi | |
| # GoogleService-Info.plistをバックアップ | |
| if [ -f "ios/Runner/GoogleService-Info.plist" ]; then | |
| cp ios/Runner/GoogleService-Info.plist /tmp/GoogleService-Info.plist | |
| fi | |
| # Info.plistをバックアップ(Google Sign-In設定を保持) | |
| if [ -f "ios/Runner/Info.plist" ]; then | |
| cp ios/Runner/Info.plist /tmp/Info.plist | |
| fi | |
| rm -rf ios | |
| flutter create --project-name similarity_quiz --org com.tqmane --platforms=ios . | |
| if [ -d "/tmp/ios_icons" ]; then | |
| cp -r /tmp/ios_icons/* ios/Runner/Assets.xcassets/AppIcon.appiconset/ | |
| fi | |
| # GoogleService-Info.plistを復元 | |
| if [ -f "/tmp/GoogleService-Info.plist" ]; then | |
| cp /tmp/GoogleService-Info.plist ios/Runner/GoogleService-Info.plist | |
| fi | |
| # Info.plistを復元(GIDClientID, GIDServerClientID, CFBundleURLTypesを保持) | |
| if [ -f "/tmp/Info.plist" ]; then | |
| cp /tmp/Info.plist ios/Runner/Info.plist | |
| fi | |
| - name: Setup CocoaPods | |
| run: | | |
| gem install cocoapods | |
| pod --version | |
| - name: Set iOS deployment target to 16.4 | |
| working-directory: flutter-app/ios | |
| run: | | |
| # Podfileの最小バージョンを16.4に設定 | |
| sed -i '' "s/platform :ios, '.*'/platform :ios, '16.4'/" Podfile | |
| # project.pbxprojのIPHONEOS_DEPLOYMENT_TARGETを更新 | |
| sed -i '' 's/IPHONEOS_DEPLOYMENT_TARGET = [0-9.]*;/IPHONEOS_DEPLOYMENT_TARGET = 16.4;/g' Runner.xcodeproj/project.pbxproj | |
| - name: Clean and get dependencies | |
| working-directory: flutter-app | |
| run: | | |
| flutter clean | |
| flutter pub get | |
| - name: Cache CocoaPods | |
| uses: actions/cache@v4 | |
| with: | |
| path: flutter-app/ios/Pods | |
| key: ${{ runner.os }}-pods-${{ hashFiles('flutter-app/ios/Podfile.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pods- | |
| - name: Install CocoaPods dependencies | |
| working-directory: flutter-app/ios | |
| run: | | |
| pod repo update | |
| pod install --verbose | |
| - name: Build iOS (no codesign) | |
| working-directory: flutter-app | |
| run: flutter build ios --release --no-codesign | |
| - name: Create IPA package | |
| run: | | |
| cd flutter-app/build/ios/iphoneos | |
| mkdir -p Payload | |
| cp -r Runner.app Payload/ | |
| zip -r ../../../similarity_quiz-ios.ipa Payload | |
| - name: Upload iOS build | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ios-build | |
| path: flutter-app/similarity_quiz-ios.ipa | |
| build-android: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: '3.38.3' | |
| channel: 'stable' | |
| - name: Flutter doctor | |
| run: flutter doctor -v | |
| - name: Create Android platform structure | |
| working-directory: flutter-app | |
| run: | | |
| # 既存のandroidフォルダを削除して再生成(アイコンとgoogle-services.jsonは保持) | |
| if [ -d "android/app/src/main/res" ]; then | |
| cp -r android/app/src/main/res /tmp/android_res | |
| fi | |
| if [ -f "android/app/google-services.json" ]; then | |
| cp android/app/google-services.json /tmp/google-services.json | |
| fi | |
| rm -rf android | |
| flutter create --project-name similarity_quiz --org com.tqmane --platforms=android . | |
| if [ -d "/tmp/android_res" ]; then | |
| cp -r /tmp/android_res/* android/app/src/main/res/ | |
| fi | |
| if [ -f "/tmp/google-services.json" ]; then | |
| cp /tmp/google-services.json android/app/google-services.json | |
| fi | |
| - name: Disable Impeller in AndroidManifest | |
| working-directory: flutter-app | |
| run: | | |
| # AndroidManifest.xmlにImpeller無効化フラグを追加 | |
| python3 -c " | |
| with open('android/app/src/main/AndroidManifest.xml', 'r') as f: | |
| content = f.read() | |
| impeller_meta = ''' | |
| <meta-data | |
| android:name=\"io.flutter.embedding.android.EnableImpeller\" | |
| android:value=\"false\" />''' | |
| if 'EnableImpeller' not in content: | |
| content = content.replace('</application>', impeller_meta + '\n </application>') | |
| with open('android/app/src/main/AndroidManifest.xml', 'w') as f: | |
| f.write(content) | |
| " | |
| - name: Configure Android build for desugaring | |
| working-directory: flutter-app | |
| run: | | |
| # Kotlin DSL (.gradle.kts) または Groovy DSL (.gradle) の両方に対応 | |
| BUILD_FILE="" | |
| if [ -f "android/app/build.gradle.kts" ]; then | |
| BUILD_FILE="android/app/build.gradle.kts" | |
| echo "Using Kotlin DSL: $BUILD_FILE" | |
| elif [ -f "android/app/build.gradle" ]; then | |
| BUILD_FILE="android/app/build.gradle" | |
| echo "Using Groovy DSL: $BUILD_FILE" | |
| else | |
| echo "ERROR: No build.gradle found!" | |
| ls -la android/app/ | |
| exit 1 | |
| fi | |
| # Kotlin DSL用の設定 | |
| if [[ "$BUILD_FILE" == *.kts ]]; then | |
| python3 -c " | |
| with open('$BUILD_FILE', 'r') as f: | |
| content = f.read() | |
| # isCoreLibraryDesugaringEnabledを追加 | |
| if 'isCoreLibraryDesugaringEnabled' not in content: | |
| content = content.replace( | |
| 'compileOptions {', | |
| 'compileOptions {\n isCoreLibraryDesugaringEnabled = true' | |
| ) | |
| # multiDexEnabledを追加 | |
| if 'multiDexEnabled' not in content: | |
| content = content.replace( | |
| 'defaultConfig {', | |
| 'defaultConfig {\n multiDexEnabled = true' | |
| ) | |
| # dependenciesにdesugar_jdk_libsを追加 | |
| if 'desugar_jdk_libs' not in content: | |
| if 'dependencies {' in content: | |
| content = content.replace( | |
| 'dependencies {', | |
| 'dependencies {\n coreLibraryDesugaring(\"com.android.tools:desugar_jdk_libs:2.0.4\")' | |
| ) | |
| else: | |
| content += ''' | |
| dependencies { | |
| coreLibraryDesugaring(\"com.android.tools:desugar_jdk_libs:2.0.4\") | |
| } | |
| ''' | |
| with open('$BUILD_FILE', 'w') as f: | |
| f.write(content) | |
| print('build.gradle.kts updated successfully') | |
| " | |
| else | |
| # Groovy DSL用の設定 | |
| python3 -c " | |
| with open('$BUILD_FILE', 'r') as f: | |
| content = f.read() | |
| # compileOptionsにcoreLibraryDesugaringEnabledを追加 | |
| if 'coreLibraryDesugaringEnabled' not in content: | |
| content = content.replace( | |
| 'compileOptions {', | |
| 'compileOptions {\n coreLibraryDesugaringEnabled true' | |
| ) | |
| # Java 17に更新 | |
| content = content.replace('JavaVersion.VERSION_1_8', 'JavaVersion.VERSION_17') | |
| content = content.replace("jvmTarget = '1.8'", "jvmTarget = '17'") | |
| # multiDexEnabledを追加 | |
| if 'multiDexEnabled' not in content: | |
| content = content.replace( | |
| 'versionName flutterVersionName', | |
| 'versionName flutterVersionName\n multiDexEnabled true' | |
| ) | |
| # dependenciesにdesugar_jdk_libsを追加 | |
| if 'desugar_jdk_libs' not in content: | |
| if 'dependencies {' in content: | |
| content = content.replace( | |
| 'dependencies {', | |
| \"dependencies {\\n coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'\" | |
| ) | |
| else: | |
| content += \"\\n\\ndependencies {\\n coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'\\n}\\n\" | |
| with open('$BUILD_FILE', 'w') as f: | |
| f.write(content) | |
| print('build.gradle updated successfully') | |
| " | |
| fi | |
| # settings.gradle(.kts)のKotlinバージョンを更新 | |
| if [ -f "android/settings.gradle.kts" ]; then | |
| sed -i 's/kotlin(\"android\") version \"[0-9.]*\"/kotlin(\"android\") version \"1.9.22\"/' android/settings.gradle.kts | |
| echo "settings.gradle.kts updated" | |
| elif [ -f "android/settings.gradle" ]; then | |
| sed -i 's/org.jetbrains.kotlin.android\" version \"[0-9.]*\"/org.jetbrains.kotlin.android\" version \"1.9.22\"/' android/settings.gradle | |
| echo "settings.gradle updated" | |
| fi | |
| - name: Get dependencies | |
| working-directory: flutter-app | |
| run: flutter pub get | |
| - name: Build APK | |
| working-directory: flutter-app | |
| run: flutter build apk --release | |
| - name: Sign APK with apksigner (v4) | |
| if: env.KEYSTORE_BASE64 != '' | |
| env: | |
| KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} | |
| KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} | |
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | |
| KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} | |
| run: | | |
| UNSIGNED_APK="flutter-app/build/app/outputs/flutter-apk/app-release.apk" | |
| SIGNED_APK="flutter-app/build/app/outputs/flutter-apk/similarity_quiz-signed.apk" | |
| # キーストアをデコード | |
| echo "$KEYSTORE_BASE64" | base64 -d > release.keystore | |
| # zipalignで最適化 | |
| ${ANDROID_HOME}/build-tools/34.0.0/zipalign -v -p 4 "$UNSIGNED_APK" "${UNSIGNED_APK%.apk}-aligned.apk" | |
| # apksignerで署名 | |
| ${ANDROID_HOME}/build-tools/34.0.0/apksigner sign \ | |
| --ks release.keystore \ | |
| --ks-key-alias "$KEY_ALIAS" \ | |
| --ks-pass pass:"$KEYSTORE_PASSWORD" \ | |
| --key-pass pass:"$KEY_PASSWORD" \ | |
| --v4-signing-enabled true \ | |
| --out "$SIGNED_APK" \ | |
| "${UNSIGNED_APK%.apk}-aligned.apk" | |
| # 署名の検証 | |
| ${ANDROID_HOME}/build-tools/34.0.0/apksigner verify --verbose "$SIGNED_APK" | |
| # 一時ファイルをクリーンアップ | |
| rm -f release.keystore "${UNSIGNED_APK%.apk}-aligned.apk" | |
| - name: Rename unsigned APK (fallback) | |
| if: env.KEYSTORE_BASE64 == '' | |
| env: | |
| KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} | |
| run: | | |
| mv flutter-app/build/app/outputs/flutter-apk/app-release.apk flutter-app/build/app/outputs/flutter-apk/similarity_quiz-unsigned.apk | |
| - name: Upload APK | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android-apk | |
| path: flutter-app/build/app/outputs/flutter-apk/similarity_quiz-*.apk | |
| # リリースジョブ | |
| release: | |
| runs-on: ubuntu-latest | |
| needs: [build-linux, build-windows, build-macos, build-ios, build-android] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Display structure | |
| run: ls -R artifacts | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: | | |
| artifacts/linux-build/*.tar.gz | |
| artifacts/windows-build/*.zip | |
| artifacts/macos-build/*.zip | |
| artifacts/ios-build/*.ipa | |
| artifacts/android-apk/*.apk | |
| generate_release_notes: true | |
| name: "Flutter App ${{ github.ref_name }}" | |
| body: | | |
| ## Flutter 判別クイズアプリ | |
| ### ダウンロード | |
| - **Windows**: similarity_quiz-windows-x64.zip | |
| - **macOS**: similarity_quiz-macos.zip | |
| - **Linux**: similarity_quiz-linux-x64.tar.gz | |
| - **iOS**: similarity_quiz-ios.ipa (要署名/AltStore等) | |
| - **Android (Quiz App)**: similarity_quiz-unsigned.apk / signed.apk | |
| ### インストール方法 | |
| - Windows: ZIPを解凍して `similarity_quiz.exe` を実行 | |
| - macOS: ZIPを解凍して `similarity_quiz.app` を実行 | |
| - Linux: `tar -xzvf` で解凍して `similarity_quiz` を実行 | |
| - iOS: AltStore/Sideloadly等でインストール | |
| - Android: APKをインストール | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |