はじめに
今回は、LINEを使ったアプリ開発をする際の、LIFFの導入手順をまとめてみました。
少しでも参考になれば幸いです。
前提
・すでにLIFFアプリは作成済みであることを前提とさせていただきます。
・開発環境はDockerを使用していることを前提とさせていただきます。
開発用LIFFアプリの作成手順は、こちらの記事がわかりやすく参考になるかと思います。
また、今回はフレームワークにNuxt4を使用しています。
Nuxtの導入手順に関してはこちらをご参照ください。
Dockerの導入手順はこちらの記事をご参照ください。
1. @line/liff SDKをインストール
まずは必要なパッケージをインストールします。
環境差異を防ぐためコンテナ内で行います。
以下のコマンドを順に実行します。
// 開発コンテナを起動します
docker compose up --build
// コンテナへ入ります
// (別のターミナルを開き、プロジェクトディレクトリへ移動)
// Alpineベースでbashが無いならshが一般的です
docker compose exec {対象のコンテナ(サービス)名} sh
// インストールします
pnpm add @line/liff
// コンテナから出ます
exit
2. .env.exampleの追加
プロジェクトルートに以下の.env.exampleを追加し、.envファイルのヒントを示します。
# LIFF (LINE Front-end Framework) ID
# LINE Developers Console > LIFF タブで発行した値を入れる
NUXT_PUBLIC_LIFF_ID=YOUR_LIFF_ID_HERE
NUXT_PUBLIC_LIFF_IDは、LIFF SDKが「どの LIFF アプリを初期化するか」を識別するために必要になります。
3. nuxt.config.tsの更新
nuxt.config.tsに以下の記述を追加します。
runtimeConfig: {
public: {
liffId: process.env.NUXT_PUBLIC_LIFF_ID || '',
},
},
runtimeConfig:には「アプリ実行時に利用する環境変数」を定義します。
public:はクライアント側(ブラウザ側)からも参照可能にする設定です。
4. liffプラグインの作成
以下のような、app/plugins/liff.client.tsを作成します。
// ============================================================
// LINE Front-end Framework (LIFF) SDK を読み込み
// ============================================================
// @line/liff は LINE公式のフロントエンドSDKです。
// LINEアプリ内ブラウザとの連携機能を提供します。
//
// 例:
// - ログイン状態確認
// - ユーザープロフィール取得
// - LINEログイン
// - ID Token取得
// - LINE内ブラウザ判定
//
// 公式:
// https://developers.line.biz/ja/docs/liff/overview/
// ============================================================
import liff from '@line/liff'
// ============================================================
// Nuxt Plugin 定義
// ============================================================
// defineNuxtPlugin() は Nuxt 起動時に実行される
// プラグインを定義する関数です。
//
// plugins/liff.client.ts
// のように .client.ts にすることで、
// クライアント側(ブラウザ側)のみで実行されます。
//
// LIFF SDK は window/document を使用するため、
// SSR(Node.js側)では実行できません。
// ============================================================
export default defineNuxtPlugin(async () => {
// ==========================================================
// Runtime Config 取得
// ==========================================================
// useRuntimeConfig() は nuxt.config.ts の
// runtimeConfig を取得する Nuxt公式Composableです。
//
// nuxt.config.ts 例:
//
// runtimeConfig: {
// public: {
// liffId: process.env.NUXT_PUBLIC_LIFF_ID || '',
// },
// }
//
// public 配下はクライアント側でも参照可能です。
// ==========================================================
const config = useRuntimeConfig()
// ==========================================================
// LIFF ID 取得
// ==========================================================
// 環境変数から LIFF ID を取得します。
//
// .env 例:
// NUXT_PUBLIC_LIFF_ID=2001234567-abcdefgh
//
// LIFF ID は LINE Developers コンソールで発行されます。
// ==========================================================
const liffId = config.public.liffId
// ==========================================================
// LIFF ID 未設定チェック
// ==========================================================
// LIFF ID が未設定の場合は
// liff.init() を実行できないため、
// 初期化をスキップします。
//
// これにより:
// - 開発環境
// - CI
// - 一部Preview環境
//
// などでもアプリがクラッシュしません。
// ==========================================================
if (!liffId) {
// ========================================================
// 開発者向け警告ログ
// ========================================================
console.warn('[LIFF] NUXT_PUBLIC_LIFF_ID is not set. Skipping liff.init().')
// ========================================================
// Nuxtへ liff を注入
// ========================================================
// provide すると:
//
// const { $liff } = useNuxtApp()
//
// のように全体で利用可能になります。
//
// init未実行でも $liff 自体は存在するため、
// 型エラーや参照エラーを防げます。
// ========================================================
return {
provide: { liff },
}
}
// ==========================================================
// LIFF 初期化
// ==========================================================
// liff.init() は LIFF SDK の初期化処理です。
//
// 内部的には:
// - LINEアプリとの接続
// - LIFFセッション開始
// - ID Token管理
// - ログイン状態確認
//
// などを行います。
//
// 公式:
// https://developers.line.biz/ja/reference/liff/#initialize-liff-app
// ==========================================================
try {
// ========================================================
// LIFF SDK 初期化実行
// ========================================================
await liff.init({ liffId })
} catch (error) {
// ========================================================
// 初期化失敗時
// ========================================================
// 例えば:
// - LIFF ID誤り
// - Endpoint URL不一致
// - 通信エラー
// - LINE外ブラウザ問題
//
// など。
//
// try-catch により
// アプリ全体のクラッシュを防止します。
// ========================================================
console.error('[LIFF] liff.init() failed', error)
}
// ==========================================================
// Nuxt全体へ liff を注入
// ==========================================================
// これにより:
//
// const { $liff } = useNuxtApp()
//
// でアクセス可能になります。
//
// Vue Component 例:
//
// const { $liff } = useNuxtApp()
//
// if ($liff.isLoggedIn()) {
// const profile = await $liff.getProfile()
// }
// ==========================================================
return {
provide: { liff },
}
})
// ============================================================
// TypeScript 型拡張
// ============================================================
// NuxtApp に $liff を追加します。
//
// これを書かない場合:
//
// Property '$liff' does not exist on type 'NuxtApp'
//
// のような型エラーになります。
// ============================================================
declare module '#app' {
interface NuxtApp {
// ========================================================
// typeof liff
// ========================================================
// importした liff オブジェクトそのものの型を利用。
//
// これにより:
//
// $liff.login()
// $liff.logout()
// $liff.getProfile()
//
// などが完全に型補完されます。
// ========================================================
$liff: typeof liff
}
}
このプラグインはブラウザ起動時に(アプリケーションレベルで)1回だけ呼ばれます。
(ページ遷移時は呼ばれず、画面リロード時には呼ばれます)
ブラウザアクセス
↓
Nuxt起動
↓
Plugin実行
↓
await liff.init()
↓
provide
↓
Page Component表示
5. app.vue(トップページ)の実装
最後に、トップページをデフォルトのNuxt Welcome画面からカスタマイズしていきます。
app.vueを以下の内容で上書きします。
<script setup lang="ts">
const { $liff } = useNuxtApp()
const config = useRuntimeConfig()
const isReady = ref(false)
const isInClient = ref(false)
const initError = ref<string | null>(null)
onMounted(() => {
if (!config.public.liffId) {
initError.value = 'LIFF ID が未設定です。.env の NUXT_PUBLIC_LIFF_ID を設定してください。'
isReady.value = true
return
}
isInClient.value = $liff.isInClient()
isReady.value = true
})
const openInLine = () => {
if (!config.public.liffId) return
window.location.href = `https://liff.line.me/${config.public.liffId}`
}
</script>
<template>
<ClientOnly>
<div v-if="isReady">
<div v-if="initError" class="liff-error">
<p>{{ initError }}</p>
</div>
<div v-else-if="isInClient" class="liff-app">
<p>Hello from my-app</p>
</div>
<div v-else class="liff-guide">
<h1>LINEアプリで開いてください</h1>
<p>
このコンテンツは LINE 内の LIFF アプリでのみご利用いただけます。<br>
下のボタンをタップして LINE で開いてください。
</p>
<button type="button" class="liff-guide__button" @click="openInLine">
LINEで開く
</button>
</div>
</div>
<template #fallback>
<p>読み込み中...</p>
</template>
</ClientOnly>
</template>
<style scoped>
.liff-guide {
max-width: 480px;
margin: 40px auto;
padding: 24px;
text-align: center;
}
.liff-guide__button {
margin-top: 16px;
padding: 12px 24px;
font-size: 16px;
background-color: #06c755;
color: #fff;
border: none;
border-radius: 6px;
cursor: pointer;
}
.liff-error {
max-width: 480px;
margin: 40px auto;
padding: 16px;
color: #c00;
text-align: center;
}
</style>
<template>内の<ClientOnly>は、Nuxtで「この中のコンポーネントはクライアント(ブラウザ)側だけで描画する」という意味です。
NuxtはデフォルトでSSR(サーバーサイドレンダリング)に対応していますが、以下のようなブラウザ専用コード
window.~, localStorage.~
を書くとSSR時にエラーになってしまうため、使用します。
同様に、<script>内のonMounted(() => {もブラウザでしか実行されないため、
console.log(window.location.href)などはonMounted内で実行するようにします。
<ClientOnly>とonMountedを上手に使うことが、NuxtのSSR対応には必要です。(設定でssrはオフにできます)
各行の詳しい内容は割愛しますが、気になった方はAIに質問してみてください。
6. 実際にLINEでアクセスしてみる
最後に実際にLINEでアクセスしてみます。
① .envの作成
プロジェクトルートに.envを作成します。
NUXT_PUBLIC_LIFF_ID=YOUR_LIFF_ID_HERE
② LIFFアプリのエンドポイントURLを登録
長くなってしまうためこの記事では省略しますが、こちらの記事がわかりやすいのでご参照ください。
③ アプリを起動し、LINEでアクセスする。
以下のコマンドを実行し、アプリを起動します(Docker使用時の例)
docker compose up --build
LIFF URL(以下の例)
(例)https://liff.line.me/2001234567-asdfghjk
を以下のサイトでQRコードにして、LINEのカメラで読み込むと、無事に表示されているかと思います。