3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【個人開発】Next.jsでLINE BOTアプリ作ってみた

3
Last updated at Posted at 2024-09-26

目次

1. アプリ概要
2. 使用技術
3. 開発
4. 終わりに

アプリ概要

QR コード

友達追加お願いします!

請求書発行BOT

機能

  • LIFF のアプリ内で請求書を作成できる
  • その請求書を LINE の友達に送信できる

作成動機

  • 家族や友達とお金の貸し借りをよくする
  • お金を返してと言いづらいことを解消したい
  • 身近なアプリである LINE で Next.js を使用したものを作りたかった
  • デプロイまでしたかった

Github リンク

使用技術

技術一覧

  • TypeScript (Next.js)
  • Image Generation
  • LIFF(LINE ログインチャネル)
  • LINE Official Account Manager
  • Vercel
  • Git
  • Github

開発

開発の流れ

  1. LINE ログインチャネルを作成し、LIFF アプリを作成
  2. Next.js で Web アプリを作成し、LIFF アプリに登録
  3. LINE 公式アカウントを作成し、作成した LIFF アプリを埋め込む

1. LINE ログインチャネルを作成し LIFF アプリを作成

LIFF アプリを作成するために LINE ログインチャネルを作成します。(LINE ログインと LINE ミニアプリ以外のチャネルには LIFF アプリを追加できないみたいです。)
https://developers.line.biz/console/ にアクセスし、LINE アカウントでログインし、プロバイダーを作成し、そのプロバイダーの中に LINE ログインチャネルを作成します。

請求書発行BOT

ログインチャネルを作成したら、「LIFF」タブから LIFF アプリを作成します。
エンドポイント URL は一旦 http://localhost:3000/ としておきます。

image.png

2. Next.js で Web アプリを作成

環境変数

先ほど作成した LIFF アプリの LIFF ID を env ファイルに記載します。
LIFF ID は LIFF アプリ詳細画面に記載してあります。

請求書発行BOT
.env.local
NEXT_PUBLIC_LIFF_ID=my-liff-id

画像生成 API

今回のアプリでは、ユーザーからの入力に応じて請求書の画像を動的に生成したいので、Next.js の機能である Image Generation を利用して API を作成しました。

参考記事

src/app/api/og/invoice/route.ts
import { NextRequest } from "next/server";
import { ImageResponse } from "@vercel/og";

export const runtime = "edge";

export function GET(req: NextRequest) {
  if (req.method !== "GET") {
    return new Response("Method Not Allowed", { status: 405 });
  }

  try {
    const { searchParams } = new URL(req.url);

    const issueDate = searchParams.get("issueDate") || "";
    const dueDate = searchParams.get("dueDate") || "";
    const amount = searchParams.get("amount") || "";
    const message = searchParams.get("message") || "";

    return new ImageResponse(

      ()

    );
  } catch (e: unknown) {
    if (e instanceof Error) {
      console.log(`${e.message}`);
    } else {
      console.log("An unknown error occurred");
    }
    return new Response("画像の生成に失敗しました", {
      status: 500,
    });
  }
}

例えば
http://localhost:3000/api/og/invoice?issueDate=2024-09-25&dueDate=2024-10-01&amount=1000&message=支払いお願いします。
という URL にアクセスすると

請求書発行BOT

このような画像が返ってきます。

フロントエンド

src/app/page.tsx
"use client";

import { useEffect, useState } from 'react';
import liff from '@line/liff';

interface Profile {
  name: string;
  picture: string;
}

export default function Home() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [profile, setProfile] = useState<Profile>({ name: '', picture: '' });
  const [amount, setAmount] = useState('');
  const [dueDate, setDueDate] = useState('');
  const [message, setMessage] = useState('');

  useEffect(() => {
    const liffId = process.env.NEXT_PUBLIC_LIFF_ID;
    console.log('LIFF ID:', liffId);
    console.log('All env variables:', process.env);

    if (!liffId) {
      console.error('LIFF ID is missing');
      return;
    }

    liff
      .init({ liffId })
      .then(() => {
        if (liff.isLoggedIn()) {
          const idToken = liff.getDecodedIDToken();
          setProfile({ name: idToken?.name ?? '', picture: idToken?.picture ?? '' });
          setIsLoggedIn(true);
        }
      })
      .catch((error) => {
        console.log('LIFF initialization failed', error);
      });
  }, []);

  const handleLogin = () => {
    liff.login();
  };

  const getCurrentDate = () => {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, '0');
    const day = String(today.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  };

  function handleCreateInvoice() {
    if (!amount || !dueDate || !message) {
      alert('金額、期日、メッセージを入力してください');
      return;
    }

    const issueDate = getCurrentDate();

    const invoiceImageUrl = `https://nextjs-line-invoice-bot.vercel.app/api/og/invoice?amount=${amount}&dueDate=${dueDate}&issueDate=${issueDate}&message=${encodeURIComponent(message)}`;

    liff.shareTargetPicker([
      {
        type: "text",
        text: "下記の内容にて請求書をお送りいたしますので、ご確認ください。",
      },
      {
        type: "image",
        originalContentUrl: invoiceImageUrl,
        previewImageUrl: invoiceImageUrl,
      },
      {
        type: 'text',
        text: `このメッセージは請求書送信BOTから送信されています。\nhttps://lin.ee/qeZlCxi`,
      },
    ]);
  }

  return (

    ()

  );
}

デプロイ

今回は Vercel を使ってデプロイしました。
Vercel の管理画面の Settings の Environment Variables から LIFF ID を設定する必要があります。
デプロイが完了したら、LIFF アプリのエンドポイント URL をデプロイ先の URL に変更します。

3. LINE 公式アカウントを作成し、作成した LIFF アプリを埋め込む

LIFF の設定

LIFF アプリを自分以外の人が使えるように、ステータスを「開発中」から「公開済み」に変更します。

請求書発行BOT

また LIFF アプリのシェアターゲットピッカーはオンにしておきます。

公式 LINE アカウントの作成

https://manager.line.biz/ にアクセスし公式 LINE アカウントを作成します。

LIFF アプリを埋め込む

作成した公式アカウント内で LIFF アプリを使用します。
LIFF アプリの URL は LIFF アプリの管理画面に記載されています。

請求書発行BOT 

今回はリッチメニューから作成した LIFF アプリにアクセスできるようにしました。

請求書発行BOT  請求書発行BOT

色々面白い設定もできて触っていて楽しかったです。

終わりに

今回作成したアプリはシンプルなものなので、機能を追加してもっと便利なアプリにしたいと思いました。
はじめて LINE のアプリを作成してみて、さまざまな機能があることを知り、使いこなせるともっと面白くて便利なアプリを作成できると思いました。

追記

このアプリを少し改良して、機能の追加やデザインの修正をしてみました。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?