こんにちは!
今回は、LINEのLIFFアプリでメッセージ送信をする手順を解説していきます。
では見ていきましょう!!
目次
そもそもLIFFアプリとは
LINE Front-end Framework(LIFF)は、LINEが提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。
LIFFアプリを使うと、LINEのユーザーIDなどをLINEプラットフォームから取得できます。LIFFアプリではこれらを利用して、ユーザー情報を活用した機能を提供したり、ユーザーの代わりにメッセージを送信したりできます。
LIFFアプリは以下のように、アプリ内で開くことができます。ChromeやSafariなどの外部ブラウザでも開くことができるようです。
今回やりたいこと
今回やりたいことは、以下になります。
- メッセージを送信したい公式LINEアカウントで、LIFF URLを押下して、LIFFアプリを起動する
- LIFFアプリ内の「ユーザーから管理者へ」ボタンを押したら、ユーザーから管理者へメッセージ送信する。
- LIFFアプリ内の「管理者からユーザーへ」ボタンを押したら、管理者からユーザーへメッセージ送信する。
LINE Developersコンソールで公式LINEアカウントを作る
LIFFアプリ用のチャネルを追加する
まずLINE Developersコンソールでプロバイダーとチャネルを作成します。
チャネルの種類は「LINEログイン」を選択して、LIFFアプリを追加しましょう。
作成方法は公式の以下の手順を踏めば、簡単に作成できます。
以下の手順で、LIFFアプリをチャネルに追加する際に、エンドポイントURLを設定する必要があります。これは、LIFF URLを利用してLIFFアプリを起動した際に、ここで設定したurlが読み込まれます。
後に「Create LIFF App」というものを使ってVueで開発環境を作りますが、ビルドしたファイルを任意のサーバーにデプロイして、エンドポイントURLとして設定する必要があります。なお、エンドポイントURLはhttpsである必要があります。
メッセージ送信用のチャネルを追加する
LIFFアプリで公式LINEアカウントにメッセージを送るには、チャネルをもう一つ作成します。
先ほどのLIFFアプリ用のチャネルと同じプロバイダー内で、チャネルの種類は「Messaging API」を選択してチャネルを追加してください。
作成方法は、以下の手順になります。
チャネルを追加したら「Messaging API設定」タブにQRコードがあるので、友達登録しておきましょう。
Create LIFF AppでLIFFアプリの開発環境をつくる
LIFFアプリの開発環境ですが、コマンド1つで構築できるCLIツールである、Create LIFF Appというものがあります。
ReactのCreate React Appや、Next.jsのCreate Next Appのように、Create LIFF Appからの質問に答えていくことで、用途に合わせたLIFFアプリのひな形を含む開発環境が生成され、すぐに開発が始められます。
動作を確認したバージョンは以下になります。
動作環境
今回の環境
- Create LIFF App 1.1.0
- Node.js 16.19.0
- npm 8.19.3
使用する言語とフレームワーク
フレームワークは、以下の中から使えますが、今回はVue.jsでjavascriptを使っていこうと思います。
- Next.js
- Nuxt
- React
- Vue.js
- Svelte
Create LIFF Appを使う
まずは、Create LIFF Appを実行していきます。
npx @line/create-liff-app
プロジェクト名を入力します。例として「my-app」にします。
? Enter your project name: my-app
フレームワーク名と言語を選択します。今回はVueとjavascriptを選択します。
? Which template do you want to use? (Use arrow keys)
vanilla
react
❯ vue
svelte
nextjs
nuxtjs
? JavaScript or TypeScript? (Use arrow keys)
❯ JavaScript
TypeScript
LIFF IDを入力します。後からLIFF IDを設定することもできます。(のちに生成される.envに記述する)
LIFF IDは、LIFFアプリ用に追加したチャネル内に記述してあります。
? Please enter your LIFF ID:
Don't you have LIFF ID? Check out https://developers.line.biz/ja/docs/liff/getting-started/ (liffId)
どのパッケージマネージャを使用するかを選択します。今回はnpmを選択します。
? Which package manager do you want to use? (Use arrow keys)
yarn
❯ npm
そうするとLIFFアプリのひな形を含む開発環境が出来ているはずです。
LIFFアプリを起動する
npm run dev
コマンドを打つと、ローカルホストでLIFFアプリが起動されます。
以下の例だとhttp://localhost:5173/で起動されている状態です。
実際に遷移してみて、LIFF init succeeded.
と表示されていれば成功です。
注意点!
LIFF IDを設定していない場合は、以下のように LIFF init failed.
というメッセージを含む画面が表示されます。
生成されたmy-appのディレクトリ内にある.envファイルにLIFF IDを書いて、LIFFアプリを再起動してください。
LIFF IDは、LINE DevelopersコンソールのLIFFアプリ用のチャネルに書いてあります。
任意のサーバーにデプロイする
これでLIFFアプリを開発する準備ができました。
なおLIFFアプリはLINE上で動かしていくことになるので、動作を確認するにはnpm run build
でビルドした後に、生成されたファイルを任意のサーバーにデプロイした上で、URLをLINE DevelopersコンソールのLIFFアプリ用のチャネルにある[エンドポイントURL]に設定しなければいけません。エンドポイントURLはhttpsである必要があります。
任意のサーバーへのデプロイ方法は、解説しません。
サーバーにデプロイして、エンドポイントurlを設定したら、LIFF URLを友達登録した公式LINEアカウントにメッセージ送信して、以下のようにLIFFアプリを起動します。「Create LIFF App」の初期画面が表示すれば、成功です。
ユーザーから管理者へメッセージを送る
src/App.vueを確認する
まず、生成されたmy-appディレクトリ内にある、src/App.vueの中身を見ていきましょう。
<template>
<div>
<h1>create-liff-app</h1>
<p v-if="message">{{ message }}</p>
<p v-if="error">
<code>{{ error }}</code>
</p>
<a href="https://developers.line.biz/ja/docs/liff/" target="_blank" rel="noreferrer">
LIFF Documentation
</a>
</div>
</template>
<script>
import liff from "@line/liff";
export default {
data() {
return {
message: "",
error: ""
};
},
mounted() {
liff
.init({
liffId: import.meta.env.VITE_LIFF_ID
})
.then(() => {
this.message = "LIFF init succeeded.";
})
.catch((e) => {
this.message = "LIFF init failed.";
this.error = `${e}`;
});
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
最初にmounted()
の中身が読み込まれまれ、liff.init() が実行されます。
このメソッドを実行することによって、のちに記述しますが、そのユーザーのアクセストークンや、メッセージを送信できるメソッドを実行できるようになります。
メッセージ送信する
それでは、ユーザーから管理者へメッセージを送っていきます。
まずmethods
を追加して、その中にsendUsertoAdminMessege()
を作成します。
mounted() {
liff
.init({
liffId: import.meta.env.VITE_LIFF_ID
})
.then(() => {
this.message = "LIFF init succeeded.";
})
.catch((e) => {
this.message = "LIFF init failed.";
this.error = `${e}`;
});
},
// ここから追加
methods: {
sendUsertoAdminMessege() {
// メッセージ送信する
liff.sendMessages([{
type: "text",
text: "ユーザーからメッセージ送信したしん!",
}])
.then(() => {
console.log('Message sent');
})
.catch((error) => {
console.log('Error sending message: ' + error);
});
}
}
sendUsertoAdminMessege()
の中で実行されている liff.sendMessages() は、メッセージ送信を送信するメソッドになります。
次にテンプレート部分に、メッセージ送信するボタンを追加します。
<template>
<div>
<h1>create-liff-app</h1>
<p v-if="message">{{ message }}</p>
<p v-if="error">
<code>{{ error }}</code>
</p>
<a href="https://developers.line.biz/ja/docs/liff/" target="_blank" rel="noreferrer">
LIFF Documentation
</a>
<!-- ここから追加 -->
<div style="padding-top: 10px">
<button @click="sendUsertoAdminMessege()">ユーザーから管理者へ</button>
</div>
<!-- ここまで -->
</div>
</template>
そしたら、npm run build
でビルドしたファイルをデプロイして、以下の動画のようにLIFFアプリを起動し、「ユーザーから管理者へ」ボタンを押すと、メッセージ送信ができるようになっていると思います。
管理者からユーザーへメッセージを送る
次に、管理者からユーザーへメッセージを送ります。
管理者からユーザーへメッセージを送るには、LINEのMessage APIを使っていきます。
そのためにまずは、ユーザー情報を取得していきます。
ユーザー情報を取得する
ユーザーが、LINEでLIFFアプリを起動した後、liff.init() を実行してログイン処理を行うと、ユーザーのプロフィール(ユーザーID、表示名、プロフィール画像、メールアドレスなど)を取得できるようになります。
ユーザー情報を取得する方法は、以下の2通りあります。
- IDトークンを送信してユーザー情報を取得する
- アクセストークンを送信してユーザー情報を取得する
今回は、「アクセストークンを送信してユーザー情報を取得する」方法でやっていきます。
また、LIFFアプリへのログイン処理や、アクセストークン取得は、フロント側でやりますが、実際にユーザーへメッセージを送るのは、サーバーサイド側でNode.jsを使って実装していきます。
具体的な手順としては以下のようになります。
- liff.init() でログインする。
- liff.getAccessToken() でアクセストークンを取得。
- サーバーサイド側にapiで2で受け取ったアクセストークンを送信する。
- サーバーサイド側で受け取ったアクセストークンを GET /oauth2/v2.1/verify で検証する。
- サーバーサイド側でGET /v2/profile でユーザーのプロフィール情報を安全に取得する。
- サーバーサイド側で POST v2/bot/message/push で管理者からユーザーへメッセージ送信する。
フロントエンド側
以下が全体のコードです。LIFFアプリを起動したら、ログイン処理が完了するまで、「ログイン中」と表示させるようにしています。
ログインが完了すると、「ログイン成功」とボタンが2つ表示されます。
また、ブラウザからアクセスした場合は、「LINEアプリから実行してください」と表示するようにしています。
全体のソースコードが変わっているので、コピペした方がいいかもしれません。
axiosを使ってapiを叩いているので、npm install axios
でインストールしてください
<template>
<div>
<h1>create-liff-app</h1>
<div>
{{ message }}
</div>
<template v-if="isBrowserCheck">
<div>
<div>
<button @click="sendUsertoAdminMessege()">ユーザーから管理者へ</button>
</div>
<div class="kankaku">
<button @click="sendAdmintoUserMessege()">管理者からユーザーへ</button>
</div>
</div>
</template>
</div>
</template>
<script>
import liff from "@line/liff";
import axios from 'axios'
export default {
data() {
return {
message: "ログイン中",
error: "",
accessToken: "",
isBrowserCheck: false,
};
},
mounted() {
liff
.init({
liffId: import.meta.env.VITE_LIFF_ID
})
.then(() => {
this.accessToken = liff.getAccessToken();
if (this.accessToken == null) {
this.isBrowserCheck = false;
this.message = "LINEアプリから実行してください";
return false;
}
this.isBrowserCheck = true;
this.message = "ログイン成功";
})
.catch((e) => {
this.message = "ログイン失敗";
this.error = `${e}`;
});
},
methods: {
sendUsertoAdminMessege() {
liff.sendMessages([{
type: "text",
text: "ユーザーからメッセージ送信したしん!",
}]);
},
async sendAdmintoUserMessege() {
const apiClient = axios.create({
baseURL: "https://hogehogehogehogehoge",
headers: {
"Content-type": "application/json",
},
});
await apiClient.post("/api/backend/sendMessage", {
accessToken: this.accessToken,
})
}
},
};
</script>
<style>
.kankaku {
padding-top: 10px;
}
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
まず以下の部分で、liff.init() でログインした後に、 liff.getAccessToken()でアクセストークンを取得しています。
返り値がnullの場合は、ブラウザからアクセスしているので、LINEアプリから実行してください。
this.accessToken = liff.getAccessToken();
ログインが成功したら、表示される「管理者からユーザーへ」ボタンを押します。
そうすると、sendAdmintoUserMessege()
メソッドが実行されて、以下の部分でapiでサーバーサイド側にアクセストークンを渡します。
以下の例だと、https://ghogehogehogehogehoge/api/backend/sendMessage
というapiに送信しています。
const apiClient = axios.create({
baseURL: "https://hogehogehogehogehoge",
headers: {
"Content-type": "application/json",
},
});
await apiClient.post("/api/backend/sendMessage", {
accessToken: this.accessToken
})
フロントエンド側は以上になります。
npm run build
でビルドしたファイルを、任意のサーバへデプロイしてください。
サーバーサイド側
ここからサーバサイド側での処理でNode.jsを使っています。
以下が全体のコードです。
const axiosBase = require("axios");
const express = require("express");
const app = express();
app.use(express.json())
app.use(express.urlencoded({
extended: true
}))
app.use(cors())
//----------------------------------------------------------
// アクセストークンを受けとって、メッセージを送信するapi
//----------------------------------------------------------
app.post("/api/backend/token", async function(req, res) {
// アクセストークンを検証する
const response1 = await verifyAcessToken(req.body['accessToken'])
if (response1.status !== 200) {
console.log("検証エラー");
return false
}
// ユーザー情報取得する
const response2 = await getProfile(req.body['accessToken'])
if (response2.status !== 200) {
console.log("プロフィール取得エラー");
return false
}
// 管理者からユーザーへメッセージ送信
const response3 = await liffLineMessagePush(response2.data.userId)
if (response3.status !== 200) {
console.log("メッセージ送信エラー");
return false
}
console.log("送信完了");
})
/**
* アクセストークンを検証
*/
const verifyAcessToken = async (id_token) => {
const axios= axiosBase.create({
baseURL: 'https://api.line.me',
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
timeout: 5000,
});
return axios.get(`oauth2/v2.1/verify?access_token=${id_token}`)
}
/**
* ユーザープロフィール情報取得
*/
const getProfile = async (accessToken) => {
const axios= axiosBase.create({
baseURL: 'https://api.line.me',
headers: {
"Content-type": "application/x-www-form-urlencoded",
Authorization:
"Bearer " + accessToken,
},
timeout: 5000,
});
return axios.get(`/v2/profile`)
}
/**
* 管理者からユーザーへメッセージ送信
*/
const liffLineMessagePush = async (userId) => {
const axios= axiosBase.create({
baseURL: 'https://api.line.me',
headers: {
"Content-type": "application/json",
Authorization:
"Bearer " + "チャネルアクセストークン",
},
timeout: 5000,
});
return axios.post('v2/bot/message/push', {
to: userId,
messages: [
{
"type":"text",
"text":"管理者からメッセージ送信したしん!"
}
]
})
}
サーバーサイド側でアクセストークンを受け取り、まずは以下のようにアクセストークンを検証( GET /oauth2/v2.1/verify)していきます。
const response1 = await verifyAcessToken(req.body['accessToken'])
if (response1.status !== 200) {
console.log("検証エラー");
return false
}
・・・・・・
・・・・・・
/**
* アクセストークンを検証
*/
const verifyAcessToken = async (accessToken) => {
const axios = axiosBase.create({
baseURL: 'https://api.line.me',
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
timeout: 5000,
});
return axios.get(`oauth2/v2.1/verify?access_token=${accessToken}`)
}
アクセストークンが有効である場合は、HTTPステータスコード 200 OK
と、以下の情報を含むJSONオブジェクトが返されます。
{
"scope": "profile",
"client_id": "1440057261",
"expires_in": 2591659
}
アクセストークンが有効の場合は、アクセストークンをAuthorization
に指定して、ユーザープロフィール (GET /v2/profile)を取得します。
const response2 = await getProfile(req.body['accessToken'])
if (response2.status !== 200) {
console.log("プロフィール取得エラー");
return false
}
・・・・・・
・・・・・・
/**
* ユーザープロフィール情報取得
*/
const getProfile = async (accessToken) => {
const axios = axiosBase.create({
baseURL: 'https://api.line.me',
headers: {
"Content-type": "application/x-www-form-urlencoded",
Authorization:
"Bearer " + accessToken,
},
timeout: 5000,
});
return axios.get(`/v2/profile`)
}
成功の場合は、HTTPステータスコード 200 OK
と、以下の情報を含むJSONオブジェクトが返されます。
userId
が、メッセージ送信時に使うユーザーidになります。
{
"userId": "U4af4980629...",
"displayName": "Brown",
"pictureUrl": "https://profile.line-scdn.net/abcdefghijklmn",
"statusMessage": "Hello, LINE!"
}
先ほど取得した、ユーザーidで、Message API(POST v2/bot/message/push)を叩いて、ユーザーへメッセージ送信を行います。
ここでは、Authorization
に LINE Developersのメッセージ送信用のチャネルから取得できる、チャネルアクセストークンを指定します。
// 管理者からユーザーへメッセージ送信
const response3 = await liffLineMessagePush(response2.data.userId)
if (response3.status !== 200) {
console.log("メッセージ送信エラー");
return false
}
console.log("送信完了");
・・・・・・
・・・・・・
/**
* 管理者からユーザーへメッセージ送信
*/
const liffLineMessagePush = async (userId) => {
const axios = axiosBase.create({
baseURL: 'https://api.line.me',
headers: {
"Content-type": "application/json",
Authorization:
"Bearer " + "チャネルアクセストークン",
},
timeout: 5000,
});
return axios.post('v2/bot/message/push', {
to: userId,
messages: [
{
"type":"text",
"text":"管理者からメッセージ送信したしん!"
}
]
})
}
以上になります!!
LIFFアプリから「管理者からユーザーへ」ボタンを押して、管理者からメッセージが送信されれば成功です!!