Wake Lock API 個案研究:BettyCrocker.com 上的購買意願指標提升了 300%

使用行動裝置烹飪時,最糟糕的情況莫過於在食譜步驟中途螢幕關閉。瞭解烹飪網站 BettyCrocker.com 如何使用 Wake Lock API 避免發生這種情況。

近一個世紀以來,Betty Crocker 一直是美國現代烹飪教學和可靠食譜開發的來源。該公司在 1997 年推出的網站 BettyCrocker.com,目前每月吸引超過 1, 200 萬名訪客造訪。實作 Wake Lock API 後,與所有使用者相比,喚醒鎖定使用者的購買意圖指標提升了約 300%

已停用的 iOS 和 Android 應用程式

Betty Crocker 於 2014 年推出的應用程式廣受歡迎,但最近因應用程式優先順序降低,因此將其從 Apple App Store 和 Google Play 商店下架。長期以來,Betty Crocker 團隊都偏好在行動網站中加入新功能,而不是在 iOS/Android 應用程式中加入。建立 iOS/Android 應用程式的技術平台已過時,且該企業沒有資源支援應用程式的更新和維護作業。從流量角度來看,網頁應用程式也更有優勢,因為它更現代化,也更容易強化。

不過,iOS/Android 應用程式確實有一個使用者喜愛的殺手功能

千禧世代烹飪專家提示:@BettyCrocker 行動應用程式在你按照食譜操作時,不會調低亮度或鎖定。—@AvaBeilke

80% 的使用者會在廚房中使用裝置烹飪,但螢幕調暗和鎖定功能仍有問題。@BettyCrocker 做了什麼?更新應用程式,讓使用者在食譜中瀏覽時不會變暗。—@KatieTweedy

使用 Wake Lock API 為網路帶來強大功能

使用裝置烹飪時,最令人沮喪的莫過於在螢幕關閉時,必須用髒手或鼻子觸碰螢幕。Betty Crocker 想知道如何將 iOS/Android 應用程式的絕佳功能移植到網路應用程式。這時,她瞭解了 Project FuguWake Lock API

有人在廚房的桌上揉麵團,桌上有麵粉

Wake Lock API 提供一種方法,可防止裝置調低亮度或鎖定螢幕。這項功能可提供全新體驗,而這類體驗先前必須透過 iOS/Android 應用程式才能使用。Wake Lock API 可減少使用者需要使用不正當且可能耗電的因應措施。

要求 Wake Lock

如要要求喚醒鎖定,您必須呼叫會傳回 WakeLockSentinel 物件的 navigator.wakeLock.request() 方法。您會將這個物件用做哨值值。瀏覽器可能會基於各種原因 (例如電池電量過低) 拒絕要求,因此建議您在 try…catch 陳述式中包裝呼叫。

釋放 Wake Lock

您還需要一種釋放喚醒鎖定的方法,方法是呼叫 WakeLockSentinel 物件的 release() 方法。如果您想在一段時間過後自動釋放喚醒鎖定,可以使用 window.setTimeout() 呼叫 release(),如以下範例所示。

// The wake lock sentinel.
let wakeLock = null;

// Function that attempts to request a wake lock.
const requestWakeLock = async () => {
  try {
    wakeLock = await navigator.wakeLock.request('screen');
    wakeLock.addEventListener('release', () => {
      console.log('Wake Lock was released');
    });
    console.log('Wake Lock is active');
  } catch (err) {
    console.error(`${err.name}, ${err.message}`);
  }
};

// Request a wake lock…
await requestWakeLock();
// …and release it again after 5s.
window.setTimeout(() => {
  wakeLock.release();
  wakeLock = null;
}, 5000);

實作

有了新的網頁應用程式,使用者就能輕鬆瀏覽食譜、完成步驟,甚至離開螢幕也不會鎖定。為達成這個目標,團隊首先快速建構前端原型,做為概念驗證,並收集使用者體驗相關意見。

原型證明實用後,他們設計了一個Vue.js 元件,可供所有品牌 (BettyCrockerPillsburyTablespoon) 共用。雖然只有 Betty Crocker 有 iOS 和 Android 應用程式,但這三個網站確實有共用的程式碼集,因此可以實作一次元件,然後在所有地方部署,如以下螢幕截圖所示。

BettyCrocker.com Wake Lock 切換鈕
BettyCrocker.com 喚醒鎖定切換鈕。
Pillsbury.com Wake Lock 切換鈕
Pillsbury.com 喚醒鎖定切換鈕。
Tablespoon.com Wake Lock 切換鈕
Tablespoon.com Wake Lock 切換鈕。

在根據新網站的現代化架構開發元件時,我們特別著重於 MVVM 模式的 ViewModel。團隊也考量到互通性而進行程式設計,以便在網站的舊版和新版架構中啟用功能。

為了追蹤可視度和可用性,Betty Crocker 整合了喚醒鎖定生命週期中核心事件的數據分析追蹤功能。團隊利用功能管理功能,將喚醒鎖定元件部署到單一網站,以便進行初始正式版推出作業,然後在監控使用情形和網頁健康狀況後,將該功能部署到其他網站。並根據這個元件的使用情形,持續監控數據分析資料。

為確保使用者安全,團隊建立了強制逾時機制,在閒置一小時後停用喚醒鎖定機制。他們最終決定在短期內,在網站上的所有食譜頁面中加入切換鈕。他們希望長期能推出新版食譜頁面。

Wake Lock 容器

var wakeLockControl = () => {
  return import(/* webpackChunkName: 'wakeLock' */ './wakeLock');
};

export default {
  components: {
    wakeLockControl: wakeLockControl,
  },
  data() {
    return {
      config: {},
      wakeLockComponent: '',
    };
  },
  methods: {
    init: function(config) {
      this.config = config || {};
      if ('wakeLock' in navigator && 'request' in navigator.wakeLock) {
        this.wakeLockComponent = 'wakeLockControl';
      } else {
        console.log('Browser not supported');
      }
    },
  },
};

喚醒鎖定元件

<template>
  <div class="wakeLock">
    <div class="textAbove"></div>
    <label class="switch" :aria-label="settingsInternal.textAbove">
      <input type="checkbox" @change="onChange()" v-model="isChecked">
      <span class="slider round"></span>
    </label>
  </div>
</template>

<script type="text/javascript">
  import debounce from 'lodash.debounce';

  const scrollDebounceMs = 1000;

  export default {
    props: {
      settings: { type: Object },
    },
    data() {
      return {
        settingsInternal: this.settings || {},
        isChecked: false,
        wakeLock: null,
        timerId: 0,
      };
    },
    created() {
      this.$_raiseAnalyticsEvent('Wake Lock Toggle Available');
    },
    methods: {
      onChange: function() {
        if (this.isChecked) {
          this.$_requestWakeLock();
        } else {
          this.$_releaseWakeLock();
        }
      },
      $_requestWakeLock: async function() {
        try {
          this.wakeLock = await navigator.wakeLock.request('screen');
          //Start new timer
          this.$_handleAbortTimer();
          //Only add event listeners after wake lock is successfully enabled
          document.addEventListener(
            'visibilitychange',
            this.$_handleVisibilityChange,
          );
          window.addEventListener(
            'scroll',
            debounce(this.$_handleAbortTimer, scrollDebounceMs),
          );
          this.$_raiseAnalyticsEvent('Wake Lock Toggle Enabled');
        } catch (e) {
          this.isChecked = false;
        }
      },
      $_releaseWakeLock: function() {
        try {
          this.wakeLock.release();
          this.wakeLock = null;
          //Clear timer
          this.$_handleAbortTimer();
          //Clean up event listeners
          document.removeEventListener(
            'visibilitychange',
            this.$_handleVisibilityChange,
          );
          window.removeEventListener(
            'scroll',
            debounce(this.$_handleAbortTimer, scrollDebounceMs),
          );
        } catch (e) {
          console.log(`Wake Lock Release Error: ${e.name}, ${e.message}`);
        }
      },
      $_handleAbortTimer: function() {
        //If there is an existing timer then clear it and set to zero
        if (this.timerId !== 0) {
          clearTimeout(this.timerId);
          this.timerId = 0;
        }
        //Start new timer; Will be triggered from toggle enabled or scroll event
        if (this.isChecked) {
          this.timerId = setTimeout(
            this.$_releaseWakeLock,
            this.settingsInternal.timeoutDurationMs,
          );
        }
      },
      $_handleVisibilityChange: function() {
        //Handle navigating away from page/tab
        if (this.isChecked) {
          this.$_releaseWakeLock();
          this.isChecked = false;
        }
      },
      $_raiseAnalyticsEvent: function(eventType) {
        let eventParams = {
          EventType: eventType,
          Position: window.location.pathname || '',
        };
        Analytics.raiseEvent(eventParams);
      },
    },
  };
</script>

結果

Vue.js 元件已部署在所有三個網站上,並帶來出色的成效。在 2019 年 12 月 10 日至 2020 年 1 月 10 日期間,BettyCrocker.com 回報了以下指標:

  • 在 Betty Crocker 使用者中,有 3.5% 使用者使用與 Wake Lock API 相容的瀏覽器,並立即啟用這項功能,因此這項功能成為前 5 大操作。
  • 啟用喚醒鎖定功能的使用者的工作階段時間比未啟用的使用者長 3.1 倍。
  • 啟用喚醒鎖定功能的使用者,其跳出率比未使用喚醒鎖定功能的使用者低 50%。
  • 與所有使用者相比,喚醒鎖定使用者的購買意願指標高出約 300%。

3.1×

工作階段持續時間更長

50%

跳出率降低

300%

購買意願指標較高

結論

Betty Crocker 使用 Wake Lock API 獲得了出色的成果。你可以自行測試這項功能,只要在任何網站 (BettyCrockerPillsburyTablespoon) 搜尋喜愛的食譜,然後啟用「烹飪時避免螢幕變暗」切換鈕即可。

喚醒鎖的用途不只限於食譜網站。其他例子包括登機證或票證應用程式,需要在掃描條碼前保持螢幕開啟;自助式應用程式,需要持續保持螢幕開啟;或以網頁為主的簡報應用程式,需要在簡報期間防止螢幕進入休眠狀態。

我們已在本網站上撰寫一篇全面性的文章,彙整了您需要瞭解的所有 Wake Lock API 相關資訊。祝你閱讀愉快,烹飪愉快!

特別銘謝

人物揉麵相片Julian Hochgesang 提供,取自 Unsplash