MishiPay PWA로 거래 10배 증가, 대기 시간 2.5년 단축

PWA로의 전환이 MishiPay의 비즈니스에 어떤 도움이 되었는지 알아보세요.

MishiPay는 쇼핑객이 계산대에서 줄을 서서 기다리는 시간을 낭비하지 않고 스마트폰으로 쇼핑을 스캔하고 결제할 수 있는 기능을 제공합니다. MishiPay의 스캔 앤 고 기술을 사용하면 쇼핑객이 자신의 휴대전화를 사용하여 상품의 바코드를 스캔하고 금액을 결제한 다음 그냥 매장을 나갈 수 있습니다. 연구에 따르면 전 세계 소매 부문에서 매장 대기로 인한 연간 비용은 약 2,000억 달러에 달합니다.

Google의 기술은 GPS 센서 및 카메라와 같은 기기 하드웨어 기능을 사용합니다. 사용자는 이 기능을 통해 MishiPay가 지원되는 매장을 찾고 오프라인 상점의 상품 바코드를 스캔한 다음 원하는 디지털 결제 수단을 사용하여 결제할 수 있습니다. 스캔앤고 기술의 초기 버전은 플랫폼에 맞는 iOS 및 Android 애플리케이션이었으며 얼리 어답터는 이 기술을 마음에 들어 했습니다. PWA로 전환하여 거래를 10배 늘리고 대기열을 2.5년이나 단축한 방법을 알아보려면 계속 읽어보세요.

    10×

    거래 증가

    2.5년

    현재 재생목록을 저장했습니다.

당면 과제

Google의 기술은 대기열이나 계산대에서 기다릴 때 대기열을 건너뛰고 매끄러운 매장 경험을 제공할 수 있어 매우 유용합니다. 하지만 Android 또는 iOS 애플리케이션을 다운로드하는 번거로움으로 인해 사용자는 그 가치에도 불구하고 당사 기술을 선택하지 않았습니다. MishiPay는 이 같은 문제를 해결하기 위해 진입 장벽을 낮추면서도 사용자 채택률을 높여야 했습니다.

솔루션

PWA를 빌드하고 출시하기 위한 우리의 노력은 설치의 번거로움을 없애는 데 도움이 되었고, 신규 사용자에게 오프라인 상점에서 Google의 기술을 사용해 보고, 대기열을 건너뛰고, 원활한 쇼핑 환경을 제공하도록 독려했습니다. 출시 이후 PWA의 사용자 채택률이 플랫폼별 애플리케이션에 비해 크게 증가했습니다.

PWA를 직접 실행하는 경우 (왼쪽, 빠르게)와 Android 앱을 설치하고 실행하는 경우 (오른쪽, 느리게)를 나란히 비교한 내용을 확인하세요.
플랫폼별 거래입니다. ¡OS: 16397 (3.98%). Android: 13769 (3.34%) 웹: 382184 (92.68%).
대부분의 거래는 웹에서 발생합니다.

기술 심층 분석

MishiPay가 사용 설정된 매장 찾기

이 기능을 사용 설정하기 위해 IP 기반 대체 솔루션과 함께 getCurrentPosition() API를 사용합니다.

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

이 접근 방식은 이전 버전의 앱에서는 잘 작동했지만 나중에 MishiPay 사용자가 큰 불편을 겪는 이유는 다음과 같습니다.

  • IP 기반 대체 솔루션의 위치가 부정확합니다.
  • MishiPay가 지원되는 지역별 매장이 늘어나면서 사용자가 목록을 스크롤하여 올바른 매장을 확인해야 하는 상황이 벌어지고 있습니다.
  • 사용자가 실수로 잘못된 매장을 선택하여 구매가 잘못 기록되는 경우가 있습니다.

이 문제를 해결하기 위해 각 매장의 매장 디스플레이에 고유한 위치정보 QR 코드를 삽입했습니다. 덕분에 온보딩 경험을 더욱 빠르게 진행할 수 있었습니다. 사용자는 매장에 있는 마케팅 자료에 인쇄된 위치정보가 지정된 QR 코드를 스캔하기만 하면 스캔앤고 웹 애플리케이션에 액세스할 수 있습니다. 이렇게 하면 서비스에 액세스하기 위해 웹 주소(mishipay.shop)를 입력하지 않아도 됩니다.

PWA를 사용한 매장 스캔 환경

제품 스캔 중

MishiPay 앱의 핵심 기능은 바코드 스캔입니다. 사용자가 자신의 구매를 스캔하여 금전 등록기에 도달하기도 전에 총금액을 확인할 수 있는 바코드 스캔입니다.

Google에서는 웹에 스캔 환경을 구축하기 위해 세 가지 핵심 레이어를 확인했습니다.

동영상 스트림, 처리 레이어, 디코더 레이어의 세 가지 기본 스레드 레이어를 보여주는 다이어그램

동영상 스트림

getUserMedia() 메서드를 사용하면 아래 나열된 제약 조건으로 사용자의 후방 카메라에 액세스할 수 있습니다. 이 메서드를 호출하면 사용자에게 카메라 액세스를 수락하거나 거부하라는 메시지가 자동으로 트리거됩니다. 동영상 스트림에 액세스할 수 있게 되면 아래와 같이 동영상 요소에 이를 전달할 수 있습니다.

/**
 * 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!!`);
  }
}

처리 레이어

특정 동영상 스트림에서 바코드를 감지하려면 주기적으로 프레임을 캡처하여 디코더 레이어로 전송해야 합니다. 프레임을 캡처하려면 Canvas APIdrawImage() 메서드를 사용하여 VideoElement의 스트림을 HTMLCanvasElement에 그립니다.

/**
 * 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');
  }
}

고급 사용 사례의 경우 이 레이어는 자르기, 회전 또는 그레이 스케일로 변환과 같은 전처리 작업도 실행합니다. 이러한 작업은 CPU를 많이 사용할 수 있으며 바코드 스캔이 장기 실행 작업이므로 애플리케이션이 응답하지 않는 결과를 초래할 수 있습니다. OffscreenCanvas API를 사용하면 CPU 집약적인 작업을 웹 워커에 오프로드할 수 있습니다. 하드웨어 그래픽 가속을 지원하는 기기에서 WebGL API 및 WebGL2RenderingContext는 CPU를 많이 사용하는 사전 처리 작업에서 게인을 최적화할 수 있습니다.

디코더 레이어

마지막 레이어는 처리 레이어에서 캡처한 프레임에서 바코드를 디코딩하는 역할을 하는 디코더 레이어입니다. Shape Detection API (아직 모든 브라우저에서 사용할 수 없음) 덕분에 브라우저 자체에서 ImageBitmapSource에서 바코드를 디코딩합니다. 이러한 바코드는 img 요소, SVG image 요소, video 요소, canvas 요소, Blob 객체, ImageData 객체, ImageBitmap 객체일 수 있습니다.

동영상 스트림, 처리 레이어, Shape Detection API의 세 가지 기본 스레드 레이어를 보여주는 다이어그램

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

아직 Shape Detection API를 지원하지 않는 기기의 경우 바코드를 디코딩할 대체 솔루션이 필요합니다. Shape Detection API는 Shape Detection API와 대체 솔루션 간에 전환하는 데 도움이 되는 getSupportedFormats() 메서드를 제공합니다.

// Feature detection.
if (!('BarceodeDetector' in window)) {
  return;
}
// Check supported barcode formats.
BarcodeDetector.getSupportedFormats()
.then((supportedFormats) => {
  supportedFormats.forEach((format) => console.log(format));
});

바코드 감지기 지원 및 지원되는 바코드 형식에 따라 Shape Detection API 또는 대체 솔루션이 사용되는 방식을 보여주는 흐름 다이어그램

대체 솔루션

모든 웹 애플리케이션과 쉽게 통합하여 스캔을 구현할 수 있는 여러 오픈소스 및 기업 스캔 라이브러리가 제공됩니다. 다음은 MishiPay에서 추천하는 몇 가지 라이브러리입니다.

라이브러리 이름 유형 Wasm 솔루션 바코드 형식
QuaggaJs 오픈소스 아니요 1일
ZxingJs 오픈소스 아니요 1D 및 2D (제한적)
CodeCorp Enterprise 1D 및 2D
스칸디트 Enterprise 1D 및 2D
오픈소스 및 상업용 바코드 스캔 라이브러리 비교

위의 모든 라이브러리는 위에서 설명한 모든 레이어를 구성하는 완전한 SDK입니다. 또한 다양한 스캔 작업을 지원하는 인터페이스를 노출합니다. 비즈니스 사례에 필요한 바코드 형식과 감지 속도에 따라 Wasm 솔루션과 비 Wasm 솔루션 간에 결정을 내릴 수 있습니다. 바코드를 디코딩하는 데 추가 리소스 (Wasm)가 필요한 오버헤드에도 불구하고 Wasm 솔루션은 정확성 측면에서 비 Wasm 솔루션보다 성능이 뛰어납니다.

우선은 Scandit이었습니다. 비즈니스 사용 사례에 필요한 모든 바코드 형식을 지원하며, 스캔 속도에서 사용 가능한 모든 오픈소스 라이브러리를 능가합니다.

향후 스캔 기능

모든 주요 브라우저에서 Shape Detection API를 완전히 지원하게 되면 바코드 스캐너에 필요한 기능이 포함된 새로운 HTML 요소 <scanner>을 가질 수 있습니다. MishiPay의 엔지니어링은 스캔 앤 고 등의 환경을 지원하는 오픈소스와 라이선스가 부여된 라이브러리가 증가하고 있기 때문에 바코드 스캔 기능이 새로운 HTML 요소로 활용될 수 있는 확실한 사용 사례가 있다고 생각합니다.

결론

앱 피로는 제품이 시장에 진입할 때 개발자가 직면하는 문제입니다. 사용자는 종종 애플리케이션을 다운로드하기 전에 애플리케이션이 제공하는 가치를 알고 싶어 합니다. MishiPay가 쇼핑객의 시간을 절약하고 사용 경험을 개선하는 매장에서 애플리케이션을 사용하기 전에 다운로드를 기다리는 것은 직관적이지 않습니다. 이러한 점에서 PWA가 도움이 됩니다. 진입 장벽을 제거하여 트랜잭션을 10배 늘리고 사용자가 대기열에서 대기하는 시간을 2.5년 단축할 수 있었습니다.

감사의 말

Joe Medley가 이 문서를 검토했습니다.