Wake Lock API 案例研究:BettyCrocker.com 上的购买意愿指标增长了 300%

在移动设备上烹饪时,最糟糕的情况莫过于在查看食谱步骤时屏幕关闭。了解烹饪网站 BettyCrocker.com 如何使用 Wake Lock API 来防止这种情况。

近一个世纪以来,Betty Crocker 一直是美国现代烹饪说明和可信食谱开发的来源。 该公司的网站 BettyCrocker.com 于 1997 年推出,如今每月吸引超过 1, 200 万访问者。实现 Wake Lock API 后,与所有用户相比,唤醒锁定用户的购买意图指标提高了约 300%

已弃用的 iOS 和 Android 应用

Betty Crocker 在 2014 年大张旗鼓地发布了自己的应用,但最近在其应用被降级后,从 Apple App Store 和 Google Play 商店下架了这些应用。长期以来,Betty Crocker 团队一直更倾向于在移动网站上添加新功能,而不是在 iOS/Android 应用中添加。用于创建 iOS/Android 应用的技术平台已过时,并且该公司没有资源来支持日后更新和维护这些应用。从客观上讲,Web 应用在流量方面要大得多,也更现代化,并且更易于增强。

不过,iOS/Android 应用确实有一个深受用户喜爱的杀手级功能

千禧一代厨艺达人提示:在您按照食谱烹饪时,@BettyCrocker 移动应用不会调暗或锁定。 - @AvaBeilke

80% 的用户会在厨房使用设备烹饪,但屏幕调暗和锁定会带来问题。 @BettyCrocker 做了什么? 更新了应用,以便在用户查看食谱时不调暗屏幕。 - @KatieTweedy

使用 Wake Lock API 将杀手级功能引入到 Web 中

使用设备烹饪时,最令人沮丧的事情莫过于在屏幕关闭时,必须用脏兮兮的手或甚至用鼻子触摸屏幕。Betty Crocker 团队反思自己如何将 iOS/Android 应用的杀手级功能移植到 Web 应用。就在此时,他们了解了 Project FuguWake Lock API

一个人在撒满面粉的厨房桌上揉面团

Wake Lock API 提供了一种方法来防止设备屏幕变暗或锁定。此功能可实现之前需要 iOS/Android 应用才能实现的新体验。Wake Lock API 减少了对可能耗电的权宜解决方法的需求。

请求唤醒锁定

如需请求唤醒锁定,您需要调用返回 WakeLockSentinel 对象的 navigator.wakeLock.request() 方法。您将使用此对象作为哨兵值。浏览器可能会出于各种原因(例如电池电量过低)拒绝请求,因此最好将调用封装在 try…catch 语句中。

释放唤醒锁定

您还需要一种释放唤醒锁的方法,可通过调用 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);

实现

借助新版 Web 应用,用户应该能够轻松浏览食谱、完成步骤,甚至在离开时屏幕也不会锁定。为了实现这一目标,该团队首先构建了一个快速的前端原型,以便进行概念验证并收集用户体验反馈。

原型证明非常实用,于是他们设计了一个可供所有品牌(BettyCrockerPillsburyTablespoon)共享的 Vue.js 组件。虽然只有 Betty Crocker 有 iOS 和 Android 应用,但这三个网站确实共用一个代码库,因此他们只需实现一次该组件,即可在所有平台上部署该组件,如下面的屏幕截图所示。

BettyCrocker.com 唤醒锁定切换开关
BettyCrocker.com 唤醒锁定切换开关。
Pillsbury.com 唤醒锁定切换开关
Pillsbury.com 唤醒锁定切换开关。
Tablespoon.com 唤醒锁定切换开关
Tablespoon.com 唤醒锁定切换开关。

在基于新网站的现代化框架开发组件时,我们非常注重 MVVM 模式的 ViewModel。该团队还在编程时考虑了互操作性,以便在网站的旧版和新版框架上实现功能。

为了跟踪可见度和易用性,Betty Crocker 集成了唤醒锁定生命周期中核心事件的数据分析跟踪。该团队利用功能管理将唤醒锁定组件部署到单个网站以进行初始正式版发布,然后在监控使用情况和网页健康状况后,将该功能部署到其余网站。他们会继续根据此组件的使用情况监控分析数据。

为了为用户提供故障安全保障,该团队创建了一个强制超时功能,以便在用户无活动状态持续一小时后停用唤醒锁。他们最终确定的实施方案是,在网站上的所有食谱页面上短期内添加一个切换开关。他们希望从长远来看,改进食谱页面浏览体验。

唤醒锁容器

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 报告了以下指标:

  • 在所有使用与 Wake Lock API 兼容的浏览器的 Betty Crocker 用户中,有 3.5% 的用户立即启用了该功能,使其成为前 5 项操作之一。
  • 启用唤醒锁的用户的会话时长比未启用唤醒锁的用户长 3.1 倍。
  • 启用唤醒锁的用户的跳出率比未使用唤醒锁功能的用户低 50%。
  • 与所有用户相比,唤醒锁定用户的购买意向指标高出约 300%。

3.1×

更长的会话时长

50%

降低跳出率

300%

购买意愿指标更高

总结

Betty Crocker 在使用 Wake Lock API 后取得了出色的成效。您可以自行测试此功能,方法是在其任一网站(BettyCrockerPillsburyTablespoon)上搜索您喜爱的食谱,然后启用在您烹饪时防止屏幕变暗切换开关。

唤醒锁的用例并不局限于食谱网站。 其他示例包括:需要在扫描条形码之前保持屏幕开启状态的登机牌或票券应用、持续保持屏幕开启状态的 kiosk 式应用,或可防止屏幕在演示期间进入休眠状态的基于 Web 的演示文稿应用。

我们在本网站上撰写了一篇详细的文章,其中汇总了有关 Wake Lock API 的所有须知信息。祝您阅读愉快,烹饪愉快!

致谢

有人揉面团照片由 Unsplash 上的 Julian Hochgesang 提供。