1
/
5

LIFFを利用したユーザー体験の向上

こんにちは。エンジニアの佐々木です。最近アイスの実ばかり食べています。

Linc’wellは医療・ヘルスケアに関する複数のプロダクトを開発しており、その中で最近リリースしたのが「sai+ダイアリー」と呼ばれるプロダクトです。

sai+ダイアリーは、Linc’wellが持つ女性向けD2Cブランドの「sai+」を補完するためのプロダクトで、現在は女性の生理管理のための機能を提供しています。今後はピルの服用記録機能や医師との連絡機能を追加し、将来的には女性の健康をトータルサポートするプロダクトを目指しています。

sai+ダイアリーは、フロントエンドがTypeScriptとNext.jsを利用したSPAとなっており、Apollo ClientでGraphQLのAPIを呼んでいます。APIサーバーはRuby on Railsで作成しています。シンプルな構成のSPAですが、ターゲット層のユーザーのほとんどがLINEを利用することを考慮してLIFFと呼ばれる技術を採用しています。

恥ずかしながら最近までLIFFの存在を知りませんでしたが、実際に使ってみると容易にLINE上で動くアプリケーションを作成でき、またユーザーの体験も向上させることができました。本記事では、LIFFの概要やメリット、具体的な利用例を紹介します。

LIFFとは

LIFFはLINE Front-end Frameworkの略で、LINE社が提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。

LINE Front-end Framework
LINE Front-end Framework(LIFF)は、LINEが提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。 ...
https://developers.line.biz/ja/docs/liff/overview/

アプリと聞くと身構える方もいるかもしれませんが、既存のウェブサイトのURLをLINE Developersコンソール画面で登録するだけでLIFFアプリになります。LINEでLIFFアプリのURLを開くことで、LIFFブラウザと呼ばれるWebViewを利用したブラウザでアプリケーションが開かれます。LIFFアプリはLIFF SDKが提供するAPIを利用でき、そのAPIを通じてLINEに登録したユーザーの情報やデバイスの情報の取得、LINEのアクション(投稿、カメラ起動、シェア等)を実行できます。

sai+ダイアリーでLIFFを利用する最大の目的は、シームレスな認証のためです。ユーザー登録やログインにおけるユーザーの離脱をなるべく避けるために、体験の良い認証を実現する必要がありました。LIFFを利用することで、ユーザーから見るとLINEログインすら必要がなくなり、アプリケーションを立ち上げると自動でログインしているように見えます。

LIFFは起動時にSDKがLINEログインを自動で行い、アクセストークンやIDトークンを取得します。sai+ダイアリーではここで取得したIDトークンを利用し、API認証を行っています。LIFFのIDトークンは有効期限が1時間であり、有効期限が切れた際にはAPI認証が通らなくなります。そのため、sai+ダイアリーではIDトークンの有効期限が切れたタイミングでアプリケーションを一度閉じて、再度開いてもらうようにユーザーに促しています。アプリを1時間開きっぱなしというユースケースが想定されなかったため、上記の解決策でも問題ないと判断しました。

以下はLIFFアプリを開いてから実際にサーバーで認証するまでのシーケンス図で、このフローに沿って認証を行っています。

LIFFアプリおよびサーバーでユーザー情報を使用する
ユーザーが、LIFFブラウザでLIFFアプリを起動したり、外部ブラウザでLIFFアプリを起動して liff.init メソッドでログイン処理を行ったりすると、LIFFアプリはユーザーのプロフィール(ユーザーID、表示名、プロフィール画像、メールアドレス)を取得できます。 LIFFアプリで、これらのユーザー情報を正しく処理しないと、なりすましやその他の種類の攻撃に対して脆弱になります。 ...
https://developers.line.biz/ja/docs/liff/using-user-profile/#use-user-info-on-server


LIFFのAPIでできることの例として以下のようなものがあります。

ユーザー情報の取得

クライアント側で以下のような情報を取得できます。

  • LINEユーザーID
  • ユーザー名
  • プロフィール画像URL
  • メールアドレス
  • IDトークンの有効期限
  • ユーザーの認証時刻
  • ユーザーが使用した認証方法

ログイン処理

LINEでLIFFアプリを開く場合は、LIFFの初期化時に自動でログイン処理が実行されますが、他の起動方法、例えばPCのブラウザから開く場合には別途ログイン処理を実装する必要があります。

login APIを利用すれば、処理実行時にLINEログインのダイアログが表示でき、PCのブラウザであっても容易にログイン処理を実装することができます。

ユーザーの友だちへのメッセージ送信

shareTargetPicker APIを利用することで、開発者が作成したメッセージを、ユーザーが選択したグループ・友だちに対して、ユーザーが送信したかのように投稿することができます。これにより、最小限のユーザーの手間で情報のシェア、拡散を促すことができます。


その他提供されているAPIは以下に記載されています。

LIFF v2 APIリファレンス
LIFF v2の動作環境については、『LIFFドキュメント』の「 概要 」を参照してください。 なお、LIFFアプリをLIFFブラウザで開いた場合と、外部ブラウザで開いた場合では、使用できる機能が異なります。たとえば、 liff.scanCode() は、外部ブラウザでは利用できません。詳しくは、各クライアントAPIの説明をご覧ください。 OpenChatでのLIFFアプリの利用はサポートされていません 現在のところ、OpenChatではLIFFアプリの利用は正式にサポートされていません。たとえば、LIF
https://developers.line.biz/ja/reference/liff/

利用例

以下では、フロントエンド側でどのようなLIFFの使い方をしているかを説明していきます。導入が非常に簡単であることがわかると思います。

まず、複数のコンポーネントからLIFFのAPIを呼べるようにProviderとHooksを作成します。

なお、今回IDトークンをAPI認証に利用していて、IDトークンの有効期限切れを把握したかったためisExpire関数を定義しています。

// src/contexts/liff/index.tsx

import React, { createContext, useContext, useEffect, useState } from 'react';
import type Liff from '@line/liff';

type UseLiff = {
  idToken?: string;
  initialized: boolean;
  isInClient: boolean;
  loggedIn: boolean;
  closeWindow?: () => void;
  isExpire: () => boolean;
  login?: () => void;
  logout?: () => void;
};

const LiffContext = createContext<typeof Liff>(undefined);

export const LiffProvider: React.FC = ({ children }) => {
  const [liff, setLiff] = useState<typeof Liff>(undefined);

  useEffect(() => {
    (async () => {
      const liff = (await import('@line/liff')).default;
      await liff.init({ liffId: process.env.NEXT_PUBLIC_LIFF_ID });
      setLiff(liff);
    })();
  }, []);

  return <LiffContext.Provider value={liff}>{children}</LiffContext.Provider>;
};

export const useLiff = (): UseLiff => {
  const liff = useContext(LiffContext);
  if (!liff) {
    return {
      initialized: false,
      isInClient: false,
      loggedIn: false,
      isExpire: () => false,
    };
  }

  const isExpire = (): boolean => {
    if (!liff.isLoggedIn()) {
      return false;
    }

    const expirationTime = liff.getDecodedIDToken().exp;
    return expirationTime < Date.now() / 1000;
  };

  return {
    idToken: liff.getIDToken(),
    initialized: true,
    isInClient: liff.isInClient(),
    loggedIn: liff.isLoggedIn(),
    closeWindow: liff.closeWindow,
    isExpire: isExpire,
    login: liff.login,
    logout: liff.logout,
  };
};

これだけです。

あとは、LIFFのAPIを呼び出したいコンポーネントでuseLiff()を記述し、LIFFの情報を取得したりAPIを呼び出すことができます。

const { idToken, initialized, closeWindow, isExpire } = useLiff();

今後使いたい機能

現在は利用していないのですが、今後体験を良くしていくにあたり、LIFF間遷移と呼ばれる仕組みに注目しています。LIFF間遷移というのは、LIFFアプリから異なるLIFFアプリと行き来できるという仕組みです。

Linc’wellは、リモートで予約から受診まですべてが完結するオンライン診療サービスも開発しています。sai+ダイアリーとオンライン診療がLIFF間遷移できるようにすることで、ユーザーがsai+ダイアリー利用時にオンライン診療の予約が必要になった場合に、シングルサインオンしているような感覚でオンライン診療の予約ができるという体験を提供できるのではないかと感じています。

LIFFアプリを開く
LIFF v2では、 LIFFブラウザ または外部ブラウザでLIFFアプリを開くことができます。 ここでは、ユーザーがLIFFアプリを開く操作を説明します。 ユーザーがLIFF URLにアクセスします。 LIFF URLは、 LIFFアプリをチャネルに追加すると、発行されます。 ...
https://developers.line.biz/ja/docs/liff/opening-liff-app/#move-liff-to-liff

おわりに

LIFFの概要、できること、利用例を紹介させていただきました。LIFFはフレームワークと言いつつも、少ないコードの変更で部分的に導入できます。サービスがLINE上で利用されることを前提とするのであれば、ユーザーの体験を向上させる手段の一つとしてLIFFが有効だと感じています。今回はLIFFの紹介でしたが、ユーザーの体験を突き詰めて技術を適用し、少しずつプロダクトを改善していきたいと思います。

株式会社Linc'well (リンクウェル)'s job postings
9 Likes
9 Likes

Weekly ranking

Show other rankings
Like Shun Sasaki's Story
Let Shun Sasaki's company know you're interested in their content