# LIFFアプリを開発する

LIFFアプリは、HTMLやJavaScriptで構成されるウェブアプリです。ここでは、LIFFアプリを開発する手順とLIFFアプリ特有の処理について説明します。

# LIFFアプリのタイトルを設定する

LIFFアプリのタイトルは、LIFFアプリのタイトルバーに表示されます。 LIFFアプリのHTMLソースの<title>要素に、LIFFアプリのタイトルを指定します。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>タイトル</title>

# LIFFアプリにLIFF SDKを組み込む

LIFFアプリには、以下の2種類の方法でLIFF SDKを組み込めます。

# CDNパスを指定する

LIFF SDKで提供する機能を利用するには、LIFFアプリのHTMLソースの<script>要素のsrc属性に、LIFF SDKのCDNパスを指定します。 LIFFでは、以下の2種類のCDNパスを用意しています。目的に合ったCDNパスを指定してください。

CDNパス 説明
CDNエッジパス メジャーバージョンのみを含むCDNパスです。常に最新の機能を使用する場合は、このCDNパスを使用します。メジャーバージョンがアップデートされたときのみURLを更新する必要があります。
例:https://static.line-scdn.net/liff/edge/2/sdk.js
CDN固定パス パッチバージョンまで含むCDNパスです。特定のバージョンの機能を使用する場合は、このCDNパスを使用します。LIFFアプリを更新しない限り、指定したパッチバージョンを使い続けることができます。LIFFの新機能や、セキュリティ改善、バグ修正を反映したいときのみURLを更新してください。自動的に更新されないため、LIFF SDKのアップデートの影響を受けません。
例:https://static.line-scdn.net/liff/edge/versions/2.22.3/sdk.js
どのバージョンを使うべきか

CDN固定パスを使用している開発者は、LIFFアプリを更新するタイミングを決める必要があります。アップデートの内容を正しく理解し、自分のLIFFアプリに適しているか判断するために、『LIFFドキュメント』の「リリースノート」をこまめに確認してください。

CDN固定パスを指定する例:

<script charset="utf-8" src="https://static.line-scdn.net/liff/edge/versions/2.22.3/sdk.js"></script>
LIFF SDKはUTF-8で書かれています

LIFF SDKはUTF-8で書かれているため、HTMLソースをUTF-8以外の文字コードで作成する場合は、charset="utf-8"をあわせて指定してください。

# npmパッケージを利用する

LIFFでは、npmパッケージも公開しています。npmを利用して、LIFF SDKをインストールすることもできます。

SDKバージョンを管理してください

適切なSDKバージョンを使用することは開発者の責任です。SDKバージョンを最新の状態に保つために、LIFFリリースノートを定期的に確認し、ローカルのSDKを頻繁に更新してください。LIFFのバージョニングポリシーの詳細は『LIFF SDK(sdk.js)のアップデートポリシー』を参照してください。

webpack v5を使ったプロジェクトでLIFF v2.16.0以前のnpm版を使用すると、ビルド時にエラーが発生します

webpack v5から、Node.jsのポリフィルが削除されました。 (opens new window)その影響により、webpack v5を使ったプロジェクトでLIFF v2.16.0以前のnpm版を使用すると、ビルド時にエラーが発生します。詳しくは、2021年10月26日のニュース、「LIFF v2.16.1をリリースしました」を参照してください。

LIFF SDKをnpmでインストールし、アプリに組み込むための手順は、以下のとおりです。

  1. 以下のコマンドをターミナルで実行し、npmでLIFF SDKをインストールしてください。

    $ npm install --save @line/liff
    

    あるいは、以下のコマンドをターミナルで実行し、YarnでLIFF SDKをインストールすることもできます。

    $ yarn add @line/liff
    
  2. SDKをアプリに組み込む

    JavaScriptまたはTypeScriptファイルに以下のコードを組み込んでください。

    import liff from '@line/liff';
    
    liff.init({
        liffId: '1234567890-AbcdEfgh', // Use own liffId
    });
    

    TypeScriptの型の定義は@line/liffパッケージに含まれています。

    window.liff を宣言および編集しないでください

    下位互換性を維持するため、グローバルLIFFインスタンスのwindow.liffを宣言および編集しないでください。LINEが正常に動作しなくなる可能性があります。

関連ページ:https://www.npmjs.com/package/@line/liff (opens new window)

LIFF SDKのファイルサイズを削減する

プラガブルSDKを使うと、LIFF SDKのファイルサイズを削減できます。詳しくは、「プラガブルSDK」を参照してください。

# LIFF APIを呼び出す

LIFF SDKを組み込むと、以下の操作を実行できます。

# LIFFアプリを初期化する

liff.init()メソッドを実行すると、LIFFアプリが初期化され、LIFFアプリからLIFF SDKのほかのメソッドを実行できるようになります。

LIFFアプリのクエリパラメータについて

LIFF URLへのアクセス時やLIFF間遷移時などに、URLに liff.* のようなクエリパラメータが付与されることがあります。

例:

  • liff.state(LIFF URLに指定した追加情報を示す)
  • liff.referrer(LIFF間遷移前のURLを示す。詳しくは、「LIFF間遷移前のURLを取得する」を参照してください)

上記は、LIFFアプリを正常に動作させるために、SDK側から付与されるクエリパラメータです。 LIFFアプリのURLに独自の処理を行う場合は、LIFFアプリの起動やLIFF間遷移などLIFFアプリの正常な動作を保証するため、liff.initがresolveされるまでliff.*のクエリパラメータを変更しないように設計してください。

LIFFアプリを初期化する前でも実行できるメソッド

以下のプロパティおよびメソッドは、liff.init()メソッドを実行する前でも利用できます。 LIFFアプリを初期化する前にLIFFアプリを動作させている環境を取得したり、LIFFアプリ初期化に失敗した際にLIFFアプリを閉じたりできます。

liff.closeWindow()メソッドは、LIFF SDKバージョンが2.4.0以上の場合のみ、liff.init()によるLIFFアプリの初期化が終了する前でも実行できます。

外部ブラウザでのLIFFアプリ初期化時にliff.login()メソッドを自動で実行するには

liff.init()メソッドのconfigオブジェクトのwithLoginOnExternalBrowserプロパティにtrueを指定することで、外部ブラウザでのLIFFアプリ初期化時に、liff.login()メソッドを自動で実行できます。

liff.init({
    liffId: '1234567890-AbcdEfgh', // Use own liffId
    withLoginOnExternalBrowser: true, // Enable automatic login process
}).then(() => {
    // Start to use liff's api
});

liffIdに指定するLIFFアプリIDは、LIFFアプリをチャネルに追加すると取得できます。詳しくは、「LIFFアプリをチャネルに追加する」を参照してください。

liff.init({
    liffId: '1234567890-AbcdEfgh', // Use own liffId
})
    .then(() => {
        // start to use LIFF's api
    })
    .catch((err) => {
        console.log(err);
    });

なお、liff.readyで、LIFFアプリ起動後、liff.init()の実行が初めて終了したときにresolveするPromiseオブジェクトを取得できます。

詳しくは、『LIFF v2 APIリファレンス』の「liff.init()」および「liff.ready」を参照してください。

LIFFアプリ初期化時の注意事項
  • liff.init()メソッドは、1次リダイレクト先URLに付与されるliff.stateaccess_token=xxxなどの情報を元に初期化処理を行います。エンドポイントURLにクエリパラメータやパスが含まれている場合、正しくLIFFアプリを初期化するために、1次リダイレクト先URLと2次リダイレクト先URLで、1回ずつliff.init()メソッドを実行してください。リダイレクトについて詳しくは、「LIFF URLにアクセスしてからLIFFアプリが開くまでの動作について」を参照してください。

  • liff.init()メソッドが返すPromiseオブジェクトがresolveする前に、サーバーやフロントエンド側の処理などでURLを変更しないようにしてください。URLを変更すると、INIT_FAILEDが返され、LIFFアプリを開けません。たとえば、liff.init()実行後にlocation.replace()などでリダイレクトする場合は、Promiseオブジェクトがresolveされてから画面遷移するように設計してください。

    liff.init({
        liffId: '1234567890-AbcdEfgh', // Use own liffId
    }).then(() => {
        // Redirect to another page after the returned Promise object has been resolved
        window.location.replace('https://liff.line.me/1234567890-AbcdEfgh/path');
    });
    
  • liff.stateが含まれる1次リダイレクト先URLは、liff.init()実行時に2次リダイレクト先URLへリダイレクトされます。liff.init()実行前の1次リダイレクト先URLにはユーザーのアクセストークンなどの機密情報が含まれるため、Google Analyticsなど外部のロギングツールにURLの情報を送らないように注意してください。
    なお、LIFF v2.11.0以降のバージョンでは、liff.init()がresolveされたタイミングでURLから機密情報が除外されます。そのため、以下のようにthen()メソッド内でページビューを送信することで、機密情報の漏洩を防ぐことができます。ロギングツールを利用する場合は、LIFFアプリをv2.11.0以降にバージョンアップすることをお勧めします。LIFF v2.11.0の更新内容について詳しくは、『LIFFドキュメント』の「リリースノート」を参照してください。

    liff.init({
        liffId: '1234567890-AbcdEfgh', // Use own liffId
    }).then(() => {
        ga('send', 'pageview');
    });
    

# 外部ブラウザでLINEログインを利用する場合

外部ブラウザでLINEログインを利用する場合は、以下のとおりliff.init()メソッドを2回実行します。

  1. LIFF SDKロード後に、liff.init()メソッドを実行します。

  2. liff.login()メソッドを実行し、認証ページおよび認可画面の処理が終了すると、LIFFアプリ(redirectUri)にリダイレクトされます。そこで、改めてliff.init()メソッドを実行します。

    liff.init()メソッドの処理中にエラーが発生した場合、またはログイン時にユーザーが認可をキャンセルした場合は、errorCallbackが実行されます。

フロー図

LIFFブラウザ内での認可リクエストについて

LIFFブラウザ内でLINEログインによる認可リクエストを行った際の動作は保証されません。また、LIFFアプリを外部ブラウザやLINE内ブラウザで開く場合には、必ずliff.login()メソッドでログイン処理を行い、LINEログインによる認可リクエストは行わないでください。

# LIFFアプリが動作している環境を取得する

liff.isInClient()メソッドやliff.getOS()メソッドなどを実行して、LIFFアプリが動作している環境を取得します。

// print the environment in which the LIFF app is running
console.log(liff.getLanguage());
console.log(liff.getVersion());
console.log(liff.isInClient());
console.log(liff.isLoggedIn());
console.log(liff.getOS());
console.log(liff.getLineVersion());

詳しくは、『LIFF APIリファレンス』の各メソッドを参照してください。

# ログイン処理を行う

外部ブラウザおよびLINE内ブラウザの場合、liff.login()メソッドを実行して、ログイン処理を行います。

注意

LIFFブラウザの場合、liff.init()実行時に自動でログイン処理が実行されるため、liff.login()は利用できません。

liff.init()メソッド実行時にwithLoginOnExternalBrowserプロパティをtrueにした場合

liff.init()メソッドのwithLoginOnExternalBrowserプロパティをtrueに指定した場合、外部ブラウザでもLIFFアプリ初期化時にliff.login()メソッドを自動で実行することができます。詳しくは、『LIFF APIリファレンス』の「liff.init()」を参照してください。

// login call, only when external browser or LINE's in-app browser is used
if (!liff.isLoggedIn()) {
    liff.login();
}

また、liff.logout()メソッドを実行して、ログアウトすることもできます。

// logout call only when external browse or LINE's in-app browser is used
if (liff.isLoggedIn()) {
    liff.logout();
    window.location.reload();
}

詳しくは、『LIFF v2 APIリファレンス』の「liff.login()」および「liff.logout()」を参照してください。

# URLを開く

liff.openWindow()メソッドを実行して、指定したURLをLINE内ブラウザまたは外部ブラウザで開きます。

以下のコードはhttps://line.meを外部ブラウザで開きます。

// openWindow call
liff.openWindow({
    url: 'https://line.me',
    external: true,
});

詳しくは、『LIFF v2 APIリファレンス』の「liff.openWindow()」を参照してください。

# 二次元コードリーダーを表示する

liff.scanCodeV2()メソッドを実行して、二次元コードリーダーを起動し、ユーザーが読み取った文字列を取得します。

// scanCodeV2 call
liff.scanCodeV2()
    .then((result) => {
        // e.g. result = { value: 'Hello LIFF app!' }
    })
    .catch((err) => {
        console.log(err);
    });

詳しくは、『LIFF APIリファレンス』の「liff.scanCodeV2()」を参照してください。

liff.scanCode()メソッドは非推奨です

従来のliff.scanCode()メソッドは非推奨になります。二次元コードリーダーを実装する場合は、liff.scanCodeV2()メソッドを使用することをお勧めします。

liff.scanCode2()メソッドの動作環境

liff.scanCodeV2()メソッドは以下の環境で動作します。

  • iOS:iOS14.3以降
  • Android:すべてのバージョン
  • 外部ブラウザ:WebRTC API (opens new window) をサポートするウェブブラウザ
OS バージョン LIFFブラウザ 外部ブラウザ
iOS 11〜14.2 ✅ ※1
14.3以降 ✅ ※2 ✅ ※1
Android すべてのバージョン ✅ ※2 ✅ ※1
PC すべてのバージョン ✅ ※1

※1 WebRTC API (opens new window)をサポートするウェブブラウザのみ利用できます。

※2 LIFFブラウザの画面サイズがFullの場合のみ利用できます。詳しくは、『LIFFドキュメント』の「LIFFブラウザの画面サイズ」を参照してください。

二次元コードリーダーを起動するには[Scan QR]をオンにしてください

LIFFアプリをチャネルに追加するときに、[Scan QR]をオンにしてください。[Scan QR]の設定は、LIFFアプリ追加後もLINE DevelopersコンソールのLIFFタブで変更できます。

# LIFFアプリが起動された画面を取得する

liff.getContext()メソッドを実行して、LIFFアプリが起動された画面(1対1のトーク、グループトーク、複数人トーク、または外部ブラウザ)に関する情報を取得します。

const context = liff.getContext();
console.log(context);
// {"type": "utou", "userId": "U70e153189a29f1188b045366285346bc", "viewType": "full", "accessTokenHash": "ArIXhlwQMAZyW7SDHm7L2g", "availability": {"shareTargetPicker": {"permission": true, "minVer": "10.3.0"}, "multipleLiffTransition": {"permission": true, "minVer": "10.18.0"}}}

詳しくは、『LIFF v2 APIリファレンス』の「liff.getContext()」を参照してください。

# ユーザーのプロフィールを取得する

LIFFアプリでIDトークンを取得して、ユーザーのプロフィールを取得する方法は2つあります。 目的に合わせて正しく使い分けてください。

スコープを選択してください

LIFFアプリをチャネルに追加するときに、openidスコープを選択してください。スコープを選択しなかった場合やユーザーが認可しなかった場合は、IDトークンを取得できません。スコープの選択は、LIFFアプリ追加後もLINE DevelopersコンソールのLIFFタブで変更できます。

メールアドレスを取得できます

LIFFアプリをチャネルに追加するときに、emailスコープを選択し、ユーザーが認可すると、メールアドレスも取得できます。スコープの選択は、LIFFアプリ追加後もLINE DevelopersコンソールのLIFFタブで変更できます。

# サーバーに送信するために取得する

LIFFアプリからサーバーにユーザー情報を送信する場合は、以下の方法で取得したアクセストークンまたはIDトークンを送信します。 サーバーでユーザー情報を使用する方法について詳しくは、「LIFFアプリおよびサーバーでユーザー情報を使用する」を参照してください。

  • liff.getAccessToken()メソッドを実行して、現在のユーザーのアクセストークンを取得します。なお、ユーザーがLIFFアプリを閉じると、有効期限が切れていなくてもアクセストークンは無効化されます。

    // get access token
    if (!liff.isLoggedIn() && !liff.isInClient()) {
        window.alert('To get an access token, you need to be logged in. Tap the "login" button below and try again.');
    } else {
        const accessToken = liff.getAccessToken();
        console.log(accessToken);
    }
    

    詳しくは、『LIFF v2 APIリファレンス』の「liff.getAccessToken()」を参照してください。

  • liff.getIDToken()メソッドを実行して、「現在のユーザーの生のIDトークン」を取得します。

    liff.init(() => {
        const idToken = liff.getIDToken();
        console.log(idToken); // print raw idToken object
    });
    

    詳しくは、『LIFF v2 APIリファレンス』の「liff.getIDToken()」を参照してください。

# LIFFアプリで使用するために取得する

liff.getDecodedIDToken()メソッドを実行して、現在のユーザーのプロフィール情報およびメールアドレスを取得します。

LIFFアプリでユーザーの表示名などを利用する場合に、このAPIを利用してください。

ユーザー情報をサーバーに送信しないでください

liff.getDecodedIDToken()で取得したユーザー情報をサーバーに送信しないでください。 代わりに、liff.getIDToken()で取得したIDトークンを送信します。

liff.init(() => {
    const idToken = liff.getDecodedIDToken();
    console.log(idToken); // print decoded idToken object
});

詳しくは、『LIFF v2 APIリファレンス』の「liff.getDecodedIDToken()」を参照してください。

# ユーザーとLINE公式アカウントの友だち関係を取得する

ユーザーと、LIFFアプリが追加されているLINEログインのチャネルにリンクされているLINE公式アカウントの友だち関係を取得します。

LINEログインのチャネルにLINE公式アカウントをリンクする方法については、『LINEログインドキュメント』の「LINEログインしたときにLINE公式アカウントを友だち追加する(友だち追加オプション)」を参照してください。

liff.getFriendship().then((data) => {
    if (data.friendFlag) {
        // something you want to do
    }
});

詳しくは、『LIFF v2 APIリファレンス』の「liff.getFriendship()」を参照してください。

スコープを選択してください

LIFFアプリをチャネルに追加するときに、profileスコープを選択してください。スコープを選択しなかった場合やユーザーが認可しなかった場合は、友だち関係を取得できません。スコープの選択は、LIFFアプリ追加後もLINE DevelopersコンソールのLIFFタブで変更できます。

liff.permanentLink.createUrlBy()メソッドを実行して、LIFFアプリの任意のページのパーマネントリンクを取得できます。

// For example, if the endpoint URL of the LIFF app is https://example.com/path1?q1=v1 and its LIFF ID is 1234567890-AbcdEfgh
liff.permanentLink
  .createUrlBy('https://example.com/path1?q1=v1')
  .then((permanentLink) => {
    // https://liff.line.me/1234567890-AbcdEfgh
    console.log(permanentLink);
  });

liff.permanentLink
  .createUrlBy('https://example.com/path1/path2?q1=v1&q2=v2')
  .then((permanentLink) => {
    // https://liff.line.me/1234567890-AbcdEfgh/path2?q=2=v2
    console.log(permanentLink);
  });

詳しくは、『LIFF v2 APIリファレンス』の「liff.permanentLink.createUrlBy()」を参照してください。

# 現在のトークルームにメッセージを送信する

liff.sendMessages()メソッドを実行して、ユーザーの代わりに、LIFFアプリが開かれているトークルームにメッセージを送信します。1回のリクエストでメッセージオブジェクトを最大5つまで送信できます。

以下のコードは、LIFFアプリが表示されているトークルームに、ユーザーのメッセージとして「Hello, World!」を送信します。

liff
  .sendMessages([
    {
      type: "text",
      text: "Hello, World!",
    },
  ])
  .then(() => {
    console.log("message sent");
  })
  .catch((err) => {
    console.log("error", err);
  });

詳しくは、『LIFF APIリファレンス』の「liff.sendMessages()」を参照してください。

# ユーザーの友だちにメッセージを送信する(シェアターゲットピッカー)

liff.shareTargetPicker()メソッドを実行して、ターゲットピッカー(グループまたは友だちを選択する画面)を表示し、ターゲットピッカーで選択した相手に、開発者が作成したメッセージを送信します。このメッセージは、ユーザーが送信したかのように、グループまたは友だちに表示されます。

target picker

以下のコードは、ターゲットピッカーを表示し、選択したグループまたは友だちに、ユーザーのメッセージとして「Hello, World!」を送信します。 あらかじめ、liff.isApiAvailable()メソッドを実行すると、LIFFアプリを起動した環境でターゲットピッカーが使用可能であることを確認できます。

if (liff.isApiAvailable('shareTargetPicker')) {
    liff.shareTargetPicker([
        {
            type: 'text',
            text: 'Hello, World!',
        },
    ]);
}

詳しくは、『LIFF v2 APIリファレンス』の「liff.isApiAvailable()」および「liff.shareTargetPicker()」を参照してください。

注意

# LIFFアプリを閉じる

liff.closeWindow()メソッドを実行して、開いているLIFFアプリを閉じます。

// closeWindow call
if (!liff.isInClient()) {
    window.alert('This button is unavailable as LIFF is currently being opened in an external browser.');
} else {
    liff.closeWindow();
}

詳しくは、『LIFF v2 APIリファレンス』の「liff.closeWindow()」を参照してください。

注意

liff.closeWindow()の外部ブラウザでの動作は、保証対象外です。

# OGPタグを設定する

LIFFアプリの各ページにOGPタグを設定すると、たとえばLINEのトークルームでLIFFアプリのURL(https://liff.line.me/{liffId})をシェアしたときに、任意のタイトルや説明文、サムネイル画像を表示できます。

LIFFで対応しているOGPタグは以下のとおりです。 OGPタグについて詳しくは、「The Open Graph protocol (opens new window)」を参照してください。

<html lang="ja" prefix="og: http://ogp.me/ns#">
<meta property="og:title" content="タイトル">
<meta property="og:type" content="`website`、`blog`、または`article`">
<meta property="og:description" content="ページの簡単な説明">
<meta property="og:url" content="ページのURL">
<meta property="og:site_name" content="サイト全体を表す名前">
<meta property="og:image" content="サムネイル画像のURL">
注意

LIFFアプリのURLを、line://app/{liffId}(非推奨)の形式でシェアしたときは、OGPタグは無視されます。

# LIFFアプリではない外部のサイトに遷移した場合(LINEバージョン12.13.0以降のみ)

LINEのバージョン12.13.0以降のLIFFブラウザでは、LIFFアプリからLIFFアプリでない外部サイトを開いた場合、「外部サイトに遷移した」ということを示すポップアップが表示されます。

外部サイトに遷移した時のポップアップ

ポップアップは、同じウィンドウで外部サイトを開いた場合にのみ表示されます。別のウィンドウで外部サイトを開いた場合は、ポップアップは表示されません。

LIFFアプリのエンドポイントURLより上の階層への遷移

LIFFアプリで、エンドポイントURL(例:https://example.com/path)より上の階層(例:https://example.com/)へ遷移した際の動作は保証されません。

# 次のステップ

LIFFアプリを開発したら、任意のサーバーにデプロイしてください。デプロイ後は、以下の操作を行います。

  1. LIFFアプリをチャネルに追加する
  2. LIFFアプリを開く