Steven
Steven6 min de lectura

Tu app de Mac concede acceso al micrófono — y lo olvida en cada arranque

GeekBye pidió permiso de micrófono, se lo diste y funcionó. Al siguiente arranque: desaparecido. Y la app nunca llegaba a aparecer en Configuración del Sistema → Micrófono. La culpable era una función de seguridad de macOS ejecutando la app en silencio desde una ruta que se esfuma — aquí tienes el diagnóstico y el arreglo de un solo aviso.

macOS
Permisos
Ingeniería
Lanzamientos de GeekBye
Tu app de Mac concede acceso al micrófono — y lo olvida en cada arranque

Este es un fallo que te hace dudar de tus propios ojos. Instalas GeekBye, pide acceso al micrófono, haces clic en Permitir y la transcripción funciona. Perfecto. Cierras, lo reabres a la mañana siguiente — y te pide acceso al micrófono otra vez. Vas a comprobar Configuración del Sistema → Privacidad y seguridad → Micrófono para arreglarlo a mano, y GeekBye ni siquiera está en la lista. Ni denegado. Ni permitido. Simplemente ausente, como si nunca lo hubiera pedido.

Cada pieza por separado parecía correcta. El aviso era real. El permiso funcionaba en el momento. La app estaba correctamente firmada y notarizada, con las cadenas de uso adecuadas. Y aun así el permiso se evaporaba en cada arranque. GeekBye v2.0.6 lo corrigió — y la causa raíz es una de las cosas más taimadas que hace macOS para protegerte.

La función que escondía la app de sí misma

La culpable es App Translocation de macOS, una función de seguridad de Gatekeeper. Cuando descargas una app y la ejecutas directamente desde el DMG o desde tu carpeta ~/Downloads — en cualquier sitio donde siga estando "en cuarentena" — macOS no la ejecuta realmente desde donde tú la ves. La copia de forma transparente a una ruta aleatoria y de solo lectura enterrada bajo /private/var/folders/.../AppTranslocation/… y ejecuta esa copia. Es una buena defensa: impide que una descarga maliciosa manipule los archivos que tiene al lado.

Pero aquí está la colisión. El sistema de permisos de macOS (TCC — lo que lleva la cuenta de quién puede usar tu micrófono, cámara, pantalla) identifica una app por su ruta y su identidad de código. Cuando la app está translocada, esa ruta es aleatoria y temporal. Así que cuando concedes acceso al micrófono, macOS registra fielmente el permiso — contra una ruta que no existirá en el siguiente arranque. Reabres la app, macOS la transloca a una ruta aleatoria distinta, ve una app de la que no tiene registro alguno, y vuelve a preguntar. Y como esa ruta fantasma nunca es una ubicación estable, la app jamás se gana una fila permanente en Configuración del Sistema → Micrófono.

La app le estaba concediendo permiso a un fantasma.

Por eso también solo lo sufrían algunos. Si tu copia de GeekBye ya vivía en /Applications — porque la arrastraste ahí, o porque llegó ahí vía autoactualización — no hay cuarentena, ni translocación, la ruta es estable y todo persiste a la perfección. El fallo era invisible para nosotros y para cualquiera que hubiera pasado de su primera instalación, que es exactamente el tipo de fallo que sobrevive más tiempo.

El arreglo: darle a la app un hogar de verdad

Como el problema entero es una ruta inestable, el arreglo consiste en llevar la app a una estable. La v2.0.6 detecta cuándo GeekBye se está ejecutando translocada (o simplemente ejecutándose fuera de /Applications) y ofrece un "Mover a Aplicaciones" de un clic — usando la llamada de reubicación de macOS que copia el paquete a /Applications y lo relanza desde ahí. A partir de ese momento la app tiene una identidad fija: el permiso de micrófono se mantiene, la grabación de pantalla se mantiene, y GeekBye por fin aparece en Configuración del Sistema donde uno lo esperaría.

El aviso es educado al respecto. Ofrece Mover a Aplicaciones, Ahora no y No volver a preguntar — y recuerda la última elección, para que la app nunca dé la lata a alguien que tenga una razón deliberada para ejecutarla desde otro sitio. La decisión de si siquiera mostrar el aviso está aislada en funciones pequeñas y puras (¿esta compilación está translocada? ¿está fuera de /Applications? ¿el usuario la silenció?) para que la lógica se pruebe con tests unitarios sin necesidad de lanzar una compilación notarizada real en un volumen en cuarentena real.

El mismo lanzamiento también simplificó la propia experiencia de permisos. GeekBye solía abrir una ventana de permisos personalizada y a medida — unos cientos de líneas de interfaz tratando de reproducir algo que el sistema operativo ya hace bien. La v2.0.6 la eliminó y se apoyó en el aviso de permisos nativo de macOS, respaldado por un banner discreto y no bloqueante que aparece solo cuando falta de verdad un permiso requerido. Menos código, y un comportamiento que los usuarios ya reconocen porque cualquier otra app de Mac funciona igual.

De lo que estoy más orgulloso: lo demostramos antes de creerlo

Habría sido fácil adivinar la translocación y lanzar un arreglo. En vez de eso, el lanzamiento envió primero un diagnóstico de arranque: al iniciarse, GeekBye ahora reporta su propia ruta de ejecutable y si está translocada, si está dentro de /Applications, y el estado actual de los permisos de micrófono y pantalla. Esa telemetría convirtió una teoría plausible en una confirmada — los datos de producción mostraron que las sesiones afectadas estaban, de hecho, ejecutándose desde rutas translocadas fuera de /Applications, exactamente como se predijo.

Ese orden importa. "El aviso aparece pero el permiso no se mantiene" tiene varias explicaciones posibles — un problema de firma, una cadena de uso que falta, un asunto de entitlements, una rareza de la base de datos de TCC. Descartamos las causas a nivel de API (la ruta de la petición era demostrablemente correcta), y luego dejamos que los datos del mundo real señalaran la capa de identidad/ruta en vez de lanzar un arreglo esperanzado y cruzar los dedos para que pararan los tickets de soporte.

Tres cosas que enseña este fallo

  1. Un permiso que se pide pero no persiste es un problema de identidad, no de API. Si el código de la petición es correcto y el permiso aun así se esfuma, deja de reescribir la petición. Pregúntate a qué ruta e identidad de código está atando el sistema operativo el permiso — y si esa identidad es estable entre arranques.
  2. Lanza el diagnóstico con (o antes de) el arreglo. Unos pocos campos — desde dónde estoy ejecutándome, cuál es mi estado de permisos — convirtieron una conjetura fundada en una causa raíz verificada y nos dijeron exactamente qué usuarios estaban afectados. Instrumenta la frontera que sospechas antes de parchearla.
  3. Los fallos que se esconden de los desarrolladores son los que corren en el entorno "equivocado". El nuestro vivía en /Applications en cada máquina de desarrollo, así que el fallo era estructuralmente invisible para nosotros mientras golpeaba a los usuarios primerizos. Cuando un reporte no se reproduce, la primera pregunta es qué es distinto en dónde se ejecuta, no si el usuario se equivoca.

GeekBye v2.0.6 lanzó el aviso de reubicación y el diagnóstico juntos. Para el arco de fiabilidad más amplio en el que encaja, mira lo que de verdad cuesta una versión 2 (v2.0.0) y por qué la grabación de pantalla captura el monitor equivocado (v2.0.10) — otro fallo que solo aparecía en un entorno concreto. Para el lanzamiento de pequeños detalles de al lado, software tranquilo: el arreglo del parpadeo y el chip de modo de respuesta (v2.0.3 + v2.0.5).

Artículos Relacionados

Distinguir una llamada de una app abierta
Steven
Steven10 min de lectura

Distinguir una llamada de una app abierta

GeekBye puede notar que te has unido a una reunión por video y ofrecerte grabarla. La detección resulta ser la mitad fácil — un binario Swift que lee títulos de ventana cada diez segundos. La mitad difícil es la precisión: no dispararse cuando Zoom está meramente abierto, no ofrecerte grabar una reunión que ya estás grabando, y no silenciar el micrófono en la llamada en la que realmente estás. Tres releases, y cada una es una salvaguarda que tuvo que aprender a no derrotarse a sí misma.

Ingeniería
macOS
Desktop
El silencio era estructural
Steven
Steven8 min de lectura

El silencio era estructural

Las dos últimas releases de GeekBye v1 giran en torno a la misma verdad incómoda: la transcripción en tiempo real sobre una red real no es sin pérdidas, y lo honesto es dejar de fingir que lo es. La v1.8.20 guardaba en disco una copia de cada chunk de audio antes de descartarlo durante una reconexión, y empezó a marcar en voz alta los huecos en la transcripción. La v1.9.0 dejó de enviar silencio para ahorrar ancho de banda — y descubrió que el silencio era justo la señal que el transcriptor usaba para saber que una frase había terminado. Dos releases sobre el coste de tirar cosas.

Ingeniería
Audio
Fiabilidad
Los tres verbos que mantienen vivo el Web Audio
Steven
Steven10 min de lectura

Los tres verbos que mantienen vivo el Web Audio

Dos releases puntuales de GeekBye, con dos meses de diferencia y en dos archivos distintos, le enseñaron a nuestro código de audio la misma lección desde extremos opuestos: dejar de tratar el AudioContext del navegador como desechable. Una release aprendió a hacer resume() de un contexto que macOS había suspendido silenciosamente a mitad de grabación; la otra aprendió a hacer suspend() en vez de close() para que las sesiones consecutivas dejen de estrellarse contra el techo de aproximadamente seis contextos de Chromium. Resume, suspend, close — ese es todo el argumento.

Ingeniería
Audio
Desktop