Docs

A biblioteca

Mostradores e campos de dados

Um mostrador não recebe pressionamentos de botão nem acessa a rede na tela. Por isso a biblioteca consulta nosso servidor em segundo plano, seu mostrador desenha o QR code onde você escolher, e a notificação de login da Garmin permite ao comprador pagar sem escanear. Campos de dados funcionam do mesmo jeito.

Como funciona

  • O segundo plano consulta. O serviço em segundo plano do mostrador envia ao nosso servidor a mesma requisição que um app envia, no horário que o servidor indicou.
  • A hora fica por cima. Num mostrador, ver a hora é um recurso principal, e a Garmin recomenda não colocar paywall sobre ela. Enquanto bloqueado, seu mostrador desenha o QR code onde você escolher. Um campo de dados o desenha no próprio espaço.
  • O link fica nas configurações. O mostrador também grava seu link de compra nas configurações, que o app Connect IQ do celular mostra. O comprador pode abri-lo ali sem escanear.
  • A notificação dispensa o escaneamento. Quando o mostrador está bloqueado e o celular conectado, ele envia a notificação de login da Garmin. O comprador toca nela, paga, e o mostrador desbloqueia em segundos.

Adicione a um mostrador ou campo de dados

Mostradores e campos de dados usam só lib/watch/face: PayFace.mc e 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>

A config é anotada com (:background), já que o segundo plano a lê. Mantenha TRIAL_DAYS nela, e defina como 0 para não ter teste: a parte do mostrador o lê diretamente.

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;
}

Os hooks

OndeChamada
getInitialView()Paywall.startTrial(); Paywall.schedule(false); a cada início
getServiceDelegate()return [new PayBg()];
onBackgroundData(data)Paywall.take(data);
onSettingsChanged()Paywall.soon();
onUpdate(dc)if (!Paywall.unlocked()) { Paywall.drawQr(dc, x, y, side); }

Um mostrador completo, com a hora em cima e o código abaixo enquanto bloqueado:

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);
        }
    }
}

Adicione uma propriedade unlock somente leitura. O mostrador a preenche com o link de compra da resposta do servidor. Defina a string UnlockTitle nos seus próprios 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>

Desenhar o código

  • Paywall.drawQr(dc, x, y, side) desenha o código com side de largura num quadrado branco, centrado em x, y. Antes da primeira resposta, não desenha nada.
  • Chame só enquanto !Paywall.unlocked().
  • Desenhe só com a tela totalmente ligada, nunca no modo sempre ativo de um relógio AMOLED.

Notificação de login da Garmin

  • Quando é enviada: uma vez, na primeira verificação que encontra o mostrador bloqueado (teste encerrado, ou sem teste). De novo cada vez que o comprador salva as configurações do mostrador enquanto ele está bloqueado. Só com o celular conectado: precisa do próprio celular, não do Wi-Fi.
  • O que o comprador vê: a própria notificação da Garmin no celular. A Garmin escreve o texto ("<app> needs you to sign in"), e nenhum app pode mudá-lo. Tocar nela abre sua página de pagamento no navegador do próprio Garmin Connect.
  • Depois do pagamento: a página termina, o celular passa o resultado ao relógio e o segundo plano do mostrador consulta nosso servidor. O resultado sozinho não desbloqueia nada, já que qualquer um poderia digitar o endereço. Só a resposta do nosso servidor desbloqueia.
  • Nunca enviada duas vezes por engano: o próprio segundo plano a marca como enviada (CIQ 3.2 ou mais recente), mesmo que o mostrador não rode logo depois. Num relógio que não pode enviá-la, o QR code e o link das configurações continuam funcionando.

Apps não a enviam. A tela de compra de um app já desbloqueia cerca de um segundo após o pagamento.

Quanto tempo um desbloqueio leva

Nosso servidor não consegue alcançar um relógio. Um mostrador só fica sabendo de um pagamento na próxima verificação, e a Garmin permite uma verificação em segundo plano no máximo a cada 5 minutos.

Como o comprador pagouO mostrador desbloqueia
Tocou na notificação de loginEm segundos
Escaneou o código ou usou o link das configurações, nos 2 dias após a instalação ou o fim do testeEm até 10 minutos
O mesmo, mais tardeEm até uma hora
Salvou as configurações do mostrador no celular após pagarNuma verificação assim que a Garmin permitir: no mínimo 5 minutos após a anterior
  • Quando uma verificação vê que o checkout foi aberto, o mostrador verifica a cada 5 minutos por meia hora.
  • Durante o teste, o mostrador verifica no fim do teste, ou diariamente se isso vier antes.
  • Após uma verificação com falha (sem celular), a próxima é uma hora depois.

Anotações e escopo

Código de glance e de segundo plano só alcança código anotado para eles. Mantenha as anotações da biblioteca como vêm e alinhe as suas.

  • Mostradores e campos de dados: PaywallConfig é (:background), e sua classe AppBase também, como no exemplo: o getServiceDelegate() dela roda em segundo plano. PayBg e PayFaceScope.mc já estão anotados.
  • Apps com glance: glance/PayScope.mc e PaywallConfig são (:glance). Um glance pode chamar Paywall.active(), Paywall.unlocked() e Paywall.trialLeft(), nada mais.
  • Apps com serviço próprio em segundo plano: glance-bg/PayScope.mc, PaywallConfig como (:glance, :background) e a permissão Background.
  • Só no app: tudo em Pay.mc, incluindo Paywall.open(), a tela de compra e suas strings. Nunca chame a partir de um glance ou de código em segundo plano.
Esc