Saiba como a mudança para o PWA ajudou a empresa da MishiPay.
O MishiPay permite que os compradores leiam e paguem pelas compras com o smartphone, em vez de perder tempo na fila no caixa. Com a tecnologia Scan & Go da MishiPay, os compradores podem usar os próprios smartphones para ler o código de barras dos itens, pagar por eles e 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 câmeras e sensores de GPS, que permitem aos usuários localizar lojas compatíveis com o MishiPay, ler códigos de barras de itens na loja física e pagar usando a forma de pagamento digital que preferirem. As versões iniciais da tecnologia Scan & Go eram aplicativos iOS e Android específicos da plataforma, e os primeiros usuários adoraram a tecnologia. Continue a ler para saber como a mudança para um PWA aumentou as transações em 10 vezes e economizou 2,5 anos de enfileiramento.
10×
Mais transações
2,5 anos
Recurso de fila salvo
Desafio
Os usuários consideram nossa tecnologia extremamente útil ao esperar em uma fila ou na fila de finalização da compra, porque permite que eles ignorem a fila e tenham uma experiência tranquila na loja. Mas o incômodo de fazer o download de um aplicativo para Android ou iOS fez com que os usuários não escolhessem nossa tecnologia, apesar do valor. Era um desafio crescente para o MishiPay e precisávamos aumentar a adoção dos usuários com uma barreira de entrada menor.
Solução
Nossos esforços para criar e lançar o PWA nos ajudaram a eliminar o transtorno 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 perfeita. Desde o lançamento, houve um aumento enorme na adoção dos usuários com nosso PWA em comparação com os aplicativos específicos da plataforma.
![Transações por plataforma. ~OS: 16.397 (3,98%). Android: 13769 (3,34%). Web: 382184 (92,68%).](https://web.dev/static/case-studies/mishipay/image/transactions-platform-3f29e33b0839e.png?authuser=5&hl=pt-br)
Detalhes técnicos
Localizar lojas habilitadas para 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 mais tarde provou ser um grande ponto problemático para os usuários do MishiPay pelos seguintes motivos:
- Imprecisões de local nas soluções substitutas com base em IP.
- Uma lista crescente de lojas compatíveis com MishiPay por região exige que os usuários rolem uma lista e identifiquem o repositório correto.
- Às vezes, os usuários escolhem acidentalmente a loja errada, fazendo com que as compras sejam registradas incorretamente.
Para resolver esses problemas, incorporamos códigos QR geolocalizados exclusivos nas telas de cada
loja. Isso preparou o caminho para uma experiência de integração mais rápida. Os usuários simplesmente digitalizam os códigos QR geolocalizados impressos no material de marketing presente nas lojas para acessar o aplicativo da Web Scan & Go.
Dessa forma, eles podem evitar digitar o endereço da Web mishipay.shop
para acessar o serviço.
Verificando produtos
Um recurso importante do app MishiPay é a leitura do código de barras, porque ela permite que nossos usuários leiam as próprias compras e vejam o valor total, mesmo antes de irem até o caixa eletrônico.
Para criar uma experiência de verificação 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 acesso à câmera. Assim que tivermos acesso à transmissão de vídeo, poderemos redirecioná-la 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 decodificador. Para capturar um frame, basta desenhar os streams de VideoElement
para
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 executa algumas tarefas de pré-processamento, como corte, rotação ou conversão para escala de cinza. Essas tarefas podem consumir muita CPU e fazer com que o aplicativo
não responda, já que a leitura do código de barras é uma operação de longa duração. Com a ajuda da API OffscreenCanvas, podemos descarregar a tarefa com uso intensivo de CPU em um worker da Web. Em dispositivos com suporte à aceleração gráfica de hardware,
a API WebGL e a
WebGL2RenderingContext
dela podem
otimizar os ganhos nas tarefas de pré-processamento com uso intensivo da CPU.
Camada decodificador
A camada final é a decodificadora, responsável por decodificar 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
, 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 são compatíveis com a API Shape Detection, precisamos de uma solução substituta 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
Há várias bibliotecas de verificação corporativas e de código aberto disponíveis que podem ser facilmente integradas a qualquer aplicativo da Web para implementar a verificação. Aqui estão algumas das bibliotecas que a MishiPay recomenda.
Todas as bibliotecas acima são SDKs completos que compõem todas as camadas discutidas acima. Eles também expõem interfaces para oferecer suporte a várias operações de verificação. Dependendo dos formatos de código de barras e da velocidade de detecção necessários para o caso de negócios, é possível decidir entre soluções Wasm e não Wasm. Apesar da sobrecarga de exigir um recurso adicional (Wasm) para decodificar o código de barras, as soluções Wasm superam as soluções que não são Wasm em termos de precisão.
O Scandit foi nossa escolha principal. Ele oferece suporte a todos os formatos de código de barras necessários para nossos casos de uso empresariais. Ele supera todas as bibliotecas de código aberto disponíveis na velocidade de leitura.
O futuro da verificação
Quando a API Shape Detection for totalmente compatível com todos os principais navegadores, é possível que tenhamos um novo elemento HTML <scanner>
que tenha os recursos necessários para um leitor de código de barras. A engenharia da MishiPay acredita que há um caso de uso sólido para que a funcionalidade de leitura do 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 possibilitando experiências como o Scan & Go e muitas outras.
Conclusão
A fadiga de apps é um problema que os desenvolvedores enfrentam quando seus produtos chegam ao mercado. Os usuários geralmente querem entender o valor que um aplicativo oferece antes de fazer o download. Em uma loja, em que o MishiPay economiza o tempo dos compradores e melhora a experiência deles, não é intuitivo esperar um download antes de usar um aplicativo. É aqui que nosso PWA pode ajudar. Ao eliminar a barreira de entrada, aumentamos nossas transações em 10 vezes e permitimos que nossos usuários economizassem 2,5 anos de espera na fila.
Agradecimentos
Este artigo foi revisado por Joe Medley.