🔔

最新版Flutterでのローカル通知の実装 | エラーガイドflutter_local_notifications

に公開

はじめに

今回は、Flutterでの通知の実装について解説します。
flutter_local_notificationsを使用した通知をAndroidで実装します。

このパッケージでは、公式ドキュメントや既存の記事通りに実装してもエラーが起きることが多々あります。
以下のようなエラーが出た人も多いのではないでしょうか。

  • Unresolved reference: coreLibraryDesugaringEnabled
  • Dependency ':flutter_local_notifications' requires desugar_jdk_libs version to be 2.1.4 or above
  • [!] Your app is using an unsupported Gradle project.
  • Error: The method 'requestPermission' isn't defined for the class 'AndroidFlutterLocalNotificationsPlugin'.
  • Android resource linking failed: error: resource @mipmap/launcher_icon not found.
  • Gradle task assembleDebug failed with exit code 1
  • 警告: [options] ソース値8は廃止されていて、今後のリリースで削除される予定です

など
原因は

  • Flutterのバージョン
  • Androidの設定
  • 使っているflutter_local_notificationsのバージョン
    が嚙み合っていないことが考えられます。

この記事では

この記事では2025年7月現在Flutter最新バージョンでのAndroid向け
ローカル通知(即時通知)を行います。最小限で動くコード設定方法を解説します。
ボタンを押すと即時通知が届くシンプルな実装をします。
即時通知以外の通知や通知内容の変更、その他通知のカスタマイズについては別の記事で解説しようと思います。

準備

前提

ここからは、このチュートリアルをそのまま試すために必要な環境を紹介します。
この章は特に大切で、多くの記事や動画の通りに行ってもエラーが起きる原因となります。

Flutterのバージョン

ターミナルで

flutter doctor --version

と打つとバージョンを確認できます。古いFlutter(2.x,3.10など)では、同じコードでもビルドエラーがでます。DartのサポートやGradleAndroidの設定などが大きく異なるからです。
そのため以下のコマンドで最新のFlutterにアップグレードすることをお勧めします。

flutter upgrade

以下のようになっているか、それ以上のバージョンであればよいです。

Flutter 3.32.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision fcf2c11572 (8 days ago)2025-06-24 11:44:07 -0700
Engine • revision dd93de6fb1 (8 days ago)2025-06-24 07:39:37 -0700
ToolsDart 3.8.1DevTools 2.45.1

Androidのバージョン

この記事ではAndroid5.0(API21)以上をターゲットとします。
また、Android 13以降では通知権限をユーザーから明示的に取得する必要があります。この実装コードも後で紹介します。

エディタやエミュレータ

エディタはAndroid StudioでもVSCodeどちらでも大丈夫です。
また、モバイル向けを想定していて、Androidエミュレータでの実装です。私はVSCodePixel4aを使用しています。

Gradleについて

最も悩まされたのはここです。他の記事であまり紹介されていない場合が多いです。
FlutterではAndroidのビルド設定をGradleで行います。
最近のFlutterでは

  • build.gradle.kts (Kotlin DSL)
  • build.gradle (Groovy)

の二種類があるそうです。公式推奨は Kotlin DSL です。
古いGroovy式を使っていたりすると正しく機能せず、新しいプロジェクトを作る必要があります。
Flutterのアップグレードして新規プロジェクトを作りましょう。

また、ファイルに
android/app/build.gradle.kts

があることを確認しましょう。

実装

プロジェクト作成

flutter create -t app notificationapp
cd notificationapp

でプロジェクトを立ち上げます。
-t appは明示的にモバイルアプリ用であることを示しますが、デフォルトでモバイルアプリ用なのでなくても大丈夫です。

flutter emulators --launch (emulator Id)

emulator Idがわからない場合は、以下のコマンドで確認できます。

flutter emulators

pubspec.yaml

flutter_local_notifications: ^19.3.0を使います。
Flutterパッケージは頻繫に破壊的アップデートがあるのでバージョン固定をするのがおすすめです。
pubspec.yamlに以下の設定をしましょう。
permission_handler: ^11.3.0も設定します。

dependencies:
  flutter:
    sdk: flutter
  flutter_local_notifications: ^19.3.0 #追加
  permission_handler: ^11.3.0 #追加

AndroidManifest.xml

permissionを通しましょう。

android/app/src/main/AndroidManifest.xml
の2行目に

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- 追加 -->

を追加しましょう。
インデントも忘れずに。
androidでの通知送信許可などの設定をします。

build.gradle.kts

android/app/build.gradle.kts

android{
    ndkVersion = "27.0.12077973" //変更
}

とします。デフォルトではエラーが起きる可能性が高いです。

また、

android{
    defaultConfig
        minSdk = 21 //変更
}

また、

android{
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
        isCoreLibraryDesugaringEnabled = true // 追加
    }

とします。人によってもともとあったりなかったりだと思いますが、特にここは大切です。
さらに、ファイルの最下に

dependencies {
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
} // 追加

を追加します。最後の数字2.1.5についても同様に時期によって異なる場合があるため、エラーの原因となることがありますので注意してください。

全体としてコードは以下のようになっています。そのままコピペでも大丈夫です。

android/app/build.gradle.kts
plugins {
    id("com.android.application")
    id("kotlin-android")
    // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
    id("dev.flutter.flutter-gradle-plugin")
}

android {
    namespace = "com.example.notificationapp" // notificationappは自分のプロジェクト名に変更
    compileSdk = flutter.compileSdkVersion
    ndkVersion = "27.0.12077973"

    

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_11.toString()
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId = "com.example.notificationapp" // notificationappは自分のプロジェクト名に変更
        // You can update the following values to match your application needs.
        // For more information, see: https://flutter.dev/to/review-gradle-config.
        minSdk = 21
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
        isCoreLibraryDesugaringEnabled = true
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig = signingConfigs.getByName("debug")
        }
    }
}

flutter {
    source = "../.."
}

dependencies {
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
}

ここで一度

flutter run

で実行してみましょう。
ここで無事に画面が表示されれば大きなヤマを乗り越えられました。
場合よっては警告がでできますが、謎コードがJava8を指定してしまうからです。ただ、ビルドが通るのであれば大きな問題ではないです。
ここまでがこの記事のメインテーマでした。
もしエラーを解決できた方がいれば嬉しいです。ほとんどが完了しています。

main.dart

私はmain.dartは最小限にしたい主義(?)なのでページを分けています。
Flutterでのページ実装についても別の記事で書こうと思います。

main.dart
import 'package:flutter/material.dart';
import 'pages/home_page.dart';

void main() {
  runApp(const MyApp());
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Notification Demo',
      home: const HomePage(),
    );
  }
}

main.dartは何でも大丈夫です。
自分のプロジェクトに合わせて変えて大丈夫です。

home_page.dart

lib/pagesディレクトリにhome_page.dartを作成します。

home_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io' show Platform;

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final FlutterLocalNotificationsPlugin notificationsPlugin = FlutterLocalNotificationsPlugin();

  
  void initState() {
    super.initState();
    initNotifications();
  }

  Future<void> initNotifications() async {
    // 1. Initialize settings
    const AndroidInitializationSettings androidSettings =
        AndroidInitializationSettings('@mipmap/ic_launcher');

    const DarwinInitializationSettings iosSettings = DarwinInitializationSettings();

    const InitializationSettings initSettings = InitializationSettings(
      android: androidSettings,
      iOS: iosSettings,
    );

    await notificationsPlugin.initialize(initSettings);

    // 2. Request permission for Android 13+ and iOS
    await _requestPermissions();
  }

  Future<void> _requestPermissions() async {
    if (Platform.isAndroid) {
      final status = await Permission.notification.status;
      if (!status.isGranted) {
        await Permission.notification.request();
      }
    } else if (Platform.isIOS) {
      final iosImpl = notificationsPlugin
          .resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>();
      await iosImpl?.requestPermissions(
        alert: true,
        badge: true,
        sound: true,
      );
    }
  }

  Future<void> showInstantNotification() async {
    const AndroidNotificationDetails androidDetails = AndroidNotificationDetails(
      'your_channel_id',
      'Your Channel Name',
      importance: Importance.max,
      priority: Priority.high,
    );

    const DarwinNotificationDetails iosDetails = DarwinNotificationDetails();

    const NotificationDetails notificationDetails = NotificationDetails(
      android: androidDetails,
      iOS: iosDetails,
    );

    await notificationsPlugin.show(
      0,
      'Instant Notification',
      'This is a test notification',
      notificationDetails,
    );
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Local Notification')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FilledButton(
              onPressed: showInstantNotification,
              child: const Text('Show Instant Notification'),
            ),
          ],
        ),
      ),
    );
  }
}

コードの説明はコメントアウトにしています。公式ドキュメントを参考に書き上げたものです。
AndroidiOSのイニシャライズと、Androidでのpermission(通知を送信していいですか?のようなもの)の実装、通知を送信するコードなどから構成されています。
実行すると、ボタンを押すことで
アイコンがデフォルトのFlutterアイコン
タイトルがInstant Notification
内容がThis is a test notification
の通知が即時に来ます。

おわりに

お疲れ様でした!
今回はFlutterでのflutter_local_notificationsを使用した通知について紹介しました。特にエラーについて。
この記事でエラーが解決できたり、うまく実装できた方がいたら幸いです。
次は、通知の詳細なカスタマイズについて紹介しようと思います。例えば指定時間に送信、通知のメッセージの変更、アイコンの変更などなど。
実装してほしいものがあればぜひコメントで教えてください!

私は、Flutterを中心にプログラミングをしています。他にもPythonやC、AIや競技プログラミングなどもやっています。興味があればぜひ他の記事も見てみてください。
ありがとうございました。

Discussion