正在載入索引…

Day 24:LIFF 刮刮樂實戰體驗

4.2k 字,約 4 分鐘

2025 iThome 鐵人賽:Line Bot × NestJS:30 天開發日記。 原文發表於 iThome,也可以在下方留言。

文章目錄
  1. 前言
    1. 實作目標
    2. 資料夾結構說明
    3. 用戶裝置及權限驗證
    4. 結果通知功能
    5. 社群分享機制
    6. 自動關閉流程
    7. LIFF 與官方帳號的連結配置
    8. 分享 LIFF 網頁前的狀態檢查
    9. 本日結語

前言

在了解 LIFF 的基礎設計流程後,本文將透過「刮刮樂」案例示範 LIFF API 的實際應用。從啟動時檢查權限與執行環境、確認用戶分享功能權限,到刮刮樂結束後發送訊息並關閉 LIFF,完整呈現 LIFF 在互動應用中的整合流程,幫助大家更清楚理解其實際運作方式。

本日程式碼的範例連結 。本文著重於 LIFF API 的整合應用,以刮刮樂為例說明完整的互動流程,刮刮樂的視覺實作細節請參考範例程式碼。

實作目標

本次將打造一個互動式刮刮樂應用,具備以下功能

  • 建立行動裝置刮刮樂體驗:開發一個在行動裝置上運作流暢的刮刮樂網站,支援觸控操作
  • 社群分享機制:刮出獎項後,使用者可將中獎結果分享給 LINE 好友
  • 結果通知功能:自動將刮獎結果透過訊息發送至使用者的聊天室
  • 自動關閉流程:無論使用者是否進行分享操作,完成互動後皆會自動關閉 LIFF 視窗,返回聊天室介面

完整功能影片

資料夾結構說明

本次在 components 目錄中建立了三個核心組件

  • ScratchCard.vue:使用 p5.js 實作刮刮樂互動效果,處理觸控刮除邏輯與視覺呈現
  • PrizeModal.vue:自訂模態框組件,當刮刮樂完全刮開時顯示中獎結果
  • Toast.vue:提示訊息組件,用於顯示分享成功訊息及錯誤提示

用戶裝置及權限驗證

使用到的 LIFF API

  • liff.isLoggedIn():檢查使用者目前是否已登入 LINE 帳號
  • liff.login():當使用者尚未登入時,引導至 LINE 登入畫面進行授權
  • liff.isInClient():檢查使用者是否在 LINE 內建瀏覽器中開啟
  • liff.getOS():取得使用者的作業系統類型,回傳值包含 ios、android 及 web 三種
  • liff.isApiAvailable('shareTargetPicker'):檢查使用者的 LINE 版本是否支援分享功能。
ts
/** 檢查並處理用戶登入狀態 */
const checkLoginStatus = (): void => {
  if (!liff.isLoggedIn()) {
    liff.login();
  }
};

/** 驗證用戶裝置及執行環境 */
const validateEnvironment = async (): Promise<boolean> => {
  const userOS = liff.getOS();
  if (!liff.isInClient() || userOS === 'web') {
    await showErrorDialog('請在 LINE 應用程式中開啟此活動');
    closeLiffWindow(3000);
    return false;
  }

  return true;
};

/** 檢查是否支援分享功能 */
const checkShareAvailability = (): boolean => {
  const isAvailable = liff.isApiAvailable('shareTargetPicker');

  if (!isAvailable) {
    showToast('提醒用戶!分享功能不可用', '需要更新 LINE 版本', 'error');
  }

  canShare.value = isAvailable;
  return isAvailable;
};

/** 初始化 LIFF */
const initializeLiff = async (): Promise<void> => {
  try {
    // 初始化 LIFF SDK
    await liff.init({ liffId: import.meta.env.VITE_LIFF_ID });

    // 檢查用戶登入狀態
    checkLoginStatus();

    // 驗證執行環境
    const isValidEnvironment = await validateEnvironment();
    if (!isValidEnvironment) {
      return;
    }

    // 檢查分享功能可用性
    checkShareAvailability();

  } catch (error) {
    console.error("LIFF 初始化失敗:", error);
    showResultMessage('初始化失敗', '請重新整理頁面', 'error');
  }
};

結果通知功能

當使用者刮開刮刮卡並抽中獎項時,系統會在顯示中獎訊息的同時,自動透過 LINE 聊天室發送通知訊息,讓使用者可以保存中獎記錄。

使用到的 LIFF API

  • liff.sendMessages():將中獎結果自動發送至當前 LINE 聊天室,訊息會顯示在與官方帳號的對話視窗中

App.vue script:

ts
/** 發送 LINE 訊息 */
const sendLineMessage = async (message: string): Promise<void> => {
  await liff.sendMessages([
    {
      type: "text",
      text: `🎉 ${message}\n感謝您參與我們的活動!`
    }
  ]);
};

/** 處理刮刮卡完成事件 */
const handleScratchComplete = async (data: { progress: number; message: string }): Promise<void> => {
  try {
    await sendLineMessage(data.message);
    showPrizeMessage(data.message);
  } catch (error) {
    console.error('處理完成訊息時發生錯誤:', error);
    showToast('操作失敗', '請稍後再試', 'error');
  }
};

社群分享機制

透過 LIFF SDK 將中獎訊息即時分享到 LINE 聊天室,提升活動的社群擴散效果。

使用到的 LIFF API

  • liff.shareTargetPicker():開啟 LINE 的分享選擇器,讓使用者可以主動選擇要分享的聊天室或好友。可以在分享訊息中包含 LIFF URL,當其他使用者點擊連結後,被引導加入對應的官方帳號並參與活動

在 shareTargetPicker 的 callback 函數中,應避免使用 alert()、confirm() 等會阻塞執行緒的方法,這可能導致 LIFF 在部分裝置上無法正常運作 。因此本次實作皆採用自訂組件來顯示提示訊息。

使用 shareTargetPicker 功能前,要確認以下兩項條件

  • 使用者必須已登入 LINE 帳號
  • 已在 LINE Developers 控制台的 LIFF 應用設定中啟用相關設定

shareTargetPicker 支援發送的訊息類型(這部分與 sendMessages 相同)

  • 六種基礎訊息:text、image、video、audio、location、sticker
  • Template Message:buttons、confirm、carousel、image carousel等樣板訊息
  • Flex Message:高度客製化訊息

只有 image、audio 及 video 訊息可以透過 external 參數標記來源為 LIFF

App.vue template:

html
  <div id="app">
    <!-- 刮刮樂組件 -->
    <ScratchCard @onCompleted="handleScratchComplete" />

    <!-- 中獎彈窗 -->
    <PrizeModal :show="showModal" :message="prizeMessage" :canShare="canShare" @share="handleShare"
      @close="handleClose" />

    <!-- 結果提示 -->
    <Toast :show="showToastVisible" :title="toastTitle" :text="toastText" :type="toastType" />
  </div>

App.vue script:

ts
/** 分享訊息到 LINE */
const shareToLine = async (message: string): Promise<void> => {
  const liffUrl = `https://liff.line.me/${import.meta.env.VITE_LIFF_ID}`;

  await liff.shareTargetPicker([
    {
      type: "text",
      text: message
    },
    {
      type: "template",
      altText: "刮刮卡活動邀請",
      template: {
        type: "buttons",
        text: "你也來挑戰刮刮卡吧!",
        actions: [
          {
            type: "uri",
            label: "立即參加抽獎",
            uri: liffUrl
          }
        ]
      }
    }
  ]);
};

/** 處理分享按鈕點擊事件 */
const handleShare = async () => {
  showModal.value = false;

  try {
    await shareToLine(prizeMessage.value);
    showToast('分享成功!', '訊息已分享到 LINE');
  } catch (error) {
    console.error('分享失敗:', error);
    showToast('分享失敗', '請稍後再試', 'error');
  } finally {
    closeLiffWindow(1500); // 延遲關閉視窗
  }
};

自動關閉流程

不論使用者是否完成分享,或是直接點擊關閉按鈕,系統都能順利關閉 LIFF 視窗並返回 LINE 聊天室,提供流暢的使用體驗。

使用到的 LIFF API

  • liff.closeWindow():關閉當前 LIFF 瀏覽器視窗,讓使用者返回 LINE 聊天室介面
ts
/** 關閉 LIFF 視窗 */
const closeLiffWindow = (delay: number = 2000): void => {
  setTimeout(() => {
    liff.closeWindow();
  }, delay);
};

LIFF 與官方帳號的連結配置

當需要重新觸發 LIFF 授權畫面時,可以透過以下步驟取消既有的應用程式連結

  • 開啟 LINE 應用程式
  • 前往「主頁」→「設定」→「我的帳號」
  • 點選「連結中的應用程式」
  • 找到已綁定 LINE Login 的頻道並取消連結

完成上述步驟後,下次點選 LIFF 連結時就會重新顯示授權畫面。

LINE Login 頻道綁定官方帳號

在 LINE Developers Console 中,將 Login 頻道與 LINE 官方帳號進行綁定,建立兩者之間的關聯性。

LIFF 應用程式加好友選項

在 LIFF 應用程式設定中,可以配置「加好友選項」(Add friend option),讓使用者在授權時可以同步加入官方帳號為好友。

LIFF 授權畫面呈現

啟用 LIFF 選項後,使用者在首次開啟 LIFF 應用時,授權畫面會顯示「加入好友」的選項,讓使用者可以一併將官方帳號加為好友。

透過這些設定,可以在使用者首次開啟 LIFF 應用時,引導他們加入官方帳號,有助於提升官方帳號的好友數量與後續互動機會。

分享 LIFF 網頁前的狀態檢查

在 LINE Developers 控制台選擇對應的 LIFF 進行設定

Developing 狀態

  • 無法分享給其他用戶
  • 僅供開發者測試使用

Published 狀態

  • 可分享給其他用戶
  • 發布後無法切回 Developing 狀態

本日結語

相對於昨天的基礎應用,今天的實作聚焦在單一完整的互動功能上。這個刮刮卡應用可以直接整合到 LINE 圖文選單中,讓使用者點擊後立即參與抽獎,刮開後的中獎結果會自動發送到聊天室,創造即時且有趣的互動體驗。

留言

留言使用 GitHub 帳號登入(Giscus),留言會存在 GitHub Discussions。