name: Custom macOS Client Generator run-name: Custom macOS Client Generator on: workflow_dispatch: inputs: server: description: 'Rendezvous Server' required: true default: '' type: string key: description: 'Public Key' required: true default: '' type: string apiServer: description: 'API Server' required: true default: '' type: string custom: description: "Custom JSON" required: true default: '' type: string uuid: description: "uuid of request" required: true default: '' type: string iconlink: description: "icon link" required: false default: 'false' type: string logolink: description: "logo link" required: false default: 'false' type: string appname: description: "app name" required: true default: 'rustdesk' type: string filename: description: "Filename" required: true default: 'rustdesk' type: string extras: description: "extra inputs in json" required: true default: '{}' type: string env: SCITER_RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503, also 1.78 has ABI change which causes our sciter version not working, https://blog.rust-lang.org/2024/03/30/i128-layout-update.html RUST_VERSION: "1.75" # sciter failed on m1 with 1.78 because of https://blog.rust-lang.org/2024/03/30/i128-layout-update.html MAC_RUST_VERSION: "1.81" CARGO_NDK_VERSION: "3.1.2" SCITER_ARMV7_CMAKE_VERSION: "3.29.7" SCITER_NASM_DEBVERSION: "2.14-1" LLVM_VERSION: "15.0.6" FLUTTER_VERSION: "3.24.5" ANDROID_FLUTTER_VERSION: "3.24.5" # >= 3.16 is very slow on my android phone, but work well on most of others. We may switch to new flutter after changing to texture rendering (I believe it can solve my problem). FLUTTER_RUST_BRIDGE_VERSION: "1.80.1" # for arm64 linux because official Dart SDK does not work FLUTTER_ELINUX_VERSION: "3.16.9" TAG_NAME: "${{ inputs.upload-tag }}" VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" # vcpkg version: 2024.07.12 VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c" VERSION: "${{ fromJson(inputs.extras).version }}" NDK_VERSION: "r27c" #signing keys env variable checks ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}" MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}" # To make a custom build with your own servers set the below secret values RS_PUB_KEY: "${{ inputs.key }}" RENDEZVOUS_SERVER: "${{ inputs.server }}" CUSTOM: "${{ inputs.custom }}" UUIDFOLDER: "${{ inputs.uuid }}" API_SERVER: "${{ inputs.apiServer }}" UPLOAD_ARTIFACT: 'true' SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}" STATUS_URL: "${{ secrets.GENURL }}/updategh" jobs: generate-bridge: uses: ./.github/workflows/bridge.yml with: version: ${{ fromJson(inputs.extras).version }} build-for-macos-flutter: name: Build macOS runs-on: macos-latest needs: [generate-bridge] strategy: fail-fast: false matrix: job: # - { # target: x86_64-apple-darwin, # os: macos-13, #macos-latest or macos-14 use M1 now, https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#:~:text=14%20GB-,macos%2Dlatest%20or%20macos%2D14,-The%20macos%2Dlatestlabel # extra-build-args: "", # arch: x86_64, # vcpkg-triplet: x64-osx, # } - { target: aarch64-apple-darwin, os: macos-latest, # extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296 extra-build-args: "--screencapturekit", arch: aarch64, vcpkg-triplet: arm64-osx, } steps: - name: Export GitHub Actions cache environment variables uses: actions/github-script@v6 with: script: | core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - name: Set rdgen value if: ${{ fromJson(inputs.extras).rdgen == 'true' }} run: | echo "STATUS_URL=${{ secrets.GENURL }}/updategh" >> $env:GITHUB_ENV - name: Set rdgen value if: ${{ fromJson(inputs.extras).rdgen == 'false' }} run: | echo "STATUS_URL=${{ inputs.apiServer }}/api/updategh" >> $env:GITHUB_ENV - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "5% complete"}' - name: Checkout source code if: ${{ env.VERSION != 'master' }} uses: actions/checkout@v4 with: repository: rustdesk/rustdesk ref: refs/tags/${{ env.VERSION }} submodules: recursive - name: Checkout source code if: ${{ env.VERSION == 'master' }} uses: actions/checkout@v4 with: repository: rustdesk/rustdesk submodules: recursive - name: Restore bridge files uses: actions/download-artifact@master with: name: bridge-artifact path: ./ - name: Install imagemagick and potrace and nasm and and shell: bash run: | brew install imagemagick potrace nasm cmake gcc wget ninja echo "$(brew --prefix imagemagick)/bin" >> $GITHUB_PATH - name: Update macOS Info.plist and settings continue-on-error: false shell: bash run: | # MACSTUFF Backup the original Info.plist cp ./flutter/macos/Runner/Info.plist ./flutter/macos/Runner/Info.plist.bak # MACSTUFF Update application name and display name sed -i '' -e 's|CFBundleName\s*$(PRODUCT_NAME)|CFBundleName\n\t${{ inputs.appname }}|' ./flutter/macos/Runner/Info.plist sed -i '' -e 's|CFBundleDisplayName\s*$(PRODUCT_NAME)|CFBundleDisplayName\n\t${{ inputs.appname }}|' ./flutter/macos/Runner/Info.plist sed -i '' -e 's|CFBundleIdentifier\s*$(PRODUCT_BUNDLE_IDENTIFIER)|CFBundleIdentifier\n\tcom.${{ inputs.appname }}.app|' ./flutter/macos/Runner/Info.plist # MACSTUFF Update copyright information if needed sed -i '' -e 's|NSHumanReadableCopyright\s*$(PRODUCT_COPYRIGHT)|NSHumanReadableCopyright\n\t${{ inputs.appname }}|' ./flutter/macos/Runner/Info.plist # MACSTUFF Update window title and bundle settings cp ./flutter/macos/Runner/Configs/AppInfo.xcconfig ./flutter/macos/Runner/Configs/AppInfo.xcconfig.bak sed -i '' -e 's|PRODUCT_NAME = .*|PRODUCT_NAME = ${{ inputs.appname }}|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig sed -i '' -e 's|PRODUCT_BUNDLE_IDENTIFIER = .*|PRODUCT_BUNDLE_IDENTIFIER = com.${{ inputs.appname }}.app|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig sed -i '' -e 's|PRODUCT_COPYRIGHT = .*|PRODUCT_COPYRIGHT = ${{ inputs.appname }} All rights reserved.|' ./flutter/macos/Runner/Configs/AppInfo.xcconfig # Keep DEVELOPMENT_TEAM if it exists, don't blank it out # Update Xcode project settings sed -i '' -e 's/PRODUCT_NAME = "RustDesk"/PRODUCT_NAME = "${{ inputs.appname }}"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj sed -i '' -e 's/PRODUCT_BUNDLE_IDENTIFIER = ".*"/PRODUCT_BUNDLE_IDENTIFIER = "com.${{ inputs.appname }}.app"/' ./flutter/macos/Runner.xcodeproj/project.pbxproj # Don't modify DEVELOPMENT_TEAM in project.pbxproj # Update CMake settings if [ -f "./flutter/macos/CMakeLists.txt" ]; then sed -i '' -e 's/set(BINARY_NAME ".*")/set(BINARY_NAME "${{ inputs.appname }}")/' ./flutter/macos/CMakeLists.txt fi # Update Podfile - keep the target as 'Runner' # sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'${{ inputs.appname }}'"'"' do/' ./flutter/macos/Podfile sed -i '' -e 's/target '"'"'Runner'"'"' do/target '"'"'Runner'"'"' do/' ./flutter/macos/Podfile cp ./src/lang/en.rs ./src/lang/en.rs.bak cp ./src/lang/nl.rs ./src/lang/nl.rs.bak sed -i '' -e 's|RustDesk|${{ inputs.appname }}|' ./src/lang/en.rs sed -i '' -e 's|RustDesk|${{ inputs.appname }}|' ./src/lang/nl.rs sed -i '' -e 's|Homepage: https://rustdesk.com|Homepage: ${{ fromJson(inputs.extras).urlLink }}|' ./build.py sed -i '' -e "s|launchUrl(Uri.parse('https://rustdesk.com'));|launchUrl(Uri.parse('${{ fromJson(inputs.extras).urlLink }}'));|" ./flutter/lib/common.dart sed -i '' -e "s|launchUrlString('https://rustdesk.com');|launchUrlString('${{ fromJson(inputs.extras).urlLink }}');|" ./flutter/lib/desktop/pages/desktop_setting_page.dart sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/desktop/pages/desktop_setting_page.dart sed -i '' -e "s|const url = 'https://rustdesk.com/';|const url = '${{ fromJson(inputs.extras).urlLink }}';|" ./flutter/lib/mobile/pages/settings_page.dart sed -i '' -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/mobile/pages/settings_page.dart sed -i '' -e "s|https://rustdesk.com/privacy.html|${{ fromJson(inputs.extras).urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart sed -i '' -e '/const KEY:/,/};/d' ./src/common.rs sed -i '' -e '/let Ok(data) = sign::verify(&data, &pk)/,/};/d' ./src/common.rs # Update pubspec.yaml with proper YAML formatting cp ./flutter/pubspec.yaml ./flutter/pubspec.yaml.bak echo " archive: ^3.6.1" > ./flutter/temp_dependency.txt awk '/intl:/{print;system("cat ./flutter/temp_dependency.txt");next}1' ./flutter/pubspec.yaml > ./flutter/pubspec.yaml.tmp mv ./flutter/pubspec.yaml.tmp ./flutter/pubspec.yaml rm ./flutter/temp_dependency.txt - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "10% complete"}' - name: Install flutter uses: subosito/flutter-action@v2.12.0 with: channel: "stable" flutter-version: ${{ env.FLUTTER_VERSION }} cache: true - name: Patch flutter continue-on-error: true run: | cp .github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff $(dirname $(dirname $(which flutter))) cd $(dirname $(dirname $(which flutter))) [[ "3.24.4" == 3.24.5 ]] && git apply flutter_3.24.4_dropdown_menu_enableFilter.diff - name: Workaround for flutter issue shell: bash run: | cd "$(dirname "$(which flutter)")" # https://github.com/flutter/flutter/issues/1.3.43 sed -i -e 's/_setFramesEnabledState(false);/\/\/_setFramesEnabledState(false);/g' ../packages/flutter/lib/src/scheduler/binding.dart grep -n '_setFramesEnabledState(false);' ../packages/flutter/lib/src/scheduler/binding.dart - name: Install Rust toolchain uses: dtolnay/rust-toolchain@v1 with: toolchain: ${{ env.MAC_RUST_VERSION }} targets: ${{ matrix.job.target }} components: "rustfmt" - uses: Swatinem/rust-cache@v2 with: prefix-key: ${{ matrix.job.os }} - name: Magick stuff for macOS if: ${{ inputs.iconlink != 'false' }} continue-on-error: false shell: bash run: | # Create all necessary directories first mkdir -p ./res mkdir -p ./flutter/assets mkdir -p ./flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset mkdir -p ./macos/Runner/Assets.xcassets/AppIcon.appiconset mkdir -p ./rustdesk/data/flutter_assets/assets # Download icon using curl with additional SSL options curl -k -L --tlsv1.2 --proto =https --ssl-reqd \ -H "User-Agent: Mozilla/5.0" \ "${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}&uuid=${{ fromJson(inputs.iconlink).uuid }}" \ -o ./res/icon.png || wget --no-check-certificate -O ./res/icon.png "${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}&uuid=${{ fromJson(inputs.iconlink).uuid }}" # Backup existing files (if they exist) [ -f "./res/32x32.png" ] && mv ./res/32x32.png ./res/32x32.png.bak [ -f "./res/64x64.png" ] && mv ./res/64x64.png ./res/64x64.png.bak [ -f "./res/128x128.png" ] && mv ./res/128x128.png ./res/128x128.png.bak [ -f "./res/mac-icon.png" ] && mv ./res/mac-icon.png ./res/mac-icon.png.bak [ -f "./flutter/assets/icon.png" ] && mv ./flutter/assets/icon.png ./flutter/assets/icon.png.bak [ -f "./flutter/assets/icon.svg" ] && mv ./flutter/assets/icon.svg ./flutter/assets/icon.svg.bak [ -f "./rustdesk/data/flutter_assets/assets/icon.svg" ] && mv ./rustdesk/data/flutter_assets/assets/icon.svg ./rustdesk/data/flutter_assets/assets/icon.svg.bak # Create standard app icons magick ./res/icon.png -resize 32x32 ./res/32x32.png magick ./res/icon.png -resize 64x64 ./res/64x64.png magick ./res/icon.png -resize 128x128 ./res/128x128.png # Copy icon to Flutter assets cp ./res/icon.png ./flutter/assets/icon.png cp ./res/icon.png ./rustdesk/data/flutter_assets/assets/icon.png # Convert PNG to SVG using potrace magick ./res/icon.png -flatten ./temp_icon.pbm potrace --svg -o ./flutter/assets/icon.svg ./temp_icon.pbm cp ./flutter/assets/icon.svg ./rustdesk/data/flutter_assets/assets/icon.svg rm ./temp_icon.pbm # Create macOS app icons magick ./res/icon.png -resize 16x16 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png" magick ./res/icon.png -resize 32x32 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png" magick ./res/icon.png -resize 64x64 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png" magick ./res/icon.png -resize 128x128 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png" magick ./res/icon.png -resize 256x256 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png" magick ./res/icon.png -resize 512x512 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png" magick ./res/icon.png -resize 1024x1024 "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png" # Create macOS specific icons magick ./res/icon.png -resize 128x128 ./res/mac-icon.png # Create dark mode tray icon (optimized for macOS menu bar) magick ./res/icon.png -resize 22x22 -colorspace gray -alpha set -background none -channel A -evaluate set 100% ./res/mac-tray-dark-x2.png # Create light mode tray icon (optimized for macOS menu bar) magick ./res/icon.png -resize 22x22 -negate -colorspace gray -alpha set -background none -channel A -evaluate set 100% ./res/mac-tray-light-x2.png # Create AppIcon.icns (macOS native icon format) mkdir -p ./iconset.iconset cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png" "./iconset.iconset/icon_16x16.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png" "./iconset.iconset/icon_16x16@2x.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png" "./iconset.iconset/icon_32x32.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png" "./iconset.iconset/icon_32x32@2x.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png" "./iconset.iconset/icon_128x128.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png" "./iconset.iconset/icon_128x128@2x.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png" "./iconset.iconset/icon_256x256.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png" "./iconset.iconset/icon_256x256@2x.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png" "./iconset.iconset/icon_512x512.png" cp "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png" "./iconset.iconset/icon_512x512@2x.png" iconutil -c icns ./iconset.iconset -o ./flutter/macos/Runner/AppIcon.icns rm -rf ./iconset.iconset # Create Contents.json for macOS app icon echo '{ "images": [ {"size":"16x16","idiom":"mac","filename":"app_icon_16.png","scale":"1x"}, {"size":"16x16","idiom":"mac","filename":"app_icon_32.png","scale":"2x"}, {"size":"32x32","idiom":"mac","filename":"app_icon_32.png","scale":"1x"}, {"size":"32x32","idiom":"mac","filename":"app_icon_64.png","scale":"2x"}, {"size":"128x128","idiom":"mac","filename":"app_icon_128.png","scale":"1x"}, {"size":"128x128","idiom":"mac","filename":"app_icon_256.png","scale":"2x"}, {"size":"256x256","idiom":"mac","filename":"app_icon_256.png","scale":"1x"}, {"size":"256x256","idiom":"mac","filename":"app_icon_512.png","scale":"2x"}, {"size":"512x512","idiom":"mac","filename":"app_icon_512.png","scale":"1x"}, {"size":"512x512","idiom":"mac","filename":"app_icon_1024.png","scale":"2x"} ], "info": { "version": 1, "author": "xcode" } }' > "flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json" # Copy icons and Contents.json to both locations cp -r flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/* macos/Runner/Assets.xcassets/AppIcon.appiconset/ # Verify files exist and show their sizes echo "Verifying generated files:" ls -lh ./res/mac-tray-dark-x2.png ls -lh ./res/mac-tray-light-x2.png ls -lh ./res/mac-icon.png echo "Flutter macOS app icons:" ls -lh flutter/macos/Runner/Assets.xcassets/AppIcon.appiconset/ echo "Flutter assets:" ls -lh flutter/assets/icon.* echo "RustDesk Flutter assets:" ls -lh rustdesk/data/flutter_assets/assets/ - name: replace flutter icons if: ${{ inputs.iconlink != 'false' }} continue-on-error: false shell: bash run: | cd ./flutter # Create required directories and files mkdir -p web mkdir -p assets echo '{"name":"${{ inputs.appname }}","short_name":"${{ inputs.appname }}","start_url":"/","display":"standalone","background_color":"#ffffff","theme_color":"#ffffff","description":"A remote desktop software."}' > web/manifest.json echo '${{ inputs.appname }}' > web/index.html # Ensure the AppIcon.appiconset directory exists mkdir -p macos/Runner/Assets.xcassets/AppIcon.appiconset # Copy the processed icons to Flutter locations cp ../res/mac-icon.png ./assets/icon.png cp ../flutter/assets/icon.svg ./assets/icon.svg || true flutter pub upgrade win32 flutter pub get flutter pub run flutter_launcher_icons cd .. - name: ui.rs if: ${{ inputs.iconlink != 'false' }} continue-on-error: true shell: bash run: | cp ./src/ui.rs ./src/ui.rs.bak if [ -f "./res/icon.png" ]; then SEARCH_STR="iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAEiuAABIrgHwmhA7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAEx9JREFUeJztnXmYHMV5h9" b64=$(base64 < ./res/icon.png) sed -i '' -e "s~$SEARCH_STR.*\"~$b64\"~" ./src/ui.rs fi - name: fix connection delay continue-on-error: false if: ${{ fromJson(inputs.extras).delayFix == 'true' }} shell: bash run: | sed -i '' -e '/if !key.is_empty() && !token.is_empty() {/,/}/d' ./src/client.rs - name: add cycle monitors to toolbar continue-on-error: true if: fromJson(inputs.extras).cycleMonitor == 'true' run: | wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/cycle_monitor.diff git apply cycle_monitor.diff - name: use X for offline display instead of orange circle continue-on-error: true if: fromJson(inputs.extras).xOffline == 'true' run: | wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/xoffline.diff git apply xoffline.diff - name: hide-cm continue-on-error: true if: fromJson(inputs.extras).hidecm == 'true' run: | wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/hidecm.diff git apply hidecm.diff - name: statussort continue-on-error: true if: fromJson(inputs.extras).statussort == 'true' run: | wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/statussort.diff git apply statussort.diff - name: removeNewVersionNotif continue-on-error: true if: fromJson(inputs.extras).removeNewVersionNotif == 'true' run: | wget https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeNewVersionNotif.diff git apply removeNewVersionNotif.diff - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "15% complete"}' - uses: Swatinem/rust-cache@v2 with: prefix-key: ${{ matrix.job.os }} - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "20% complete"}' - name: Setup vcpkg with Github Actions binary cache uses: lukka/run-vcpkg@v11 with: vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }} doNotCache: false - name: Install vcpkg dependencies run: | if ! $VCPKG_ROOT/vcpkg \ install \ --x-install-root="$VCPKG_ROOT/installed"; then find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do echo "$_1:" echo "======" cat "$_1" echo "======" echo "" done exit 1 fi - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "25% complete"}' - name: Create MacOS directory structure run: | mkdir -p ./build/macos/Build/Products/Release/RustDesk.app/Contents/MacOS - name: Build rustdesk run: | if [ "${{ matrix.job.target }}" = "aarch64-apple-darwin" ]; then MIN_MACOS_VERSION="12.3" sed -i -e "s/MACOSX_DEPLOYMENT_TARGET\=[0-9]*.[0-9]*/MACOSX_DEPLOYMENT_TARGET=${MIN_MACOS_VERSION}/" build.py sed -i -e "s/platform :osx, '.*'/platform :osx, '${MIN_MACOS_VERSION}'/" flutter/macos/Podfile sed -i -e "s/osx_minimum_system_version = \"[0-9]*.[0-9]*\"/osx_minimum_system_version = \"${MIN_MACOS_VERSION}\"/" Cargo.toml sed -i -e "s/MACOSX_DEPLOYMENT_TARGET = [0-9]*.[0-9]*;/MACOSX_DEPLOYMENT_TARGET = ${MIN_MACOS_VERSION};/" flutter/macos/Runner.xcodeproj/project.pbxproj fi sed -i -e "s/RustDesk.app/\"${{ inputs.appname }}.app\"/" build.py ./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }} # - name: Copy service file # run: | # cp -rf ../target/release/service ./build/macos/Build/Products/Release/RustDesk.app/Contents/MacOS/ - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "50% complete, this step takes about 5 minutes, be patient."}' - name: Install rcodesign tool if: env.MACOS_P12_BASE64 != null shell: bash run: | pushd /tmp wget https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-macos-universal.tar.gz tar -zxvf apple-codesign-0.22.0-macos-universal.tar.gz mv apple-codesign-0.22.0-macos-universal/rcodesign /usr/local/bin popd - name: Install build runtime run: | brew install llvm create-dmg nasm cmake gcc wget ninja # pkg-config is handled in a separate step, because it may be already installed by `macos-latest`(14.7.1) runner if command -v pkg-config &>/dev/null; then echo "pkg-config is already installed" else brew install pkg-config fi - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "70% complete, this step takes about 5 minutes, be patient."}' - name: Show version information (Rust, cargo, Clang) shell: bash run: | clang --version || true rustup -V rustup toolchain list rustup default cargo -V rustc -V - name: icon svg handling if: ${{ inputs.iconlink != 'false' }} continue-on-error: false shell: bash run: | ASSETS_DIR="build/macos/Build/Products/Release/RustDesk.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/assets" mkdir -p "$ASSETS_DIR" if [ -f "$ASSETS_DIR/icon.svg" ]; then mv "$ASSETS_DIR/icon.svg" "$ASSETS_DIR/icon.svg.bak" fi # First convert PNG to PBM (bitmap) magick convert ./res/icon.png ./temp_icon.pbm # Then use potrace to convert to SVG potrace --svg -o "$ASSETS_DIR/icon.svg" ./temp_icon.pbm rm ./temp_icon.pbm - name: logo handling if: ${{ inputs.logolink != 'false' }} continue-on-error: false shell: bash run: | ASSETS_DIR="build/macos/Build/Products/Release/RustDesk.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/assets" mkdir -p "$ASSETS_DIR" curl -k -L --tlsv1.2 --proto =https --ssl-reqd \ -H "User-Agent: Mozilla/5.0" \ "${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}&uuid=${{ fromJson(inputs.logolink).uuid }}" \ -o "$ASSETS_DIR/logo.png" || \ wget --no-check-certificate \ -O "$ASSETS_DIR/logo.png" \ "${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}&uuid=${{ fromJson(inputs.logolink).uuid }}" - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "85% complete"}' - name: Sign macOS app bundle if: env.MACOS_P12_BASE64 != '' run: | cd flutter/build/macos/Build/Products/Release # Debug info echo "Current directory contents:" ls -la # Rename RustDesk.app to the custom app name first if [ -d "RustDesk.app" ]; then # First rename the app if it's still called RustDesk.app mv "RustDesk.app" "${{ inputs.appname }}.app" echo "Renamed RustDesk.app to ${{ inputs.appname }}.app" fi echo "App bundle contents after rename:" ls -la "${{ inputs.appname }}.app" || echo "App not found" ls -la "${{ inputs.appname }}.app/Contents" || echo "Contents not found" # Decode the certificate echo "${{ secrets.MACOS_P12_BASE64 }}" | base64 --decode > certificate.p12 # Sign the app bundle and its contents if [ -d "${{ inputs.appname }}.app/Contents/MacOS" ]; then echo "Signing main executable..." MAIN_EXECUTABLE="${{ inputs.appname }}.app/Contents/MacOS/${{ inputs.appname }}" if [ -f "$MAIN_EXECUTABLE" ]; then rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \ --code-signature-flags runtime "$MAIN_EXECUTABLE" else echo "Main executable not found at expected path: $MAIN_EXECUTABLE" # Try to find the actual executable echo "Available executables in MacOS directory:" ls -la "${{ inputs.appname }}.app/Contents/MacOS/" ACTUAL_EXECUTABLE=$(ls "${{ inputs.appname }}.app/Contents/MacOS/" | head -n 1) if [ -n "$ACTUAL_EXECUTABLE" ]; then echo "Found executable: $ACTUAL_EXECUTABLE" rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \ --code-signature-flags runtime "${{ inputs.appname }}.app/Contents/MacOS/$ACTUAL_EXECUTABLE" fi fi echo "Signing frameworks..." find "${{ inputs.appname }}.app/Contents/Frameworks" -type f -not -name ".*" -exec \ rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \ --code-signature-flags runtime {} \; echo "Signing main bundle..." rcodesign sign --p12-file certificate.p12 --p12-password "${{ secrets.MACOS_P12_PASSWORD }}" \ --code-signature-flags runtime "${{ inputs.appname }}.app" else echo "Error: Invalid app bundle structure" exit 1 fi # Clean up rm certificate.p12 - name: Create DMG run: | cd /Users/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/flutter/build/macos/Build/Products/Release # Print directory contents for debugging echo "Directory contents:" ls -la # Find the actual .app bundle if [ -d "RustDesk.app" ]; then # First rename the app if it's still called RustDesk.app mv "RustDesk.app" "${{ inputs.appname }}.app" fi if [ ! -d "${{ inputs.appname }}.app" ]; then echo "Could not find .app bundle!" exit 1 fi echo "Creating DMG for ${{ inputs.appname }}.app" create-dmg \ --volname "${{ inputs.appname }}" \ --window-pos 200 120 \ --window-size 800 400 \ --icon-size 100 \ --icon "${{ inputs.appname }}.app" 200 190 \ --hide-extension "${{ inputs.appname }}.app" \ --app-drop-link 600 185 \ "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg" \ "${{ inputs.appname }}.app" mv "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg" $GITHUB_WORKSPACE/ #- name: Upload unsigned macOS app # if: env.UPLOAD_ARTIFACT == 'true' # uses: actions/upload-artifact@master # with: # name: ${{ inputs.appname }}-${{ matrix.job.arch }} # path: ${{ inputs.appname }}-${{ matrix.job.arch }}.dmg - name: Rename rustdesk if: env.UPLOAD_ARTIFACT == 'true' run: | cd $GITHUB_WORKSPACE echo "Directory contents:" ls -la # Find the DMG file dynamically DMG_FILE=$(find . -name "${{ inputs.appname }}-${{ matrix.job.arch }}.dmg") if [ -n "$DMG_FILE" ]; then echo "Found DMG file: $DMG_FILE" mv "$DMG_FILE" "${{ inputs.filename }}.dmg" echo "Renamed to ${{ inputs.filename }}.dmg" else echo "No DMG file found matching the pattern" exit 1 fi - name: send file to rdgen server if: ${{ fromJson(inputs.extras).rdgen == 'true' }} shell: bash run: | curl -i -X POST \ -H "Content-Type: multipart/form-data" \ -H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" \ -F "file=@$GITHUB_WORKSPACE/${{ inputs.filename }}.dmg" \ -F "uuid=${{ inputs.uuid }}" \ "${{ secrets.GENURL }}/save_custom_client" - name: send file to api server if: ${{ fromJson(inputs.extras).rdgen == 'false' }} shell: bash run: | curl -i -X POST \ -H "Content-Type: multipart/form-data" \ -H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" \ -F "file=@$GITHUB_WORKSPACE/${{ inputs.filename }}.dmg" \ "${{ inputs.apiServer }}/api/save_custom_client" - name: Report Status uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "Success"}' - name: failed if: failure() uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation failed, try again"}' - name: failed if: cancelled() uses: fjogeleit/http-request-action@v1 with: url: ${{ env.STATUS_URL }} method: 'POST' customHeaders: '{"Content-Type": "application/json"}' data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation cancelled, try again"}' #- name: Publish DMG package # if: env.UPLOAD_ARTIFACT == 'true' # uses: softprops/action-gh-release@v1 # with: # prerelease: true # tag_name: ${{ inputs.upload-tag }} # files: | # ${{ inputs.appname }}*-${{ matrix.job.arch }}.dmg