Docs

La biblioteca

Esferas y campos de datos

Una esfera no puede recibir pulsaciones de botón ni usar la red en pantalla. Por eso la biblioteca consulta a nuestro servidor en segundo plano, tu esfera dibuja el código QR donde elijas, y la notificación de inicio de sesión de Garmin permite a un comprador pagar sin escanear. Los campos de datos funcionan igual.

Cómo funciona

  • El segundo plano consulta. El servicio en segundo plano de la esfera envía a nuestro servidor la misma petición que una app, a la hora que indicó el servidor.
  • La hora queda por encima. En una esfera, ver la hora es una función principal, y Garmin desaconseja poner un muro de pago sobre ella. Mientras está bloqueada, tu esfera dibuja el código QR donde elijas. Un campo de datos lo dibuja en su propio espacio.
  • El enlace está en los ajustes. La esfera también escribe su enlace de compra en sus ajustes, que muestra la app Connect IQ del teléfono. Un comprador puede abrirlo ahí sin escanear.
  • La notificación evita el escaneo. Cuando la esfera está bloqueada y el teléfono conectado, envía la notificación de inicio de sesión de Garmin. El comprador la toca, paga, y la esfera se desbloquea en segundos.

Añádela a una esfera o un campo de datos

Las esferas y los campos de datos usan solo lib/watch/face: PayFace.mc y PayFaceScope.mc.

monkey.jungle
base.sourcePath = source;../wearcheckout/lib/watch/face
manifest.xml
<iq:permissions>
    <iq:uses-permission id="Background"/>
    <iq:uses-permission id="Communications"/>
</iq:permissions>

La configuración lleva la anotación (:background), porque la lee el segundo plano. Mantén TRIAL_DAYS en ella, y ponlo a 0 si no hay prueba: la parte de la esfera lo lee directamente.

source/PaywallConfig.mc
// PaywallConfig.mc: from your dashboard (Trail Face). Public, not a secret.
import Toybox.Lang;

(:background)
module PaywallConfig {
    const URL = "https://pay.example/api/K7Q2/c";   // your app's address
    const TRIAL_DAYS = 7;
}

Los hooks

DóndeLlamada
getInitialView()Paywall.startTrial(); Paywall.schedule(false); en cada inicio
getServiceDelegate()return [new PayBg()];
onBackgroundData(data)Paywall.take(data);
onSettingsChanged()Paywall.soon();
onUpdate(dc)if (!Paywall.unlocked()) { Paywall.drawQr(dc, x, y, side); }

Una esfera completa, con la hora arriba y el código debajo mientras está bloqueada:

source/PayFaceApp.mc
import Toybox.Application;
import Toybox.Background;
import Toybox.Graphics;
import Toybox.Lang;
import Toybox.System;
import Toybox.Time;
import Toybox.WatchUi;

// A small face for measuring: the time, and the QR code under it while locked.
(:background)
class PayFaceApp extends Application.AppBase {
    function initialize() {
        AppBase.initialize();
    }

    function onStart(state as Dictionary or Null) as Void {
    }

    function getInitialView() {
        Paywall.startTrial();
        Paywall.schedule(false);
        return [new PayFaceView()];
    }

    function getServiceDelegate() {
        return [new PayBg()];
    }

    function onBackgroundData(data) as Void {
        Paywall.take(data);
    }

    // Saving the face's settings on the phone (the buy page suggests it after paying): ask now
    // (5 minutes after the last check at the soonest, Garmin's rule).
    function onSettingsChanged() as Void {
        Paywall.soon();
    }
}

class PayFaceView extends WatchUi.WatchFace {
    function initialize() {
        WatchFace.initialize();
    }

    function onUpdate(dc as Graphics.Dc) as Void {
        var w = dc.getWidth();
        var h = dc.getHeight();
        var t = System.getClockTime();
        dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
        dc.clear();
        dc.drawText(w / 2, h * 30 / 100, Graphics.FONT_NUMBER_MEDIUM, t.hour.format("%02d") + ":" + t.min.format("%02d"),
            Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER);
        if (!Paywall.unlocked()) {
            Paywall.drawQr(dc, w / 2, h * 68 / 100, w * 36 / 100);
        }
    }
}

Añade una propiedad unlock de solo lectura. La esfera la rellena con el enlace de compra de la respuesta del servidor. Define el texto UnlockTitle en tus propios recursos.

resources/settings/settings.xml
<resources>
    <!-- The buy link, written by the face from the server's answer: the phone's Connect IQ app
         shows it in this face's settings, so a buyer can open it without scanning. -->
    <properties>
        <property id="unlock" type="string"></property>
    </properties>
    <settings>
        <setting propertyKey="@Properties.unlock" title="@Strings.UnlockTitle">
            <settingConfig type="alphaNumeric" readonly="true"/>
        </setting>
    </settings>
</resources>

Dibujar el código

  • Paywall.drawQr(dc, x, y, side) dibuja el código de side de ancho sobre un cuadrado blanco, centrado en x, y. Antes de la primera respuesta no dibuja nada.
  • Llámala solo mientras !Paywall.unlocked().
  • Dibújalo solo con la pantalla totalmente encendida, nunca en el modo siempre activo de un reloj AMOLED.

La notificación de inicio de sesión de Garmin

  • Cuándo se envía: una vez, la primera vez que una consulta encuentra la esfera bloqueada (prueba terminada o sin prueba). Otra vez cada vez que el comprador guarda los ajustes de la esfera mientras está bloqueada. Solo con el teléfono conectado: necesita el propio teléfono, no el Wi-Fi.
  • Lo que ve el comprador: la propia notificación de Garmin en el teléfono. Garmin escribe su texto ("<app> needs you to sign in") y ninguna app puede cambiarlo. Al tocarla se abre tu página de pago en el navegador de Garmin Connect.
  • Tras pagar: la página termina, el teléfono pasa el resultado al reloj y la parte en segundo plano de la esfera consulta a nuestro servidor. El resultado por sí solo no desbloquea nada, porque cualquiera podría escribir su dirección. Solo desbloquea la respuesta de nuestro servidor.
  • Nunca se envía dos veces por error: la parte en segundo plano la marca como enviada por sí misma (CIQ 3.2 o posterior), aunque la esfera no se ejecute poco después. En un reloj que no puede enviarla, el código QR y el enlace de los ajustes siguen funcionando.

Las apps no la envían. La pantalla de compra de una app ya se desbloquea un segundo después de pagar, más o menos.

Cuánto tarda un desbloqueo

Nuestro servidor no puede contactar con un reloj. Una esfera se entera de un pago solo en su siguiente consulta, y Garmin permite una consulta en segundo plano como mucho cada 5 minutos.

Cómo pagó el compradorLa esfera se desbloquea
Tocó la notificación de inicio de sesiónEn segundos
Escaneó el código o usó el enlace de los ajustes, en los 2 días tras la instalación o el fin de la pruebaEn menos de 10 minutos
Lo mismo, más tardeEn menos de una hora
Guardó los ajustes de la esfera en el teléfono tras pagarEn una consulta en cuanto Garmin lo permite: como pronto 5 minutos después de la anterior
  • Cuando una consulta ha visto la página de pago abierta, la esfera consulta cada 5 minutos durante media hora.
  • Durante la prueba, la esfera consulta al final de la prueba, o a diario si eso llega antes.
  • Tras una consulta fallida (sin teléfono), la siguiente es una hora después.

Anotaciones y ámbito

El código de glance y de segundo plano solo puede acceder al código anotado para ellos. Deja las anotaciones de la biblioteca tal como vienen y ajusta las tuyas.

  • Esferas y campos de datos: PaywallConfig es (:background), y también tu clase AppBase, como en el ejemplo: su getServiceDelegate() se ejecuta en segundo plano. PayBg y PayFaceScope.mc ya tienen la anotación.
  • Apps con glance: glance/PayScope.mc y PaywallConfig son (:glance). Un glance puede llamar a Paywall.active(), Paywall.unlocked() y Paywall.trialLeft(), nada más.
  • Apps con su propio servicio en segundo plano: glance-bg/PayScope.mc, PaywallConfig como (:glance, :background), y el permiso Background.
  • Solo en la app: todo lo de Pay.mc, incluidos Paywall.open() y la pantalla de compra con sus textos. Nunca lo llames desde un glance ni desde código en segundo plano.
Esc