Hola. Soy zm soft, que se registró como desarrollador el año pasado (finales de 2023) y empezó a lanzar aplicaciones. También planeamos lanzar una aplicación para desarrolladores para superar juntos el test cerrado mediante la cooperación entre desarrolladores, así que compruébalo si te interesa.
¿Han implementado compras dentro de la aplicación? Para los desarrolladores de apps, que los usuarios estén satisfechos y paguen por ello es lo máximo, y es el momento en que se ven recompensados los esfuerzos del desarrollo. En este artículo quiero escribir sobre cómo lograr eso.
Qué son las compras dentro de la aplicación
Como ya sabéis, las compras dentro de la aplicación se clasifican en dos tipos:
- Artículos consumibles
- Artículos de suscripción periódica
Ambos adoptan el enfoque de acceder a los artículos configurados previamente en Play Store a través de Google Play Billing Library, y se paga a Google una parte de los ingresos como comisión. Desde el punto de vista de la implementación, ambos son similares, pero los artículos de suscripción periódica tienen sus propias advertencias. Explicaré las advertencias basándome también en mi experiencia personal.
Configuración de Play Store
Registro de artículos
Primero, registra los artículos, ya que no se pueden mostrar sin registro. El precio, el nombre, etc., incluido si realmente usarás ese artículo, pueden cambiarse después, así que cualquier dato provisional está bien. Sin embargo, solo el ID no puede cambiarse, así que si estás pensando en usar artículos de prueba en producción después de modificarlos, es mejor registrarlos con IDs reutilizables como [product_1,2,3...] o [sub_1,2,3...]. El registro se puede hacer desde [Monetize], donde [In-app products] y [Subscriptions] corresponden a los artículos consumibles y de suscripción periódica respectivamente. Cada artículo se puede registrar con el botón [Create xx].

Básicamente, puedes seguir la pantalla de entrada, pero lo que me resultó confuso fue la configuración de precios para los artículos de suscripción periódica. Al principio no sabía cómo establecer precios para todas las regiones de una vez. Pensé que habría que ingresar cada región individualmente, pero se puede hacer en el siguiente orden: [Set prices] - [Country / region] - [Set price].

Al pulsar el botón, aparece el siguiente diálogo que permite configurar todo de una vez.

Registro de cuenta de prueba
A continuación, registra la cuenta de prueba. Si realizas una prueba de compra sin registrarla, se generará un pago real, así que presta atención. El registro se realiza registrando una lista de correo. Puedes hacerlo en la primera pantalla (pantalla del desarrollador) al iniciar sesión en Play Console a través de [Settings] - [License testing].

Al realizar el proceso de compra con un usuario registrado en la lista de correo, la información de pago se mostrará como "tarjeta de prueba", lo que permite realizar pruebas sin generar cargos reales.
Trabajo de implementación
La implementación en el lado de la aplicación requiere el siguiente trabajo:
- Importación de la biblioteca
- Conexión a la tienda y obtención de información de artículos
- Implementación de la pantalla de visualización de artículos
- Solicitud de compra
- Procesamiento al completar la compra
A continuación, explicaré cada uno en detalle.
Importación de la biblioteca
La importación de la biblioteca requiere lo siguiente:
- Modificación de build.gradle
- Modificación de android.manifest
Ejemplo de modificación de build.gradle:
dependencies {
implementation "com.android.billingclient:6.0.0"
}
Ejemplo de modificación del manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="com.android.vending.BILLING" />
<application
Por favor, consulta la documentación oficial para la versión, etc.
Conexión a la tienda y obtención de información de artículos
Inicializando BillingClient y ejecutando startConnection se puede comunicar con la tienda. La información de cada artículo se puede obtener con queryProductDetailsAsync. Para más detalles, consulta la documentación oficial. En mi caso, por alguna razón la obtención masiva no funcionó bien, así que primero obtuve la lista de artículos y luego obtuve los detalles individualmente con queryProductDetailAsync. Se puede distinguir si el artículo (SKU) es consumible o de suscripción según si su tipo es inapp o subs.
Implementación de la pantalla de visualización de artículos
Una vez obtenida la información de los artículos, muéstrala en una lista para que se pueda seleccionar la compra. Al tratar artículos de suscripción periódica, es necesario cumplir con la Subscription Policy, y en mi caso las actualizaciones de la aplicación fueron rechazadas consecutivamente por las siguientes dos razones:
- Localización incompleta del precio y las condiciones
- Descripción incompleta de las condiciones de la oferta
Primero, sobre la localización incompleta: el motivo fue la visualización del período (ej.: $10/month). El problema es que la palabra "month" no estaba traducida cuando se ejecutaba con la configuración de región de un idioma no soportado. Al obtener información con BillingClient, el importe del precio se recupera como la cadena formattedPrice que incluye información de unidad, por lo que no es necesario traducirlo. Por otro lado, la información del período se notifica en formato ISO 8601 como P1M, y esto debe traducirse en la aplicación. Lo traté añadiendo procesos de conversión para cada idioma:
fun formatBillingPeriod(billingPeriod: String, languageCode: String): String {
return when(languageCode) {
"en" -> {
when (billingPeriod) {
"P1W" -> "weekly"
"P1M" -> "monthly"
"P3M" -> "every 3 months"
"P6M" -> "every 6 months"
"P1Y" -> "annually"
else -> "unknown"
}
}
"ja" -> {
when (billingPeriod) {
"P1W" -> "週間"
"P1M" -> "月額"
"P3M" -> "3ヶ月ごと"
"P6M" -> "6ヶ月ごと"
"P1Y" -> "年額"
else -> "不明"
}
}
"fr" -> {
when (billingPeriod) {
"P1W" -> "hebdomadaire"
"P1M" -> "mensuel"
"P3M" -> "tous les 3 mois"
"P6M" -> "tous les 6 mois"
"P1Y" -> "annuel"
else -> "inconnu"
}
}
"es" -> {
when (billingPeriod) {
"P1W" -> "semanal"
"P1M" -> "mensual"
"P3M" -> "cada 3 meses"
"P6M" -> "cada 6 meses"
"P1Y" -> "anual"
else -> "desconocido"
}
}
"de" -> {
when (billingPeriod) {
"P1W" -> "wöchentlich"
"P1M" -> "monatlich"
"P3M" -> "alle 3 Monate"
"P6M" -> "alle 6 Monate"
"P1Y" -> "jährlich"
else -> "unbekannt"
}
}
else -> "unknown"
}
}
A continuación, sobre la descripción incompleta de las condiciones de la oferta:

Entendí el problema, pero no sabía exactamente qué texto concreto debía escribir para resolverlo. A continuación se muestra un extracto del correo electrónico original de rechazo que recibí:
Issue found: Violation of Subscriptions policy
Your app does not comply with the Subscriptions policy.
- Your offer does not clearly and accurately describe the terms of your trial offer or introductory pricing, including when a free trial will convert to a paid subscription, how much the paid subscription will cost, and that a user can cancel if they do not want to convert to a paid subscription.
Como solución, tomé prestado texto de otras aplicaciones. Como parece ser texto estándar en su mayor parte, pensé que era mejor seguir precedentes probados que pensar desde cero.
Solicitud de compra
Una vez que el usuario puede seleccionar un artículo desde la pantalla, finalmente llega el procesamiento de compra. Ejecutando el flujo de compra para el artículo obtenido, se puede invocar la pantalla de compra real.
Pruebas
Las pruebas se pueden realizar sin incurrir en cargos reales iniciando sesión con la cuenta de prueba preparada al principio. Los dos puntos de atención son:
- La ejecución del flujo de compra se realiza con la aplicación registrada en la tienda
- Para los artículos de suscripción periódica, el período se establece de forma personalizada
En cuanto a la ejecución del flujo de compra, si la aplicación es una compilación de depuración, aparecerá un error en la pantalla de compra y no se podrá ejecutar el flujo.
En cuanto a los artículos de suscripción periódica, al avanzar a la pantalla de compra real, se muestra el pago con tarjeta de prueba. En ese momento se muestra el período de renovación en la pantalla, pero este período mostrado es diferente al período realmente configurado en el artículo. En mi caso se mostraban 5 minutos. Parece que es una especificación en la que se muestra un período fijo extremadamente corto para el comportamiento de renovación de la suscripción. (Pensé que había configurado algo mal y estuve revisando los ajustes por un tiempo.)
Conclusión
Al principio parece difícil, pero una vez que se comprende la imagen general, las compras dentro de la aplicación se pueden implementar sorprendentemente fácilmente consultando la información pública como la documentación oficial. Sin embargo, para las suscripciones periódicas, hay trampas que no se pueden descubrir hasta que se prueban, así que espero que los puntos en los que tropecé sirvan de referencia para los desarrolladores que las implementen en el futuro.