fix(windows): hide console window and log to file #5
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: Sign Windows binary | |
| if: matrix.client == 'windows' && env.CODE_SIGNING_PFX != '' | |
| env: | |
| CODE_SIGNING_PFX: ${{ secrets.CODE_SIGNING_PFX }} | |
| CODE_SIGNING_PASSWORD: ${{ secrets.CODE_SIGNING_PASSWORD }} | |
| shell: pwsh | |
| run: | | |
| $pfxBytes = [Convert]::FromBase64String($env:CODE_SIGNING_PFX) | |
| [IO.File]::WriteAllBytes("$pwd\codesign.pfx", $pfxBytes) | |
| $exe = "${{ matrix.client }}\target\${{ matrix.target }}\release\screenmcp-${{ matrix.client }}.exe" | |
| $signtool = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits" -Recurse -Filter signtool.exe | Where-Object { $_.FullName -like "*x64*" } | Select-Object -First 1 -ExpandProperty FullName | |
| & $signtool sign /f codesign.pfx /p $env:CODE_SIGNING_PASSWORD /tr http://timestamp.digicert.com /td SHA256 /fd SHA256 $exe | |
| Remove-Item codesign.pfx | |
| - 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: Verify google-services.json exists | |
| run: test -f app/google-services.json | |
| - 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: Sign Windows installer | |
| if: env.CODE_SIGNING_PFX != '' | |
| env: | |
| CODE_SIGNING_PFX: ${{ secrets.CODE_SIGNING_PFX }} | |
| CODE_SIGNING_PASSWORD: ${{ secrets.CODE_SIGNING_PASSWORD }} | |
| run: | | |
| sudo apt-get install -y osslsigncode | |
| echo "$CODE_SIGNING_PFX" | base64 -d > codesign.pfx | |
| version="${GITHUB_REF_NAME#v}" | |
| file="windows/target/installer/screenmcp-setup-${version}-x86_64.exe" | |
| osslsigncode sign \ | |
| -pkcs12 codesign.pfx \ | |
| -pass "$CODE_SIGNING_PASSWORD" \ | |
| -ts http://timestamp.digicert.com \ | |
| -h sha256 \ | |
| -in "$file" \ | |
| -out "${file}.signed" | |
| mv "${file}.signed" "$file" | |
| rm codesign.pfx | |
| - 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". |