enable-game-mode.sh
· 3.6 KiB · Bash
Raw
#!/usr/bin/env bash
set -euo pipefail
# enable-game-mode.sh
# Añade LSApplicationCategoryType=public.app-category.games y LSSupportsGameMode=true
# al Info.plist de una app .app y re-firma el bundle ad-hoc para uso local.
#
# Uso:
# ./enable-game-mode.sh "/ruta/a/Application.app" [--category public.app-category.games] [--no-quarantine] [--no-deep]
#
# Ejemplo:
# ./enable-game-mode.sh "/Applications/Application.app"
CATEGORY="public.app-category.games"
REMOVE_QUARANTINE=1
USE_DEEP=1
APP=""
die() {
echo "Error: $*" >&2
exit 1
}
usage() {
cat <<EOF
Uso: $(basename "$0") "/ruta/a/App.app" [opciones]
Opciones:
--category <id> Cambia la categoría (por defecto: public.app-category.games)
--no-quarantine No elimina atributos de cuarentena
--no-deep Firma sin --deep (no recomendado)
Ejemplo:
$(basename "$0") "/Applications/Application.app"
EOF
}
# Parseo simple de argumentos
while [[ $# -gt 0 ]]; do
case "$1" in
--category)
[[ $# -ge 2 ]] || die "--category requiere un valor"
CATEGORY="$2"
shift 2
;;
--no-quarantine)
REMOVE_QUARANTINE=0
shift
;;
--no-deep)
USE_DEEP=0
shift
;;
-h|--help)
usage
exit 0
;;
-*)
die "Opción desconocida: $1"
;;
*)
if [[ -z "${APP}" ]]; then
APP="$1"
shift
else
die "Argumento inesperado: $1"
fi
;;
esac
done
[[ -n "${APP}" ]] || { usage; exit 1; }
# Resolver ruta absoluta sin realpath
APP_DIR="$(cd "$(dirname "$APP")" && pwd)"
APP_NAME="$(basename "$APP")"
APP_PATH="${APP_DIR}/${APP_NAME}"
[[ -d "${APP_PATH}" && "${APP_PATH}" == *.app ]] || die "No parece un bundle .app válido: ${APP_PATH}"
INFO_PLIST="${APP_PATH}/Contents/Info.plist"
[[ -f "${INFO_PLIST}" ]] || die "No se encontró Info.plist en: ${INFO_PLIST}"
# Comprobaciones de herramientas
command -v plutil >/dev/null 2>&1 || die "plutil no encontrado"
command -v codesign >/dev/null 2>&1 || die "codesign no encontrado"
command -v xattr >/dev/null 2>&1 || echo "Aviso: xattr no encontrado; omitiendo cuarentena" >&2
command -v spctl >/dev/null 2>&1 || true
# Copia de seguridad
TS="$(date +%Y%m%d-%H%M%S)"
BACKUP_PATH="${APP_PATH%.app}.backup-${TS}.app"
echo "→ Creando copia de seguridad en: ${BACKUP_PATH}"
cp -R "${APP_PATH}" "${BACKUP_PATH}"
# (Opcional) Eliminar cuarentena
if [[ "${REMOVE_QUARANTINE}" -eq 1 ]] && command -v xattr >/dev/null 2>&1; then
echo "→ Eliminando cuarentena (si existe)"
xattr -dr com.apple.quarantine "${APP_PATH}" || true
fi
# Editar Info.plist
echo "→ Estableciendo LSApplicationCategoryType='${CATEGORY}'"
plutil -replace LSApplicationCategoryType -string "${CATEGORY}" "${INFO_PLIST}"
echo "→ Estableciendo LSSupportsGameMode=true"
plutil -replace LSSupportsGameMode -bool true "${INFO_PLIST}"
# Mostrar valores para confirmar
echo "→ Claves establecidas:"
plutil -p "${INFO_PLIST}" | grep -E "LSApplicationCategoryType|LSSupportsGameMode" || true
# Re-firmar (ad-hoc)
echo "→ Re-firmando bundle (ad-hoc)"
if [[ "${USE_DEEP}" -eq 1 ]]; then
codesign -f -s - --deep --preserve-metadata=entitlements,requirements,flags "${APP_PATH}"
else
codesign -f -s - --preserve-metadata=entitlements,requirements,flags "${APP_PATH}"
fi
# Verificaciones (best-effort)
echo "→ Verificando firma y política de ejecución"
codesign -dv --verbose=4 "${APP_PATH}" >/dev/null 2>&1 || true
spctl -a -vv "${APP_PATH}" || true
cat <<'DONE'
Listo ✅
- Abre la app y ponla a pantalla completa para activar Game Mode durante la sesión.
- Si algo falla, restaura la copia de seguridad creada junto al original.
DONE
| 1 | #!/usr/bin/env bash |
| 2 | set -euo pipefail |
| 3 | |
| 4 | # enable-game-mode.sh |
| 5 | # Añade LSApplicationCategoryType=public.app-category.games y LSSupportsGameMode=true |
| 6 | # al Info.plist de una app .app y re-firma el bundle ad-hoc para uso local. |
| 7 | # |
| 8 | # Uso: |
| 9 | # ./enable-game-mode.sh "/ruta/a/Application.app" [--category public.app-category.games] [--no-quarantine] [--no-deep] |
| 10 | # |
| 11 | # Ejemplo: |
| 12 | # ./enable-game-mode.sh "/Applications/Application.app" |
| 13 | |
| 14 | CATEGORY="public.app-category.games" |
| 15 | REMOVE_QUARANTINE=1 |
| 16 | USE_DEEP=1 |
| 17 | |
| 18 | APP="" |
| 19 | |
| 20 | die() { |
| 21 | echo "Error: $*" >&2 |
| 22 | exit 1 |
| 23 | } |
| 24 | |
| 25 | usage() { |
| 26 | cat <<EOF |
| 27 | Uso: $(basename "$0") "/ruta/a/App.app" [opciones] |
| 28 | |
| 29 | Opciones: |
| 30 | --category <id> Cambia la categoría (por defecto: public.app-category.games) |
| 31 | --no-quarantine No elimina atributos de cuarentena |
| 32 | --no-deep Firma sin --deep (no recomendado) |
| 33 | |
| 34 | Ejemplo: |
| 35 | $(basename "$0") "/Applications/Application.app" |
| 36 | EOF |
| 37 | } |
| 38 | |
| 39 | # Parseo simple de argumentos |
| 40 | while [[ $# -gt 0 ]]; do |
| 41 | case "$1" in |
| 42 | --category) |
| 43 | [[ $# -ge 2 ]] || die "--category requiere un valor" |
| 44 | CATEGORY="$2" |
| 45 | shift 2 |
| 46 | ;; |
| 47 | --no-quarantine) |
| 48 | REMOVE_QUARANTINE=0 |
| 49 | shift |
| 50 | ;; |
| 51 | --no-deep) |
| 52 | USE_DEEP=0 |
| 53 | shift |
| 54 | ;; |
| 55 | -h|--help) |
| 56 | usage |
| 57 | exit 0 |
| 58 | ;; |
| 59 | -*) |
| 60 | die "Opción desconocida: $1" |
| 61 | ;; |
| 62 | *) |
| 63 | if [[ -z "${APP}" ]]; then |
| 64 | APP="$1" |
| 65 | shift |
| 66 | else |
| 67 | die "Argumento inesperado: $1" |
| 68 | fi |
| 69 | ;; |
| 70 | esac |
| 71 | done |
| 72 | |
| 73 | [[ -n "${APP}" ]] || { usage; exit 1; } |
| 74 | |
| 75 | # Resolver ruta absoluta sin realpath |
| 76 | APP_DIR="$(cd "$(dirname "$APP")" && pwd)" |
| 77 | APP_NAME="$(basename "$APP")" |
| 78 | APP_PATH="${APP_DIR}/${APP_NAME}" |
| 79 | |
| 80 | [[ -d "${APP_PATH}" && "${APP_PATH}" == *.app ]] || die "No parece un bundle .app válido: ${APP_PATH}" |
| 81 | |
| 82 | INFO_PLIST="${APP_PATH}/Contents/Info.plist" |
| 83 | [[ -f "${INFO_PLIST}" ]] || die "No se encontró Info.plist en: ${INFO_PLIST}" |
| 84 | |
| 85 | # Comprobaciones de herramientas |
| 86 | command -v plutil >/dev/null 2>&1 || die "plutil no encontrado" |
| 87 | command -v codesign >/dev/null 2>&1 || die "codesign no encontrado" |
| 88 | command -v xattr >/dev/null 2>&1 || echo "Aviso: xattr no encontrado; omitiendo cuarentena" >&2 |
| 89 | command -v spctl >/dev/null 2>&1 || true |
| 90 | |
| 91 | # Copia de seguridad |
| 92 | TS="$(date +%Y%m%d-%H%M%S)" |
| 93 | BACKUP_PATH="${APP_PATH%.app}.backup-${TS}.app" |
| 94 | echo "→ Creando copia de seguridad en: ${BACKUP_PATH}" |
| 95 | cp -R "${APP_PATH}" "${BACKUP_PATH}" |
| 96 | |
| 97 | # (Opcional) Eliminar cuarentena |
| 98 | if [[ "${REMOVE_QUARANTINE}" -eq 1 ]] && command -v xattr >/dev/null 2>&1; then |
| 99 | echo "→ Eliminando cuarentena (si existe)" |
| 100 | xattr -dr com.apple.quarantine "${APP_PATH}" || true |
| 101 | fi |
| 102 | |
| 103 | # Editar Info.plist |
| 104 | echo "→ Estableciendo LSApplicationCategoryType='${CATEGORY}'" |
| 105 | plutil -replace LSApplicationCategoryType -string "${CATEGORY}" "${INFO_PLIST}" |
| 106 | |
| 107 | echo "→ Estableciendo LSSupportsGameMode=true" |
| 108 | plutil -replace LSSupportsGameMode -bool true "${INFO_PLIST}" |
| 109 | |
| 110 | # Mostrar valores para confirmar |
| 111 | echo "→ Claves establecidas:" |
| 112 | plutil -p "${INFO_PLIST}" | grep -E "LSApplicationCategoryType|LSSupportsGameMode" || true |
| 113 | |
| 114 | # Re-firmar (ad-hoc) |
| 115 | echo "→ Re-firmando bundle (ad-hoc)" |
| 116 | if [[ "${USE_DEEP}" -eq 1 ]]; then |
| 117 | codesign -f -s - --deep --preserve-metadata=entitlements,requirements,flags "${APP_PATH}" |
| 118 | else |
| 119 | codesign -f -s - --preserve-metadata=entitlements,requirements,flags "${APP_PATH}" |
| 120 | fi |
| 121 | |
| 122 | # Verificaciones (best-effort) |
| 123 | echo "→ Verificando firma y política de ejecución" |
| 124 | codesign -dv --verbose=4 "${APP_PATH}" >/dev/null 2>&1 || true |
| 125 | spctl -a -vv "${APP_PATH}" || true |
| 126 | |
| 127 | cat <<'DONE' |
| 128 | |
| 129 | Listo ✅ |
| 130 | - Abre la app y ponla a pantalla completa para activar Game Mode durante la sesión. |
| 131 | - Si algo falla, restaura la copia de seguridad creada junto al original. |
| 132 | DONE |
| 133 |
macos-gamemode.md
· 2.3 KiB · Markdown
Raw
# Activar Game Mode en una app de macOS (edición local)
> **Resumen:** Vas a añadir dos claves al `Info.plist` para declarar la app como *Juegos* y marcarla como compatible con Game Mode, y después volver a firmarla ad‑hoc para que se ejecute localmente.
## Requisitos
- macOS Sonoma (14) o posterior.
- Terminal con permisos de administrador cuando sea necesario.
- Trabaja sobre **una copia** si no quieres modificar el original.
---
## Pasos rápidos
1) **(Opcional) Quitar cuarentena y/o hacer copia**
```bash
cp -R "/Applications/Application.app" ~/Desktop/
xattr -dr com.apple.quarantine ~/Desktop/Application.app # si la app está bloqueada
cd ~/Desktop
```
2) **Editar `Info.plist`**
```bash
plutil -replace LSApplicationCategoryType -string "public.app-category.games" "Application.app/Contents/Info.plist"
plutil -replace LSSupportsGameMode -bool true "Application.app/Contents/Info.plist"
```
3) **Re-firmar ad‑hoc (uso local)**
```bash
codesign -f -s - --deep --preserve-metadata=entitlements,requirements,flags "Application.app"
```
4) **Abrir a pantalla completa** → Game Mode se activa durante la sesión.
---
## Verificaciones útiles
```bash
# Comprobar claves
plutil -p "Application.app/Contents/Info.plist" | grep -E "LSApplicationCategoryType|LSSupportsGameMode"
# Ver firma y política de ejecución
codesign -dv --verbose=4 "Application.app"
spctl -a -vv "Application.app"
```
---
## Script automático
Si prefieres automatizar todo, usa el script: [`enable-game-mode.sh`](./h4ckx0r/macos-gamemode#file-enable-game-mode-sh).
**Uso básico:**
```bash
chmod +x enable-game-mode.sh
./enable-game-mode.sh "/Applications/Application.app"
```
**Flags opcionales:**
- `--category <id>` para cambiar la categoría (por defecto: `public.app-category.games`).
- `--no-quarantine` para no tocar atributos de cuarentena.
- `--no-deep` para firmar sin `--deep` (no recomendado salvo bundles simples).
---
## Notas y advertencias
- Cualquier cambio en el bundle invalida la firma original. Re‑firmar con `-s -` (ad‑hoc) es suficiente para uso local, **no** para distribución.
- Si vas a distribuir la app, firma con **Developer ID** y **notariza** para evitar bloqueos de Gatekeeper.
- Algunas apps pueden dejar de auto‑actualizarse tras modificar el bundle.
Activar Game Mode en una app de macOS (edición local)
Resumen: Vas a añadir dos claves al
Info.plistpara declarar la app como Juegos y marcarla como compatible con Game Mode, y después volver a firmarla ad‑hoc para que se ejecute localmente.
Requisitos
- macOS Sonoma (14) o posterior.
- Terminal con permisos de administrador cuando sea necesario.
- Trabaja sobre una copia si no quieres modificar el original.
Pasos rápidos
- (Opcional) Quitar cuarentena y/o hacer copia
cp -R "/Applications/Application.app" ~/Desktop/
xattr -dr com.apple.quarantine ~/Desktop/Application.app # si la app está bloqueada
cd ~/Desktop
- Editar
Info.plist
plutil -replace LSApplicationCategoryType -string "public.app-category.games" "Application.app/Contents/Info.plist"
plutil -replace LSSupportsGameMode -bool true "Application.app/Contents/Info.plist"
- Re-firmar ad‑hoc (uso local)
codesign -f -s - --deep --preserve-metadata=entitlements,requirements,flags "Application.app"
- Abrir a pantalla completa → Game Mode se activa durante la sesión.
Verificaciones útiles
# Comprobar claves
plutil -p "Application.app/Contents/Info.plist" | grep -E "LSApplicationCategoryType|LSSupportsGameMode"
# Ver firma y política de ejecución
codesign -dv --verbose=4 "Application.app"
spctl -a -vv "Application.app"
Script automático
Si prefieres automatizar todo, usa el script: enable-game-mode.sh.
Uso básico:
chmod +x enable-game-mode.sh
./enable-game-mode.sh "/Applications/Application.app"
Flags opcionales:
--category <id>para cambiar la categoría (por defecto:public.app-category.games).--no-quarantinepara no tocar atributos de cuarentena.--no-deeppara firmar sin--deep(no recomendado salvo bundles simples).
Notas y advertencias
- Cualquier cambio en el bundle invalida la firma original. Re‑firmar con
-s -(ad‑hoc) es suficiente para uso local, no para distribución. - Si vas a distribuir la app, firma con Developer ID y notariza para evitar bloqueos de Gatekeeper.
- Algunas apps pueden dejar de auto‑actualizarse tras modificar el bundle.