Construir un prompt de calificación que estaba seguro de que no se renderizaría en el simulador
Deep Cut Atlas necesitaba un prompt de calificación de App Store en algún punto, y la regla obvia es: pedirlo después de un logro genuino, no al abrir la app. Elegí “tres álbumes agregados con éxito” como señal, suficiente para significar que la app realmente cumplió su función al menos una vez, y no tanto como para que el pedido se sienta insistente.
La lógica de activación en sí no tiene nada de particular: un contador en SettingsStore, incrementado en cada adición exitosa a través de las tres pestañas que pueden dispararlo (Discover, History, y las sugerencias “More from artist” de Playlist), una verificación de umbral, y una bandera por versión de la app para que se dispare una sola vez hasta el siguiente cambio de versión. El @Environment(\.requestReview) nativo de SwiftUI se encarga de la hoja del sistema en sí, no hace falta construir ninguna interfaz para esto, basta con llamarlo en el momento indicado.
Antes de empezar, asumí que tendría que simular toda la verificación: SKStoreReviewController y su wrapper de SwiftUI son conocidos por ser poco confiables para activarse incluso en un dispositivo real, limitados por el propio límite anual por app de Apple, y había leído más de una vez que no hace absolutamente nada en el simulador. Esperaba verificar la lógica de activación con pruebas unitarias y simplemente confiar en la única línea que llama a requestReview().
Se renderizó de todos modos. Tres adiciones reales a través de la interfaz del simulador, y apareció la hoja real de calificación del sistema, al primer intento, sin necesitar ningún entitlement especial ni bandera de depuración. No era lo que esperaba al empezar, y cambió la forma de verificar el resto de la función, en vez de confiar ciegamente en la llamada, pude capturar la hoja real, confirmar que no había un nuevo aviso al reabrir la app ni con una cuarta adición, y tratar todo el flujo como algo realmente comprobado en vez de “probablemente esté bien.”
La prueba en dispositivo real que siguió fue en gran parte una formalidad a esa altura: capacidad de respuesta al tocar los botones de agregar, sin cuelgues, mismo comportamiento que en el simulador. El hallazgo interesante acá no fue la función en sí, sino que una creencia recibida sobre cómo se comporta esta API en las herramientas de desarrollo resultó ser falsa, y habría publicado con una verificación más débil de no haberlo probado directamente.
Lecturas relacionadas
Un rechazo de App Store, una trampa de MusicKit, y un trabajo que creí haber perdido
Autorización no es lo mismo que suscripción, un tipo de error que no existe, y una solución ya terminada escondida en git stash mientras yo la reconstruía a partir de notas.
Lanzar Deep Cut Atlas: qué se rompió durante mi primer envío a la App Store
Un consumible que debía ser no consumible, un ID de producto que nunca se puede reutilizar, un archivo que en silencio no se reconstruyó, y un cambio de nombre con una mecha de dos semanas.
Una sección de tracklist, y por qué tomó 30 minutos
Un método de protocolo, un enum de estado reutilizado, una convención de enrutamiento que se mantuvo, y un límite de lint que forzó una división que valía la pena hacer de todos modos.
También te podría ser útil
Proton VPN
VPN comercial con filtrado NetShield e interruptor de apagado automático.
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óneSIM Airalo
eSIM de datos local para viajes - sin necesidad de cambiar una SIM física.
Este es mi enlace de referido de Airalo. Obtienes un descuento en tu primer eSIM y yo obtengo crédito de Airalo para el mío.
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ón