fix(ci): do not overwrite android google-services.json when secret is… #3
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*' | |
| permissions: | |
| contents: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build-desktop: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Windows x86_64 | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| client: windows | |
| archive: zip | |
| ext: .exe | |
| # macOS x86_64 (Intel) | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| client: mac | |
| archive: tar.gz | |
| ext: "" | |
| # macOS aarch64 (Apple Silicon) | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| client: mac | |
| archive: tar.gz | |
| ext: "" | |
| # Linux x86_64 | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| client: linux | |
| archive: tar.gz | |
| ext: "" | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install Linux dependencies | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libxdo-dev \ | |
| libx11-dev \ | |
| libxrandr-dev \ | |
| libxi-dev \ | |
| libxtst-dev \ | |
| libglib2.0-dev \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev \ | |
| libxcb-shape0-dev \ | |
| libxcb-xfixes0-dev \ | |
| libdbus-1-dev | |
| - name: Build | |
| working-directory: ${{ matrix.client }} | |
| run: cargo build --release --target ${{ matrix.target }} | |
| - name: Determine archive name | |
| id: archive | |
| shell: bash | |
| run: | | |
| version="${GITHUB_REF_NAME}" | |
| arch="${{ matrix.target }}" | |
| name="screenmcp-${{ matrix.client }}-${arch}-${version}" | |
| echo "name=${name}" >> "$GITHUB_OUTPUT" | |
| echo "version=${version}" >> "$GITHUB_OUTPUT" | |
| - name: Package macOS (.app + .dmg) | |
| if: matrix.client == 'mac' | |
| shell: bash | |
| run: | | |
| APP="ScreenMCP.app" | |
| BINARY="mac/target/${{ matrix.target }}/release/screenmcp-mac" | |
| # Create .app bundle | |
| mkdir -p "${APP}/Contents/MacOS" "${APP}/Contents/Resources" | |
| cp mac/Info.plist "${APP}/Contents/Info.plist" | |
| cp "$BINARY" "${APP}/Contents/MacOS/screenmcp-mac" | |
| chmod +x "${APP}/Contents/MacOS/screenmcp-mac" | |
| echo "APPLscmc" > "${APP}/Contents/PkgInfo" | |
| # Ad-hoc sign (no developer cert needed, satisfies basic integrity checks) | |
| codesign --force --deep -s - "${APP}" | |
| # Create .dmg using hdiutil (native on macOS runners) | |
| staging="${{ steps.archive.outputs.name }}" | |
| hdiutil create -volname "ScreenMCP" -srcfolder "${APP}" -ov -format UDZO "${staging}.dmg" | |
| echo "ASSET=${staging}.dmg" >> "$GITHUB_ENV" | |
| - name: Package (Unix, non-Mac) | |
| if: matrix.archive == 'tar.gz' && matrix.client != 'mac' | |
| shell: bash | |
| run: | | |
| staging="${{ steps.archive.outputs.name }}" | |
| mkdir -p "${staging}" | |
| cp "${{ matrix.client }}/target/${{ matrix.target }}/release/screenmcp-${{ matrix.client }}${{ matrix.ext }}" "${staging}/" | |
| cp "${{ matrix.client }}/README.md" "${staging}/" 2>/dev/null || true | |
| tar czf "${staging}.tar.gz" "${staging}" | |
| echo "ASSET=${staging}.tar.gz" >> "$GITHUB_ENV" | |
| - name: Package (Windows) | |
| if: matrix.archive == 'zip' | |
| shell: bash | |
| run: | | |
| staging="${{ steps.archive.outputs.name }}" | |
| mkdir -p "${staging}" | |
| cp "${{ matrix.client }}/target/${{ matrix.target }}/release/screenmcp-${{ matrix.client }}${{ matrix.ext }}" "${staging}/" | |
| cp "${{ matrix.client }}/README.md" "${staging}/" 2>/dev/null || true | |
| 7z a "${staging}.zip" "${staging}" | |
| echo "ASSET=${staging}.zip" >> "$GITHUB_ENV" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.archive.outputs.name }} | |
| path: ${{ env.ASSET }} | |
| build-android: | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: android | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| - name: Setup Android SDK | |
| uses: android-actions/setup-android@v3 | |
| - name: Provide google-services.json | |
| env: | |
| GOOGLE_SERVICES_JSON_B64: ${{ secrets.GOOGLE_SERVICES_JSON }} | |
| run: | | |
| if [ -n "$GOOGLE_SERVICES_JSON_B64" ]; then | |
| echo "$GOOGLE_SERVICES_JSON_B64" | base64 -d > app/google-services.json | |
| echo "Using google-services.json from secret." | |
| elif [ -f "app/google-services.json" ]; then | |
| echo "Using checked-in app/google-services.json." | |
| else | |
| echo "ERROR: app/google-services.json not found and GOOGLE_SERVICES_JSON secret is empty." | |
| exit 1 | |
| fi | |
| - name: Build release APK | |
| run: ./gradlew assembleRelease | |
| - name: Sign APK | |
| 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: | | |
| echo "$KEYSTORE_BASE64" | base64 -d > keystore.jks | |
| # Find the unsigned APK | |
| APK=$(find app/build/outputs/apk/release -name '*.apk' | head -1) | |
| ALIGNED="app/build/outputs/apk/release/screenmcp-aligned.apk" | |
| SIGNED="app/build/outputs/apk/release/screenmcp-signed.apk" | |
| zipalign -v -p 4 "$APK" "$ALIGNED" | |
| apksigner sign \ | |
| --ks keystore.jks \ | |
| --ks-pass "pass:$KEYSTORE_PASSWORD" \ | |
| --ks-key-alias "$KEY_ALIAS" \ | |
| --key-pass "pass:$KEY_PASSWORD" \ | |
| --out "$SIGNED" \ | |
| "$ALIGNED" | |
| rm keystore.jks | |
| - name: Determine APK name | |
| id: apk | |
| shell: bash | |
| run: | | |
| version="${GITHUB_REF_NAME}" | |
| # Use signed APK if it exists, otherwise unsigned | |
| if [ -f "app/build/outputs/apk/release/screenmcp-signed.apk" ]; then | |
| APK_PATH="app/build/outputs/apk/release/screenmcp-signed.apk" | |
| else | |
| APK_PATH=$(find app/build/outputs/apk/release -name '*.apk' | head -1) | |
| fi | |
| DEST="screenmcp-android-${version}.apk" | |
| cp "$APK_PATH" "$DEST" | |
| echo "path=${DEST}" >> "$GITHUB_OUTPUT" | |
| echo "name=${DEST}" >> "$GITHUB_OUTPUT" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: screenmcp-android | |
| path: ${{ steps.apk.outputs.path }} | |
| build-windows-installer: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y nsis mingw-w64 | |
| - name: Install Rust toolchain (Windows GNU target) | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-pc-windows-gnu | |
| - name: Build Windows installer (.exe) | |
| working-directory: windows | |
| run: ./build-installer.sh "${GITHUB_REF_NAME#v}" | |
| - name: Determine installer name | |
| id: installer | |
| shell: bash | |
| run: | | |
| version="${GITHUB_REF_NAME#v}" | |
| file="screenmcp-setup-${version}-x86_64.exe" | |
| cp "windows/target/installer/${file}" "${file}" | |
| echo "path=${file}" >> "$GITHUB_OUTPUT" | |
| echo "name=${file}" >> "$GITHUB_OUTPUT" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: screenmcp-windows-installer | |
| path: ${{ steps.installer.outputs.path }} | |
| release: | |
| needs: [build-desktop, build-android, build-windows-installer] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Collect release assets | |
| run: | | |
| mkdir -p release | |
| find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' -o -name '*.apk' -o -name '*.dmg' -o -name 'screenmcp-setup-*-x86_64.exe' \) -exec mv {} release/ \; | |
| ls -lh release/ | |
| - name: Generate checksums | |
| working-directory: release | |
| run: | | |
| sha256sum * > SHA256SUMS.txt | |
| cat SHA256SUMS.txt | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| release/* | |
| generate_release_notes: true | |
| draft: false | |
| prerelease: ${{ contains(github.ref_name, '-') }} | |
| body: | | |
| ## Downloads | |
| | Platform | File | Notes | | |
| |----------|------|-------| | |
| | **macOS (Apple Silicon)** | `screenmcp-mac-aarch64-apple-darwin-*.dmg` | M1/M2/M3/M4 Macs | | |
| | **macOS (Intel)** | `screenmcp-mac-x86_64-apple-darwin-*.dmg` | Older Intel Macs | | |
| | **Windows** | `screenmcp-windows-*.zip` | x86_64 | | |
| | **Windows Installer** | `screenmcp-setup-*-x86_64.exe` | NSIS setup wizard | | |
| | **Linux** | `screenmcp-linux-*.tar.gz` | x86_64 | | |
| | **Android** | `screenmcp-android-*.apk` | ARM/x86 | | |
| ## macOS Installation | |
| 1. Download the `.dmg` for your architecture (Apple Silicon or Intel) | |
| 2. Open the `.dmg` and drag **ScreenMCP** to `/Applications` | |
| 3. **Important** — the app is not notarized, so macOS Gatekeeper will block it. Run: | |
| ```bash | |
| xattr -cr /Applications/ScreenMCP.app | |
| ``` | |
| 4. Launch ScreenMCP — it appears as a menu bar icon (no Dock icon) | |
| 5. Grant **Accessibility** and **Screen Recording** permissions when prompted | |
| ## Windows / Linux | |
| Extract the archive and run the `screenmcp-windows.exe` or `screenmcp-linux` binary. | |
| ## Android | |
| Install the APK directly. You may need to enable "Install from unknown sources". |