Saiba como a mudança para o PWA ajudou os negócios da MishiPay.
O MishiPay permite que os compradores digitalizem e paguem pelas compras com smartphones, em vez de perder tempo na fila do caixa. Com a tecnologia Scan & Go do MishiPay, os compradores podem usar o próprio smartphone para escanear o código de barras dos itens e pagar por eles, e depois simplesmente sair da loja. Estudos revelam que as filas na loja custam ao setor de varejo global cerca de US$ 200 bilhões por ano.
Nossa tecnologia depende de recursos de hardware do dispositivo, como sensores de GPS e câmeras, que permitem que os usuários localizem lojas com suporte para MishiPay, leiam códigos de barras de itens na loja física e paguem usando a forma de pagamento digital de escolha. As versões iniciais da nossa tecnologia Scan & Go eram aplicativos específicos para iOS e Android, e os primeiros usuários adoraram a tecnologia. Leia para saber como a migração para um PWA aumentou as transações em 10 vezes e economizou 2,5 anos de filas.
10×
Mais transações
2,5 anos
Fila salva
Desafio
Os usuários acham nossa tecnologia extremamente útil ao esperar em uma fila ou fila de check-out, porque ela permite que eles pulem a fila e tenham uma experiência tranquila na loja. No entanto, a dificuldade de fazer o download de um aplicativo Android ou iOS fez com que os usuários não escolhessem nossa tecnologia, apesar do valor. Era um desafio crescente para a MishiPay, e precisávamos aumentar a adoção do usuário com uma barreira de entrada menor.
Solução
Nossos esforços para criar e lançar a PWA nos ajudaram a eliminar a dificuldade de instalação e incentivaram novos usuários a testar nossa tecnologia em uma loja física, pular a fila e ter uma experiência de compra integrada. Desde o lançamento, observamos um aumento significativo na adoção do usuário com nossa PWA em comparação com nossos aplicativos específicos para plataforma.
Aprofundamento técnico
Como encontrar lojas com suporte para o MishiPay
Para ativar esse recurso, usamos a API
getCurrentPosition()
com uma solução substituta baseada em IP.
const geoOptions = {
timeout: 10 * 1000,
enableHighAccuracy: true,
maximumAge: 0,
};
window.navigator.geolocation.getCurrentPosition(
(position) => {
const cords = position.coords;
console.log(`Latitude : ${cords.latitude}`);
console.log(`Longitude : ${cords.longitude}`);
},
(error) => {
console.debug(`Error: ${error.code}:${error.message}`);
/**
* Invoke the IP based location services
* to fetch the latitude and longitude of the user.
*/
},
geoOptions,
);
Essa abordagem funcionou bem nas versões anteriores do app, mas depois se mostrou um grande problema para os usuários do MishiPay pelos seguintes motivos:
- Imprecisões de localização nas soluções de substituição baseadas em IP.
- Uma listagem crescente de lojas ativadas para o MishiPay por região exige que os usuários rolem a lista e identifiquem a loja correta.
- Os usuários às vezes escolhem a loja errada, fazendo com que as compras sejam registradas incorretamente.
Para resolver esses problemas, incorporamos QR codes com geolocalização exclusiva nas telas de cada loja. Isso facilitou a integração. Os usuários só precisam ler os códigos QR geolocalizados impressos nos materiais de marketing presentes nas lojas para acessar o aplicativo da Web Scan &Go.
Dessa forma, eles não precisam digitar o endereço da Web mishipay.shop
para acessar o serviço.
Como ler códigos de barras
Um recurso principal do app MishiPay é a leitura de código de barras, que permite que nossos usuários leiam as próprias compras e vejam o total antes mesmo de chegar ao caixa.
Para criar uma experiência de leitura na Web, identificamos três camadas principais.
Stream de vídeo
Com a ajuda do
método getUserMedia()
, podemos
acessar a câmera traseira do usuário com as restrições listadas abaixo. Invocar o método
aciona automaticamente uma solicitação para que os usuários aceitem ou neguem o acesso à câmera. Assim que tivermos
acesso ao stream de vídeo, podemos retransmiti-lo para um elemento de vídeo, conforme mostrado abaixo:
/**
* Video Stream Layer
* https://developer.mozilla.org/docs/Web/API/MediaDevices/getUserMedia
*/
const canvasEle = document.getElementById('canvas');
const videoEle = document.getElementById('videoElement');
const canvasCtx = canvasEle.getContext('2d');
fetchVideoStream();
function fetchVideoStream() {
let constraints = { video: { facingMode: 'environment' } };
if (navigator.mediaDevices !== undefined) {
navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
videoEle.srcObject = stream;
videoStream = stream;
videoEle.play();
// Initiate frame capture - Processing Layer.
})
.catch((error) => {
console.debug(error);
console.warn(`Failed to access the stream:${error.name}`);
});
} else {
console.warn(`getUserMedia API not supported!!`);
}
}
Camada de processamento
Para detectar um código de barras em um determinado stream de vídeo, precisamos capturar frames periodicamente e transferi-los
para a camada do decodificador. Para capturar um frame, basta desenhar os streams de VideoElement
em
um HTMLCanvasElement
usando o método
drawImage()
da API Canvas.
/**
* Processing Layer - Frame Capture
* https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Manipulating_video_using_canvas
*/
async function captureFrames() {
if (videoEle.readyState === videoEle.HAVE_ENOUGH_DATA) {
const canvasHeight = (canvasEle.height = videoEle.videoHeight);
const canvasWidth = (canvasEle.width = videoEle.videoWidth);
canvasCtx.drawImage(videoEle, 0, 0, canvasWidth, canvasHeight);
// Transfer the `canvasEle` to the decoder for barcode detection.
const result = await decodeBarcode(canvasEle);
} else {
console.log('Video feed not available yet');
}
}
Para casos de uso avançados, essa camada também realiza algumas tarefas de pré-processamento, como recorte,
rotação ou conversão para escala de cinza. Essas tarefas podem exigir muito da CPU e fazer com que o aplicativo
não responda, já que a leitura de código de barras é uma operação de longa duração. Com a ajuda da
API OffscreenCanvas, podemos transferir
a tarefa que exige muito da CPU para um worker da Web. Em dispositivos com suporte à aceleração gráfica de hardware,
a API WebGL e o
WebGL2RenderingContext
podem
otimizar os ganhos nas tarefas de pré-processamento que exigem muito da CPU.
Camada de decodificador
A camada final é a camada de decodificador, que é responsável por decodificar os códigos de barras dos frames
capturados pela camada de processamento. Graças à
API Shape Detection (que ainda
não está disponível em todos os navegadores), o próprio navegador decodifica o código de barras de um
ImageBitmapSource
, que pode ser um elemento img
, um elemento SVG image
, um elemento video
, um
elemento canvas
, um objeto Blob
, um objeto ImageData
ou um objeto ImageBitmap
.
/**
* Barcode Decoder with Shape Detection API
* https://web.dev/shape-detection/
*/
async function decodeBarcode(canvas) {
const formats = [
'aztec',
'code_128',
'code_39',
'code_93',
'codabar',
'data_matrix',
'ean_13',
'ean_8',
'itf',
'pdf417',
'qr_code',
'upc_a',
'upc_e',
];
const barcodeDetector = new window.BarcodeDetector({
formats,
});
try {
const barcodes = await barcodeDetector.detect(canvas);
console.log(barcodes);
return barcodes.length > 0 ? barcodes[0]['rawValue'] : undefined;
} catch (e) {
throw e;
}
}
Para dispositivos que ainda não oferecem suporte à API Shape Detection, precisamos de uma solução alternativa para decodificar
os códigos de barras. A API Shape Detection expõe um método
getSupportedFormats()
que ajuda a alternar entre a API Shape Detection e a solução substituta.
// Feature detection.
if (!('BarceodeDetector' in window)) {
return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
supportedFormats.forEach((format) => console.log(format));
});
Solução substituta
Várias bibliotecas de verificação corporativas e de código aberto estão disponíveis e podem ser facilmente integradas a qualquer aplicativo da Web para implementar a verificação. Confira algumas das bibliotecas recomendadas pela MishiPay.
Todas as bibliotecas acima são SDKs completos que compõem todas as camadas discutidas acima. Elas também expõem interfaces para dar suporte a várias operações de verificação. Dependendo dos formatos de código de barras e da velocidade de detecção necessária para o caso de negócios, uma decisão pode ser entre soluções Wasm e não Wasm. Apesar do custo de exigir um recurso extra (Wasm) para decodificar o código de barras, as soluções Wasm são mais eficientes do que as que não usam o Wasm em termos de precisão.
A Scandit foi nossa principal escolha. Ele oferece suporte a todos os formatos de código de barras necessários para nossos casos de uso comercial. Ele supera todas as bibliotecas de código aberto disponíveis em velocidade de leitura.
O futuro da verificação
Quando a API Shape Detection tiver suporte total de todos os principais navegadores, poderemos ter um
novo elemento HTML <scanner>
com os recursos necessários para um leitor de código de barras. A equipe de engenharia
da MishiPay acredita que há um caso de uso sólido para que a funcionalidade de leitura de código de barras seja um novo
elemento HTML devido ao número crescente de bibliotecas licenciadas e de código aberto que estão permitindo
experiências como o recurso "Scan & Go" e muitas outras.
Conclusão
A fadiga de apps é um problema que os desenvolvedores enfrentam quando os produtos entram no mercado. Muitas vezes, os usuários querem entender o valor que um aplicativo oferece antes de fazer o download. Em uma loja, em que o MishiPay economiza tempo dos compradores e melhora a experiência deles, é contra-intuitivo esperar por um download antes de usar um aplicativo. É aí que nossa PWA ajuda. Ao eliminar a barreira à entrada, aumentamos nossas transações em 10 vezes e permitimos que os usuários economizassem 2,5 anos de espera na fila.
Agradecimentos
Este artigo foi revisado por Joe Medley.