
こんにちは!ケイマエです。
2025年3月末でLINE Notifyがサービス終了になるので、Messaging APIを利用して置き換えしました!
LINE NotifyからMessaging APIへの移行の肝になってくるのが、グループIDを取得する方法です。
Google Spread Sheetの拡張機能のApps Scriptを使ってグループIDを取得する記事は多々ありましたが、私はLaravelのWEBサービスに組み込んで実装しました。
今回はその方法を紹介する記事になります。
興味がある方は見ていってください!
さっそくいきましょう!!
LINE Notifyとはどういうサービス?
まずLINE Notifyがどういうサービスか一言で説明します。
「LINEのグループごとにAPIキーを発行することができて、そのキーを使ってAPIを叩くと、そのグループにメッセージを送ることができるサービスです。」
これを利用することで、かなり簡単にLINE通知機能が実装できていました。
しかも無料だったので重宝していた方も多いと思います。
しかし、3月末でサービス終了となります(泣)
これからはLINE Messaging API を使ってくださいということです。
LINE Messaging API は有料か?
Messaging APIは送れるメッセージの数に制限がありますが、無料で使うこともできます!
料金プランが気になる方はこちら
200通まで無料となっていますが、グループの人数分消費されるので、5人のグループだったら月40通までとなります。
個人的なものであれば無料で事足りそうですね。
メッセージを送るだけでなく色々なAPIも提供されています。
APIリファレンスが気になる方はこちら
今回は使用するものだけピックアップしていきます。
LINE Messaging API を使うには?
Messaging APIを使うには、LINE公式アカウントが必要になります。
そしてMessaging API用のチャネルというものを作成して、アクセストークンなどを発行していきます。
API用のチャネルの作り方まではこちらのQiita記事に詳しく書いてあるので、ここでは省きます。
問題はここからで、Messaging APIでグループにメッセージを送るためにグループIDを取得する必要が出てきます。
グループIDを取得する方法は、グループに公式アカウントが参加するときに発火されるWebhookイベントを受信することで、そのレスポンスからグループIDを取得できます。
いろいろ調べましたが、現状Webhookを介してでしかグループIDを取得できません。(2025年3月時点)
先のQiita記事では、このWebhookを受信する方法として、Googleスプレッドシートの拡張機能を使っていましたが、私はLaravelのサービスに組み込んで作りました。
実際にコードを書いて説明していきたいと思います。
実際のLaravelでのコーディング
まずwebhookを受信するルートを書きます。
web.php
Route::post('/line/messaging_api_webhook','API\Line\LineMessagingApiController@handleWebhook');
そのルートの先の処理をコントローラーに書きます。
LineMessagingApiController.php
<?php
namespace App\Http\Controllers\API\Line;
use App\Http\Controllers\Controller;
use App\Models\LineGroup;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Http\Request;
class LineMessagingApiController extends Controller
{
private $client = null;
public function __construct()
{
$client = new Client(['base_uri' => config('line.messaging_api.base_uri')]);
$this->client = $client;
}
/**
* LINE Messaging APIのWebhook受信API
* (グループ参加イベントの場合、そのグループの情報を保存する)
*/
public function handleWebhook(Request $request)
{
$signature = $request->header('X-Line-Signature');
$body = $request->getContent();
$channel_secret = env('LINE_CHANNEL_SECRET');
// 署名の検証
if (!$this->isValidSignature($signature, $body, $channel_secret)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
// Webhookイベントの処理
$events = json_decode($body, true)['events'] ?? [];
foreach ($events as $event) {
if ($event['type'] === 'join') {
$group_id = $event['source']['groupId'] ?? null;
if ($group_id) {
$summary = $this->getGroupSummary($group_id);
$group = LineGroup::where('group_id', $group_id)->where('name', $summary['groupName'])->first();
// LINEグループを作成
if (is_null($group)) {
LineGroup::create([
'group_id' => $group_id,
'name' => $summary['groupName'],
]);
}
}
}
}
return;
}
/**
* グループトークの概要を取得する
*
* @param string $group_id
*/
public function getGroupSummary($group_id)
{
return $this->request('GET', config('line.messaging_api.path.group_summary')($group_id));
}
/**
* LINE Webhookの署名を検証
*/
private function isValidSignature($signature, $body, $channel_secret)
{
$hash = hash_hmac('sha256', $body, $channel_secret, true);
$expected_signature = base64_encode($hash);
return hash_equals($expected_signature, $signature);
}
/**
* リクエストを送信する
*
* @param string $method HTTPメソッド
* @param string $endpoint エンドポイント
* @param array $options リクエストオプション
*/
private function request($method, $endpoint, array $options = [])
{
try {
$defaultOptions = [
'headers' => [
'Authorization' => 'Bearer ' . env('LINE_CHANNEL_ACCESS_TOKEN')
],
];
$options = array_replace_recursive($defaultOptions, $options);
$response = $this->client->request($method, $endpoint, $options);
return json_decode($response->getBody()->getContents(), true);
} catch (ClientException $e) {
\Log::error($e->getResponse()->getBody()->getContents());
}
}
}
Webhook受信APIのhandleWebhook関数の内容について補足していきます。
以下の処理は署名の検証をしています。オープンに公開されるURLのため、不特定のアクセスを除外するためです。
$signature = $request->header('X-Line-Signature');
$body = $request->getContent();
$channel_secret = env('LINE_CHANNEL_SECRET');
// 署名の検証
if (!$this->isValidSignature($signature, $body, $channel_secret)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
API用のチャネルでLINEチャネルシークレットが分かるので、それを.envに保持して、突き合わせて認証を行う形です。
署名の検証処理やisValidSignature関数は公式で提供されているものをそのまま利用しています。
次に認証後のWebhookイベント処理(グループID取得方法)を補足していきます。
// Webhookイベントの処理
$events = json_decode($body, true)['events'] ?? [];
foreach ($events as $event) {
if ($event['type'] === 'join') {
$group_id = $event['source']['groupId'] ?? null;
if ($group_id) {
$summary = $this->getGroupSummary($group_id);
$group = LineGroup::where('group_id', $group_id)->where('name', $summary['groupName'])->first();
// LINEグループを作成
if (is_null($group)) {
LineGroup::create([
'group_id' => $group_id,
'name' => $summary['groupName'],
]);
}
}
}
}
レスポンスのeventsプロパティに各イベントが格納されているので、foreachでひとつずつ処理していきます。
欲しいイベントはグループ参加イベントなので、$event[‘type’] === ‘join’ としています。
グループ参加イベントの場合、$event[‘source’][‘groupId’] でグループIDが取得できます。
一応これで必要なグループIDは取得できるのですが、グループ概要を取得するAPIを叩いてグループ名を取得し、それをline_groupsテーブルにグループIDとグループ名をセットで保存するということをしています。
以上で、グループIDの取得ができました!
次にそのグループにメッセージを送信する方法を見ていきます。
LineMessagingApiController.phpに以下を追加
public function sendMessage($accessToken, $to)
{
$options = [
'headers' => [
'Content-Type' => 'application/json',
],
'json' => [
'to' => $to,
'messages' => [
'type' => 'text',
'text' => 'メッセージ', // 改行は"\n"を入れればできます
];
],
];
return $this->request('POST', 'https://api.line.me/v2/bot/message/push', $accessToken, $options);
}
$options[‘json’][‘to’] にグループIDをセットして、$options[‘json’][‘messages’] は上のような形にしてリクエストすることで、そのグループにメッセージを送ることができます。
まぁAPIリファレンスを見ればすぐ分かることなのですが。
以上で、LINE Notifyを利用したLINEグループへの通知機能をMessaging APIを使って置き換えることができました!
あとがき
たまにはプログラミングの記事も書かなかればと思い、久しぶりに書いてみました(笑)
正直ChatGPTを使えばコーディングはできる時代になったので、サンプルコードも不要かなと思いつつ…
今回LINEのAPIリファレンスを色々見てて、けっこうな種類のAPIが提供されているので、色々できそうだなぁと思案が広がったのが良かったです。
よろしければ他の商品紹介の記事なども見ていってください!
それではまたの記事でノシ