Un rechazo de App Store, una trampa de MusicKit, y un trabajo que creí haber perdido
Deep Cut Atlas recibió su primer rechazo de App Store esta semana, y se convirtió en una lección de dos partes: una sobre la superficie de API de MusicKit, y otra sobre mi propia higiene con git.
El rechazo
El revisor de Apple se topó con dos errores. Primero, tanto History como Discover mostraban el texto crudo “Privacy acknowledgement required” en vez de cualquier interfaz real. Segundo, tocar “Enable lifetime Pro” en Settings lanzaba una alerta de error.
La causa raíz del primer error es una distinción en la que no había pensado lo suficiente: el estado de autorización de MusicKit solo indica si el usuario le dio permiso a la app para tocar su biblioteca. No dice nada sobre si su cuenta en realidad tiene una suscripción activa de Apple Music. Mi app validaba solo por autorización y se detenía ahí, así que un revisor que concedió acceso pero no tenía suscripción pasaba directo por esa puerta y después se topaba con un error crudo de MusicKit en la siguientísima solicitud. La solución es una segunda verificación, separada, vía MusicSubscription.current, con su propia pantalla dedicada en vez de tres pestañas mostrando cada una su propia versión del mismo problema de fondo.
El segundo error era más simple: el botón de desbloqueo Pro seguía siendo tocable incluso cuando el producto de compra dentro de la app todavía no había cargado, así que un producto nil significaba una alerta de error inevitable al tocarlo. Solución directa, ocultar el botón hasta que el producto esté realmente ahí.
Acertar con el tipo de error correcto
El texto de error específico que vio el revisor de Apple (“Privacy acknowledgement required”) viene de un caso de error real de Swift, pero adivinar su tipo exacto de memoria fue mala idea. Estaba bastante seguro de que vivía en MusicSubscription.Error, que resulta no ser un tipo real en absoluto, o al menos no uno que pude encontrar documentado. Después de un par de búsquedas confirmé que el tipo real es MusicTokenRequestError.privacyAcknowledgementRequired. Valieron la pena los cinco minutos extra: lanzar una cláusula catch que coincide con un caso que no existe significa que nunca se dispara, en silencio, y no arreglaste nada.
La parte donde creí que el trabajo se había perdido
Esta es la parte de la que estoy menos orgulloso. Una sesión de trabajo anterior aparentemente ya había construido esta misma solución, “completa, verificada en el simulador,” dejada como una nota sin confirmar en el ticket de seguimiento. Cuando volví a retomar el trabajo, busqué con grep en todo el código y en cada rama las clases que describía ese comentario. Nada. Concluí que el trabajo estaba perdido, cambios sin confirmar que nunca se guardaron antes de cambiar de rama, y reconstruí todo desde las notas del ticket.
No estaba perdido. Estaba guardado en git stash, algo que nunca se me ocurrió revisar. Un stash no aparece en git branch, no aparece en git log, y un grep sobre el árbol de trabajo tampoco puede verlo, así que mi búsqueda tenía un punto ciego real que no conocía, hasta que me topé con él más tarde, haciendo una limpieza de ramas sin relación.
El lado positivo: al comparar las dos versiones con diff, mi reconstrucción detectó un error real que tenía la original, ese tipo MusicSubscription.Error incorrecto. Así que el trabajo redundante no fue en vano. Pero “irrecuperable” fue una afirmación que hice con más confianza de la que en realidad me había ganado, y quiero recordar eso la próxima vez que algo parezca perdido.
Qué sigue
La solución de código está terminada, probada, y fusionada. Lo que queda depende enteramente de mí: confirmar en App Store Connect que la compra dentro de la app en verdad está adjunta al envío de la versión (probablemente todo el segundo error), después subir el número de build y reenviar.
Lecturas relacionadas
Construir un prompt de calificación que estaba seguro de que no se renderizaría en el simulador
Un umbral de tres logros, una llamada a requestReview(), y una creencia recibida sobre el comportamiento del simulador que resultó ser falsa al probarla de verdad.
La lista de reproducción que ya tenía el nombre correcto
Un artefacto del cambio de nombre, una API sin campo de autor, y una prueba en dispositivo que mostró que el error ya se había arreglado solo, cerrado así.
Álbumes destacados, datos reales de MusicKit y una prueba que mintió al pasar
No existe un flag isEssential: Essentials es solo una playlist. featuredAlbums es la señal real, y un fixture cambiado expuso un test sin re-ejecutar.
También te podría ser útil
NordPass
Gestor de contraseñas del equipo detrás de NordVPN, con un plan gratuito.
Como afiliado de NordPass, obtengo ingresos por las compras que califican.
Más informaciónAdGuard para iOS
Bloqueo de anuncios y rastreadores en todo el sistema en iOS, sin necesidad de un servidor DNS aparte.
Como afiliado de AdGuard, obtengo ingresos por las compras que califican.
Más informaciónProton Drive
Almacenamiento en la nube cifrado, del equipo detrás de Proton Mail.
Como socio de Proton, obtengo ingresos por las compras que califican de los servicios de privacidad y seguridad de Proton (Pass, Mail, VPN, Drive).
Más información