Como estender o aplicativo móvel offline do Consumer Goods Cloud para acionar aplicativos nativos de navegação, mensageria e telefonia através da API Facade.startThirdPartyAsync.

Na rotina diária no varejo, o representante de vendas ou promotor divide seu tempo entre pesquisas de gôndola, pedidos e o deslocamento entre pontos de venda (PDVs). Durante esse trajeto, abrir o navegador GPS para traçar a rota ou enviar uma mensagem no WhatsApp confirmando o recebimento de mercadorias com o gerente da loja são tarefas recorrentes.

Quando a aplicação móvel funciona isolada, o promotor precisa copiar o endereço manualmente, sair do aplicativo, colar os dados no Google Maps ou Waze e depois repetir o processo para encontrar o contato no mensageiro. Esse fluxo gera atrito e abre espaço para erros de digitação.

Para integrar a experiência em campo, o framework do Salesforce Consumer Goods Cloud (CGC) Modeler oferece o recurso de App2App Communication (comunicação entre aplicativos).

Por meio desse protocolo, a aplicação offline do Consumer Goods Cloud invoca esquemas de URL nativos (URI Schemes ou Intent URLs) registrados no Android e no iOS. Usando a API Facade.startThirdPartyAsync, é possível transferir parâmetros contextuais (como coordenadas geográficas e mensagens de texto) sem depender de conexão de internet e sem violar a integridade do banco SQLite local (app.db3).


1. Arquitetura do App2App: do clique ao handover do sistema operacional

A comunicação entre aplicativos no Modeler Mv2 ocorre por transferência de controle (handover) ao sistema operacional. Quando o usuário clica em um botão na interface do app, o runtime do Consumer Goods Cloud solicita ao sistema operacional a abertura do aplicativo cadastrado como padrão para aquele protocolo.

O fluxo de execução compreende quatro etapas:

  1. UserInterface (.userinterface.xml): Exibe o botão ou item de menu cuja visibilidade é condicionada à existência de coordenadas válidas no cadastro.
  2. ProcessFlow (.processflow.xml): Captura o evento de clique na interface (View Action Event) e aciona uma ação lógica (actionType="LOGIC").
  3. Business Logic (.bl.js): Lê os dados do Business Object, higieniza os valores, monta a string do URI Scheme e executa a API nativa Facade.startThirdPartyAsync(url, options).
  4. Sistema operacional (Android Intent / iOS URL Scheme): O dispositivo móvel suspende temporariamente o app do Consumer Goods Cloud e abre o aplicativo correspondente (Google Maps, Waze ou WhatsApp).
┌─────────────────────────────────────────────────────────────┐
│          UserInterface Contract (.userinterface.xml)        │
│   <MenuItem name="BtnNavigate" image="Directions" ... />   │
└──────────────────────────────┬──────────────────────────────┘
                               │ Event: NavigateTo
                               ▼
┌─────────────────────────────────────────────────────────────┐
│           ProcessFlow Contract (.processflow.xml)           │
│   <Action name="NavigateToAction" actionType="LOGIC" ... /> │
└──────────────────────────────┬──────────────────────────────┘
                               │ Invoke Business Logic
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                   Business Logic (.bl.js)                   │
│   1. Obtém Latitude e Longitude do LuCustomer               │
│   2. Monta URI: maps.google.com ou waze://?ll=...           │
│   3. Executa: Facade.startThirdPartyAsync(url, {})          │
└──────────────────────────────┬──────────────────────────────┘
                               │ Device Handover
                               ▼
┌─────────────────────────────────────────────────────────────┐
│             Sistema Operacional (Android / iOS)             │
│   - Abre Google Maps / Waze / WhatsApp com dados injetados  │
│   - Ao encerrar, o usuário retorna ao CGC Mobile App        │
└─────────────────────────────────────────────────────────────┘
Code language: HTML, XML (xml)

2. A API nativa Facade.startThirdPartyAsync

O serviço Facade do framework Mv2 encapsula chamadas de baixo nível para recursos do dispositivo. O método para acionar aplicações externas possui a seguinte assinatura:

Facade.startThirdPartyAsync(url, options);
  • url (String): A URL completa ou URI Scheme customizado a ser disparado (ex.: http://maps.google.com/maps?... ou whatsapp://send?...).
  • options (Object): Objeto de configuração repassado ao runtime nativo (geralmente passado como {}).
  • Retorno (Promise): Promessa resolvida assim que o sistema operacional aceita a requisição de abertura do app terceiro.

3. Catálogo de URI Schemes para campo

Cada aplicativo requer uma formatação específica de protocolo para receber os dados contextuais:

Google Maps (Multiplataforma)

Abre o aplicativo calculando a rota da localização atual até as coordenadas do ponto de venda:

var url = "http://maps.google.com/maps?mode=d&daddr=" + latitude + "+" + longitude;

Waze

Inicia diretamente a navegação curva a curva:

var url = "waze://?ll=" + latitude + "," + longitude + "&navigate=yes";

WhatsApp

Abre uma conversa direta no WhatsApp injetando texto pré-definido:

var encodedMessage = encodeURIComponent("Olá! Sou o promotor da Alpine Group e gostaria de confirmar nossa visita técnica para hoje.");
var url = "https://api.whatsapp.com/send?phone=" + formattedPhone + "&text=" + encodedMessage;

Discador telefônico

Abre o teclado de chamadas com o número pronto para discagem:

var url = "tel:" + phoneNumber;

4. Implementação na camada de Business Logic (.bl.js)

Para ilustrar o padrão, criamos dois métodos no Business Object: um para controlar a visibilidade do botão e outro para disparar a navegação.

Método 1: Visibilidade condicional (BoMyDisplay.IsNavigateVisible.bl.js)

O botão de rota só deve aparecer na interface se o ponto de venda associado possuir coordenadas de latitude e longitude registradas no SQLite:

"use strict";

///////////////////////////////////////////////////////////////////////////////////////////////
//                 IMPORTANT - DO NOT MODIFY AUTO-GENERATED CODE OR COMMENTS                 //
//Parts of this file are auto-generated and modifications to those sections will be          //
//overwritten. You are allowed to modify:                                                    //
// - the tags in the jsDoc as described in the corresponding section                         //
// - the function name and its parameters                                                    //
// - the function body between the insertion ranges                                          //
//         "Add your customizing javaScript code below / above"                              //
///////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Avalia se o botão de navegação para mapas externos deve ser exibido.
 *
 * @function isNavigateVisible
 * @this BoMyDisplay
 * @kind businesslogic
 * @namespace CUSTOM
 * @returns {Boolean} Retorna true quando existem coordenadas válidas no registro.
 */
function isNavigateVisible() {
    var me = this;

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //                                                                                           //
    //               Add your customizing javaScript code below.                                 //
    //                                                                                           //
    ///////////////////////////////////////////////////////////////////////////////////////////////

    /* 
     * Data: 2026-09-11
     * Objetivo da Customização: Avaliar se o botão de navegação para aplicativos externos (Google Maps, Waze) deve ser exibido com base na presença de coordenadas válidas do cliente.
     */
    var isVisible = false;
    var customer = me.getLuCustomer();

    if (Utils.isDefined(customer) && customer.getPKey() !== " ") {
        var lat = customer.getLatitude();
        var lon = customer.getLongitude();

        if (Utils.isDefined(lat) && Utils.isDefined(lon) && lat !== 0 && lon !== 0) {
            isVisible = true;
        }
    }

    return isVisible;

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //                                                                                           //
    //               Add your customizing javaScript code above.                                 //
    //                                                                                           //
    ///////////////////////////////////////////////////////////////////////////////////////////////
}

Método 2: Disparo de navegação (BoMyDisplay.MyNavigateTo.bl.js)

Recupera a localização da loja, formata a URL de destino e invoca o Facade:

"use strict";

///////////////////////////////////////////////////////////////////////////////////////////////
//                 IMPORTANT - DO NOT MODIFY AUTO-GENERATED CODE OR COMMENTS                 //
//Parts of this file are auto-generated and modifications to those sections will be          //
//overwritten. You are allowed to modify:                                                    //
// - the tags in the jsDoc as described in the corresponding section                         //
// - the function name and its parameters                                                    //
// - the function body between the insertion ranges                                          //
//         "Add your customizing javaScript code below / above"                              //
///////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Dispara o aplicativo de mapas passando as coordenadas do ponto de venda.
 *
 * @function myNavigateTo
 * @this BoMyDisplay
 * @kind businesslogic
 * @async
 * @namespace CUSTOM
 * @param {Object} context Contexto de execução do processo.
 * @returns {Promise<Object>} Promessa resolvida com o contexto.
 */
function myNavigateTo(context) {
    var me = this;

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //                                                                                           //
    //               Add your customizing javaScript code below.                                 //
    //                                                                                           //
    ///////////////////////////////////////////////////////////////////////////////////////////////

    /* 
     * Data: 2026-09-11
     * Objetivo da Customização: Disparar navegação App2App para mapas externos utilizando a API nativa Facade.startThirdPartyAsync com coordenadas de latitude e longitude.
     */
    AppLog.info("BoMyDisplay.myNavigateTo: Iniciando processo App2App para mapas.");

    var customer = me.getLuCustomer();
    var latitude = 0.0;
    var longitude = 0.0;

    if (Utils.isDefined(customer)) {
        latitude = customer.getLatitude() || 0.0;
        longitude = customer.getLongitude() || 0.0;
    }

    if (latitude === 0.0 && longitude === 0.0) {
        AppLog.warn("BoMyDisplay.myNavigateTo: Coordenadas geográficas não encontradas.");
        return when.resolve(context);
    }

    var mapUrl = "http://maps.google.com/maps?mode=d&daddr=" + latitude + "+" + longitude;

    var promise = Facade.startThirdPartyAsync(mapUrl, {}).then(function() {
        AppLog.info("BoMyDisplay.myNavigateTo: Aplicativo externo acionado pelo sistema operacional.");
        return context;
    }).catch(function(error) {
        AppLog.error("BoMyDisplay.myNavigateTo: Falha ao acionar aplicativo externo.", error);
        return context;
    });

    return promise;

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //                                                                                           //
    //               Add your customizing javaScript code above.                                 //
    //                                                                                           //
    ///////////////////////////////////////////////////////////////////////////////////////////////
}

5. Orquestração no ProcessFlow (.processflow.xml)

No contrato do fluxo (MyDisplay_DisplayDetailsProcess.processflow.xml), declare o evento de tela e a transição para a lógica JavaScript. No Modeler Mv2, contratos de Process usam obrigatoriamente schemaVersion="0.0.0.5":

<?xml version="1.0" encoding="UTF-8"?>
<ProcessFlow name="MyDisplay_DisplayDetailsProcess" schemaVersion="0.0.0.5">
  <Declaration>
    <Context name="CurrentDisplay" type="BoMyDisplay" />
  </Declaration>

  <ViewActionEvents>
    <Event name="NavigateTo" action="NavigateToAction" />
  </ViewActionEvents>

  <States>
    <State name="ShowDisplayDetails">
      <Actions>
        <Action name="NavigateToAction" actionType="LOGIC" call="ProcessContext::CurrentDisplay.MyNavigateTo">
          <TransitionTo action="ShowDisplayDetails" />
        </Action>
      </Actions>
    </State>
  </States>
</ProcessFlow>

6. Configuração do botão na UserInterface (.userinterface.xml)

Na interface visual (MyDisplay_DisplayDetailsUI.userinterface.xml), inserimos a ação na barra de menu, ligando a visibilidade à regra do Business Object. Contratos de UI utilizam schemaVersion="0.0.0.5":

<?xml version="1.0" encoding="UTF-8"?>
<UserInterface name="MyDisplay_DisplayDetailsUI" schemaVersion="0.0.0.5">
  <Header title="Detalhes da Exibição">
    <MenuItems>
      <MenuItem name="BtnNavigate" image="Directions" text="labels:LblNavigateToStore" visible="ProcessContext::CurrentDisplay.isNavigateVisible">
        <Events>
          <Event name="click" event="NavigateTo" />
        </Events>
      </MenuItem>
    </MenuItems>
  </Header>
  <Container name="MainContainer">
  </Container>
</UserInterface>

7. Particularidades de teste e validação

O disparo físico de aplicações de terceiros não opera dentro do simulador desktop (sf modeler workspace server start). No navegador web do computador, a chamada do protocolo não encontra os aplicativos móveis correspondentes.

Para validar o fluxo completo:

  1. Validação sintática e de schemas: Execute no terminal:sf modeler workspace validate sf modeler workspace build
  2. Geração do pacote de deploy: Gere o arquivo de distribuição:sf modeler workspace package
  3. Distribuição para o dispositivo móvel: Suba o pacote compilado para a org Salesforce e atribua o contrato aos perfis móveis.
  4. Sincronização no tablet ou smartphone: Abra o aplicativo Salesforce Consumer Goods Cloud no dispositivo físico, execute a sincronização inicial e abra a tela de detalhe. Ao tocar no ícone de direção, o Google Maps ou Waze abrirá com a rota traçada.

Conclusão

O recurso de App2App Communication integra o banco de dados offline do Consumer Goods Cloud às ferramentas nativas de navegação e comunicação instaladas no dispositivo. A chamada a Facade.startThirdPartyAsync, combinada com a higienização de parâmetros e regras de visibilidade no Business Object, elimina a digitação manual de endereços e simplifica o atendimento diário em campo.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *