Improve mobile/desktop UX and tab bar visuals; bump version to 1.0.10 #12
Workflow file for this run
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: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-android: | |
| runs-on: ubuntu-latest | |
| env: | |
| ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} | |
| ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }} | |
| ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} | |
| ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| - name: Set up Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Configure Android signing | |
| if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }} | |
| shell: bash | |
| run: | | |
| python3 - <<'PY' | |
| import base64 | |
| import os | |
| import re | |
| import sys | |
| raw = os.environ.get("ANDROID_KEYSTORE_BASE64", "") | |
| if raw.startswith("ANDROID_KEYSTORE_BASE64="): | |
| raw = raw.split("=", 1)[1] | |
| raw = raw.strip().strip('"').strip("'") | |
| clean = re.sub(r"[^A-Za-z0-9+/=]", "", raw) | |
| if not clean: | |
| sys.exit("ANDROID_KEYSTORE_BASE64 is empty after normalization.") | |
| clean += "=" * ((4 - len(clean) % 4) % 4) | |
| try: | |
| decoded = base64.b64decode(clean, validate=False) | |
| except Exception as exc: | |
| sys.exit(f"Failed to decode ANDROID_KEYSTORE_BASE64: {exc}") | |
| with open("android/release.keystore", "wb") as f: | |
| f.write(decoded) | |
| PY | |
| STORE_PASSWORD="$(printf '%s' "${ANDROID_STORE_PASSWORD}" | tr -d '\r\n')" | |
| KEY_ALIAS="$(printf '%s' "${ANDROID_KEY_ALIAS}" | tr -d '\r\n')" | |
| KEY_PASSWORD="$(printf '%s' "${ANDROID_KEY_PASSWORD}" | tr -d '\r\n')" | |
| cat > android/key.properties <<EOF | |
| storeFile=../release.keystore | |
| storePassword=${STORE_PASSWORD} | |
| keyAlias=${KEY_ALIAS} | |
| keyPassword=${KEY_PASSWORD} | |
| EOF | |
| - name: Validate Android signing credentials | |
| if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }} | |
| shell: bash | |
| run: | | |
| STORE_PASSWORD="$(printf '%s' "${ANDROID_STORE_PASSWORD}" | tr -d '\r\n')" | |
| KEY_ALIAS="$(printf '%s' "${ANDROID_KEY_ALIAS}" | tr -d '\r\n')" | |
| KEY_PASSWORD="$(printf '%s' "${ANDROID_KEY_PASSWORD}" | tr -d '\r\n')" | |
| set +e | |
| keytool -list -keystore android/release.keystore -storepass "${STORE_PASSWORD}" >/tmp/keystore-list.txt 2>/tmp/keystore-list.err | |
| LIST_STATUS=$? | |
| if [ ${LIST_STATUS} -ne 0 ]; then | |
| echo "Keystore validation failed: store password is incorrect or keystore content is invalid." | |
| cat /tmp/keystore-list.err | |
| exit 1 | |
| fi | |
| keytool -list -keystore android/release.keystore -storepass "${STORE_PASSWORD}" -alias "${KEY_ALIAS}" >/tmp/alias-check.txt 2>/tmp/alias-check.err | |
| ALIAS_STATUS=$? | |
| if [ ${ALIAS_STATUS} -ne 0 ]; then | |
| echo "Alias validation failed: ANDROID_KEY_ALIAS does not exist in keystore." | |
| echo "Available aliases:" | |
| cat /tmp/keystore-list.txt | sed -n '1,80p' | |
| cat /tmp/alias-check.err | |
| exit 1 | |
| fi | |
| keytool -importkeystore \ | |
| -srckeystore android/release.keystore \ | |
| -srcstorepass "${STORE_PASSWORD}" \ | |
| -srcalias "${KEY_ALIAS}" \ | |
| -srckeypass "${KEY_PASSWORD}" \ | |
| -destkeystore /tmp/verify-signing.jks \ | |
| -deststorepass "tempVerify123" \ | |
| -destkeypass "tempVerify123" \ | |
| -noprompt >/tmp/keypass-check.txt 2>/tmp/keypass-check.err | |
| KEYPASS_STATUS=$? | |
| if [ ${KEYPASS_STATUS} -ne 0 ]; then | |
| echo "Key password validation failed: ANDROID_KEY_PASSWORD does not match the key for alias '${KEY_ALIAS}'." | |
| cat /tmp/keypass-check.err | |
| exit 1 | |
| fi | |
| set -e | |
| - name: Build Android release APK | |
| if: ${{ env.ANDROID_KEYSTORE_BASE64 != '' }} | |
| run: flutter build apk --release | |
| - name: Build Android debug APK (fallback) | |
| if: ${{ env.ANDROID_KEYSTORE_BASE64 == '' }} | |
| run: flutter build apk --debug | |
| - name: Prepare Android artifact | |
| shell: bash | |
| run: | | |
| TAG_NAME="${GITHUB_REF_NAME:-manual}" | |
| mkdir -p dist | |
| if [ -f build/app/outputs/flutter-apk/app-release.apk ]; then | |
| cp build/app/outputs/flutter-apk/app-release.apk "dist/NeverMissAlarm-android-${TAG_NAME}.apk" | |
| else | |
| cp build/app/outputs/flutter-apk/app-debug.apk "dist/NeverMissAlarm-android-${TAG_NAME}.apk" | |
| fi | |
| - name: Upload Android artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android-apk | |
| path: dist/*.apk | |
| build-windows: | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Build Windows release | |
| run: flutter build windows --release | |
| - name: Install Inno Setup | |
| shell: pwsh | |
| run: choco install innosetup --no-progress -y | |
| - name: Build Windows installer | |
| shell: pwsh | |
| run: | | |
| $tag = "${env:GITHUB_REF_NAME}" | |
| if ([string]::IsNullOrWhiteSpace($tag)) { $tag = "v0.0.0" } | |
| $version = $tag.TrimStart("v") | |
| $iscc = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" | |
| & $iscc "/DMyAppVersion=$version" "windows\\installer\\NeverMissAlarm.iss" | |
| - name: Create Windows zip artifact | |
| shell: pwsh | |
| run: | | |
| $tag = "${env:GITHUB_REF_NAME}" | |
| if ([string]::IsNullOrWhiteSpace($tag)) { $tag = "manual" } | |
| New-Item -ItemType Directory -Path dist -Force | Out-Null | |
| $zipPath = "dist/NeverMissAlarm-windows-$tag.zip" | |
| Compress-Archive -Path "build/windows/x64/runner/Release/*" -DestinationPath $zipPath -Force | |
| $version = $tag.TrimStart("v") | |
| $installer = "build/windows/installer/NeverMissAlarmSetup_$version.exe" | |
| if (Test-Path $installer) { | |
| Copy-Item $installer "dist/NeverMissAlarm-windows-$tag-setup.exe" -Force | |
| } else { | |
| throw "Installer not found: $installer" | |
| } | |
| - name: Upload Windows artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows-artifacts | |
| path: | | |
| dist/*.zip | |
| dist/*.exe | |
| publish-release: | |
| needs: | |
| - build-android | |
| - build-windows | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download Android artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: android-apk | |
| path: dist | |
| - name: Download Windows artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: windows-artifacts | |
| path: dist | |
| - name: Publish GitHub release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| dist/*.apk | |
| dist/*.zip | |
| dist/*.exe | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true |