【 Flutter 】 個々のユーザに対してLINEメッセージ通知を送る機能の実現 (LINE SDK・LINE Messaging APIを利用)

### 1.  はじめに

flutter × LINE の実装って本格的なものは知見がWeb上にほとんどなかったので、思い切って記事にしてみました。

今回、具体的には、個々のユーザに対してLINEメッセージ通知を送る機能を実現します。そのためには、以下の手順に沿って実装する必要があります。

- LINEログイン機能を実装し、アプリでLINEログインを行ったユーザのIDを取得
- LINEメッセージ通知機能を実装し、上で取得したユーザIDを宛先として、メッセージ通知

単に、LINEログイン機能の実装、LINEメッセージ通知機能を個別で試すことは簡単ですが、それらを実用的に利用するには、各機能を連携させて使用する必要があります。

上記の機能をFlutterで実装した解説記事が見つからなかったため、本記事で解説しようと思います。多くのFlutter開発者の方々の助けになれば幸いです。

### 2. LINEログイン機能の実装

LINE SDKを用いる事で、LINEログイン機能を実装することができます。

### 2.1  LINE Developersの設定

LINE SDKを使用するには、LINE Developersの設定をする必要があります。

**2.1.1 プロバイダーの作成**

プロバイダーとは、アプリケーションを提供する個人または組織を表す概念で、[LINE Developers Console](https://developers.line.biz/console/)で作成します。以下の1、2を実施し、プロバイダーを作成します。

1. [LINE Developers Console](https://developers.line.biz/console/)にLINEアカウントでログインする
2. トップページで、`[新規プロバイダー作成]`を選択し、プロバイダーを作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/c87c2804-f219-b7d0-aee4-994981b46a83.png)

**2.1.2 チャネルの作成（アプリ毎に必要）**

プロバイダー作成後、プロバイダーのページからチャネルを作成できます。チャネルは、アプリ毎に作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/54dd5aab-9510-3a21-e437-5b13b72e7100.png)

上記の画面から、LINEログインのチャネルを作成します。

チャネル作成後、`チャネルID` をメモしておきます。

**2.1.3  チャネルの設定**

チャネル作成後、いくつか設定を行う必要があります。今回は、Flutterを用いてiOS, Androidで動作させる事を想定しているため、Android, iOSのアプリ識別IDを入力する必要があります。具体的には、チャネルのページで、以下の項目を編集・入力・保存します。

| 入力項目 | 説明 |
| --- | --- |
| iOS bundle ID | `ios/Runner.xcodeproj/project.pbxproj` ファイルの `PRODUCT_BUNDLE_IDENTIFIER` の値 |
| Android パッケージ名 | `android/app/build.gradle` ファイルの `applicationiId` の値 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/75505154-79e4-f35e-1ed6-212898e3deac.png)

以上で、LINE Developersの設定は終わりです。

### 2.2  プログラムの実装

FlutterでLINEログインを実装するには、[flutter_line_sdk](https://pub.dev/packages/flutter_line_sdk)パッケージを使用します。

まず、Flutterプロジェクトに`flutter_line_sdk`をインストールします。

（参考：https://pub.dev/packages/flutter_line_sdk/install）

ターミナルで以下のコマンドを実行します。

```bash
flutter pub add flutter_line_sdk
```

`main.dart` に以下の1行を追加します。

```dart
import 'package:flutter_line_sdk/flutter_line_sdk.dart';
```

iOSの設定

ios/Runner/Info.plist ファイルを開き、最後の </dict> タグの直前に次のスニペットを挿入する。

```xml
<key>CFBundleURLTypes</key>
<array>
<dict>
	<key>CFBundleTypeRole</key>
	<string>Editor</string>
	<key>CFBundleURLSchemes</key>
	<array>
	<!-- Specify URL scheme to use when returning from LINE to your app. -->
	<string>line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<!-- Specify URL scheme to use when launching LINE from your app. -->
<string>lineauth2</string>
</array>
```

Androidの設定

android/app/build.gradleの以下の行で、minSdkを24にする必要がある。

```xml
android {
    defaultConfig {
        minSdk 24
    }
}
```

`main.dart`に基本的なLINEログイン機能を実装します。Buttonを押すと、ログインの処理を実行し、ログイン後に、ユーザーの`userId`を取得できます。取得した`userId` は、後ほど実装する通知機能の宛先を指定する際に使用します。

```dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_line_sdk/flutter_line_sdk.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // Your Channel IDには LINE Developersで設定したLINEログインのチャネルIDを指定
  LineSDK.instance.setup('Your Channel ID').then((_) {
    print('LineSDK Prepared');
  });
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              try {
                // LINEログイン
                // LoginOption(onlyWebLogin, botPrompt): オプションのため必須で無い
                // onlyWebLogin: true or false ログインをWebで行うか否か
                // botPrompt: "normal" or "aggressive" ログイン時に公式アカウント追加
                final result = await LineSDK.instance.login(option: LoginOption(false, "aggressive"));
                // ログイン結果からユーザID取得
                final userId = result.userProfile?.userId;
                if (userId != null) {
                  print("User ID: $userId");
                } else {
                  print("User ID not found");
                }
              } on PlatformException catch (e) {
                print(e.message);
              }
            },
            child: Text("Button"),
          ),
        ),
      ),
    );
  }
}

```

### 3. LINE通知をFlutterで実装

ログインしたユーザから取得した`userId`を宛先として、LINEのMessaging APIを使ってメッセージを送信（通知）する機能を実現します。

### 3.1. Messaging APIのセットアップ

Messaging APIを使用するには、[LINE Official Account Manager](https://manager.line.biz/)で設定が必要です。

**3.1.1  LINE公式アカウントの作成**

まず、[LINE Official Account Manager](https://manager.line.biz/) にログインし、LINE公式アカウント（通知に使うアカウント）を作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/6fd817a5-c9dc-236f-d8c3-1e0a40cb2763.png)

**3.1.2. Messaging APIの設定**

アカウント名をクリックし、アカウントのページに進み、画面右上の`[設定]>[Messaging API]`を選択する。プロバイダー選択画面が表示されるので、LINEログインで作成したプロバイダーを選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/5f2b99b9-d28f-3e9f-b915-ef71ed1c5a7b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/5fa41865-3cb4-2a1d-a004-e7f54a857119.png)

次に、LINE DevelopersでMesssaging APIのチャネルページを開き、[Messaging API設定]から`チャネルアクセストークン` を発行し、メモしておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/eab75f3d-5a99-8641-0409-0761a80af258.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/a1398047-b106-c801-33cb-67e996c30766.png)

**3.1.3  LINEログインのチャネルとMessaging APIのチャネルの紐付け**

LINEログインとMessaging APIを連携させるには、この作業を行う必要があります。

1. [LINE Developersコンソール](https://developers.line.biz/console/)にログインし、LINEログインのチャネルがあるプロバイダーをクリックします。
2. LINEログインのチャネルをクリックします。
3. ［**チャネル基本設定**］をクリックし、［**リンクされたLINE公式アカウント**］の［**編集**］をクリックします。
4. ユーザーに追加させるLINE公式アカウントを選択して、［**更新**］をクリックします。

### 3.2  実装

Messaging APIを使用するには、FlutterでHTTP通信を行うための設定をしておく必要があります。FlutterでHTTP通信を実装するために、[http](https://pub.dev/packages/flutter_line_sdk)パッケージをインストールします。

ターミナルで以下のコマンドを実行します。

```bash
flutter pub add http
```

`main.dart` に以下の1行を追加します。

```dart
import 'package:http/http.dart' as http;
```

最後に、先ほどのLINEログインのプログラムに、Messaging APIの処理として`sendLineMessage関数`を追記したプログラムを示します。このプログラムにより、個々のユーザに対してLINEメッセージ通知を送る機能を実現できます。

```dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_line_sdk/flutter_line_sdk.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  // LINE Developersで設定したLINEログインのチャネルIDを利用
  LineSDK.instance.setup('your channel id').then((_) {
    print('LineSDK Prepared');
  });
  runApp(const MainApp());
}

// LINEにメッセージを送信する関数
Future<void> sendLineMessage(String userId) async {
  // 先ほど取得したチャネルアクセストークンを利用
  const String channelAccessToken = '';
  const String apiUrl = 'https://api.line.me/v2/bot/message/push';

  var headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer $channelAccessToken',
  };

  var body = jsonEncode({
    'to': userId,
    'messages': [
      {
        'type': 'text',
        'text': 'Your custom message here',
      },
    ],
  });

  try {
    var response = await http.post(Uri.parse(apiUrl), headers: headers, body: body);

    if (response.statusCode == 200) {
      print('Message sent successfully');
    } else {
      print('Failed to send message: ${response.statusCode}');
    }
  } catch (e) {
    print('Error occurred while sending message: $e');
  }
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              try {
                final result = await LineSDK.instance.login();
                final userId = result.userProfile?.userId;
                if (userId != null) {
                  print("User ID: $userId");
                  sendLineMessage(userId);
                } else {
                  print("User ID not found");
                }
              } on PlatformException catch (e) {
                print(e.message);
              }
            },
            child: Text("Button"),
          ),
        ),
      ),
    );
  }
}

```

### 参考）他のLINEアカウントで動作確認する際の注意

LINEログインのチャネルで、以下の画面の通り「公開済み」になっていることを確認する。「開発中」となっている場合、自分のLINEアカウントでしかログインできず、他のLINEアカウントでログインしようとすると、以下のエラーが発生します。

`PlatformException(CANCEL, , null, null)` 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674933/b3fb6edb-cc5f-05a1-c8c8-57dd516ebf51.png)

### 4.  終わりに

個々のユーザに対してLINEメッセージ通知を送る機能を実現するために、LINEログイン機能、LINEメッセージ通知機能を実装し、それらを連携させて動作させてみました。

おそらく、FlutterでLINE機能を実装する記事として、本記事が最も詳細に内容を解説していますので、多くのFlutter開発者の方々の助けになれば幸いです。