Hi,
We have been testing RDGen-generated macOS clients and found a repeatable installation flow for custom clients that solves several practical issues:
- Gatekeeper/quarantine blocking the generated
.app
- ad-hoc signing requirement
- installing the generated
.app into /Applications
- installing the RustDesk macOS service for a custom app name
- correctly loading both:
com.carriez.<APP_NAME>_service
com.carriez.<APP_NAME>_server
- handling custom clients such as:
ImagineIT_Console.app
ImagineIT_Remote_Access.app
- cleaning previous custom-client installations before reinstalling
- supporting both Intel and Apple Silicon DMGs in the same ZIP package
The key issue we found is that the daemon may install correctly, but the user LaunchAgent may not start automatically in the active GUI session. Loading it explicitly without sudo fixes it:
launchctl bootstrap gui/$(id -u) /Library/LaunchAgents/com.carriez.<APP_NAME>_server.plist
launchctl enable gui/$(id -u)/com.carriez.<APP_NAME>_server
launchctl kickstart -kp gui/$(id -u)/com.carriez.<APP_NAME>_server
We now have a working install.command script that:
Detects the Mac architecture.
Selects the matching DMG (x86_64 or aarch64).
Installs the .app into /Applications.
Removes quarantine attributes.
Applies ad-hoc signing.
Installs the service using the RustDesk macOS service logic.
Forces the user LaunchAgent to load in the current GUI session.
Optionally cleans previous custom RDGen clients.
Would you be interested in including this as documentation, an example script, or a helper installer for macOS RDGen clients?
I will share the full script, hope it helps.
I will share the full script, hope it helps.
What the script currently does:
* Detects the Mac architecture using `uname -m`.
* Automatically selects the matching DMG from the same folder:
* `x86_64` for Intel Macs.
* `aarch64` for Apple Silicon Macs.
* Mounts the selected DMG.
* Detects the `.app` bundle inside the DMG.
* Installs the app into `/Applications`.
* Removes quarantine attributes with `xattr`.
* Fixes execution permissions.
* Applies ad-hoc code signing with `codesign --sign -`.
* Optionally cleans previous custom RDGen client installations.
* Installs the macOS RustDesk service using the known working service installation logic.
* Creates/validates the required preference files.
* Loads the system LaunchDaemon:
* `com.carriez.<APP_NAME>_service`
* Forces the user LaunchAgent to load in the active GUI session:
* `com.carriez.<APP_NAME>_server`
* Opens the installed app after installation.
* Prints useful verification commands and log paths.
The key fix for us was that the daemon could be installed and running, but the user LaunchAgent did not always start in the current GUI session. Explicitly loading it without `sudo` fixed the issue:
```bash
launchctl bootstrap gui/$(id -u) /Library/LaunchAgents/com.carriez.<APP_NAME>_server.plist
launchctl enable gui/$(id -u)/com.carriez.<APP_NAME>_server
launchctl kickstart -kp gui/$(id -u)/com.carriez.<APP_NAME>_server
Below is the small hardcoded cleanup function we are using for our own custom RDGen macOS clients.
In our case, we have two possible custom clients:
ImagineIT_Console.app
ImagineIT_Remote_Access.app
Before installing a new client, we clean both possible previous installations to avoid leaving old LaunchDaemons, LaunchAgents, preferences, or app bundles behind.
clean_all_imagineit_products() {
echo ""
echo "Cleaning previous ImagineIT RDGen products..."
echo ""
clean_existing_installation "ImagineIT_Console" "/Applications/ImagineIT_Console.app"
clean_existing_installation "ImagineIT_Remote_Access" "/Applications/ImagineIT_Remote_Access.app"
echo ""
echo "Finished cleaning previous ImagineIT RDGen products."
}
This function depends on a generic cleanup helper like:
clean_existing_installation "APP_NAME_WITHOUT_DOT_APP" "/Applications/APP_NAME.app"
For example:
clean_existing_installation "MyCompany_RemoteSupport" "/Applications/MyCompany_RemoteSupport.app"
To adapt this to another RDGen user/company, only replace the hardcoded app names:
clean_all_custom_rdgen_products() {
echo ""
echo "Cleaning previous custom RDGen products..."
echo ""
clean_existing_installation "MyCompany_Console" "/Applications/MyCompany_Console.app"
clean_existing_installation "MyCompany_RemoteAccess" "/Applications/MyCompany_RemoteAccess.app"
echo ""
echo "Finished cleaning previous custom RDGen products."
}
If there is only one custom client, this can be simplified to:
clean_all_custom_rdgen_products() {
clean_existing_installation "MyCompany_RemoteAccess" "/Applications/MyCompany_RemoteAccess.app"
}
The important part is that the app name must match the real .app bundle name, because RustDesk macOS services are derived from it:
/Applications/MyCompany_RemoteAccess.app
com.carriez.MyCompany_RemoteAccess_service
com.carriez.MyCompany_RemoteAccess_server
~/Library/Preferences/com.carriez.MyCompany_RemoteAccess/
This made it possible for us to switch cleanly between different RDGen-generated macOS clients without leaving old services running.
One final note: the script is currently written in Spanish because our team is Spanish-speaking. If this is useful for the project, I can later help adapt the messages and comments to English.
install.zip
Hi,
We have been testing RDGen-generated macOS clients and found a repeatable installation flow for custom clients that solves several practical issues:
.app.appinto/Applicationscom.carriez.<APP_NAME>_servicecom.carriez.<APP_NAME>_serverImagineIT_Console.appImagineIT_Remote_Access.appThe key issue we found is that the daemon may install correctly, but the user LaunchAgent may not start automatically in the active GUI session. Loading it explicitly without
sudofixes it:Below is the small hardcoded cleanup function we are using for our own custom RDGen macOS clients.
In our case, we have two possible custom clients:
ImagineIT_Console.appImagineIT_Remote_Access.appBefore installing a new client, we clean both possible previous installations to avoid leaving old LaunchDaemons, LaunchAgents, preferences, or app bundles behind.
This function depends on a generic cleanup helper like:
For example:
To adapt this to another RDGen user/company, only replace the hardcoded app names:
If there is only one custom client, this can be simplified to:
The important part is that the app name must match the real
.appbundle name, because RustDesk macOS services are derived from it:This made it possible for us to switch cleanly between different RDGen-generated macOS clients without leaving old services running.
One final note: the script is currently written in Spanish because our team is Spanish-speaking. If this is useful for the project, I can later help adapt the messages and comments to English.
install.zip