عرض الإشعارات المحلية باستخدام flutter_local_notifications
عرض الإشعارات المحلية باستخدام flutter_local_notifications
تتيح الإشعارات المحلية لتطبيق Flutter تنبيه المستخدمين برسائل أو تذكيرات أو تحديثات — بالكامل من كود Dart، دون الحاجة إلى خادم بعيد. تُعدّ إضافة flutter_local_notifications المعيار الفعلي لجدولة الإشعارات المحلية وعرضها على كلٍّ من Android وiOS. في هذا الدرس ستقوم بإعداد الإضافة من الصفر، وتهيئتها بشكل صحيح لكل منصة، ثم إطلاق أول إشعار لك.
إضافة الاعتمادية
افتح pubspec.yaml وأضف الإضافة تحت dependencies:
dependencies:
flutter:
sdk: flutter
flutter_local_notifications: ^17.0.0 # استخدم أحدث إصدار مستقر
نفّذ flutter pub get لتنزيل الحزمة. على Android لا تحتاج إلى تغييرات إضافية في Gradle للإشعارات الأساسية؛ أما على iOS فيجب طلب الإذن في وقت التشغيل (مُغطَّى أدناه).
إعداد منصة Android
على Android 13 (API 33) وما فوق، يجب الإعلان عن إذن POST_NOTIFICATIONS وطلبه في وقت التشغيل. أضفه إلى android/app/src/main/AndroidManifest.xml داخل وسم <manifest>:
<!-- مطلوب لـ Android 13+ -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- مطلوب لجدولة التنبيهات الدقيقة على Android 12+ -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
يجب أيضاً تعيين الحد الأدنى لإصدار SDK إلى 21 على الأقل في android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
}
}
إعداد منصة iOS
على iOS، افتح ios/Runner/AppDelegate.swift وتأكد من أنه يستدعي super.application(_:didFinishLaunchingWithOptions:) حتى تتمكن الإضافة من تسجيل معالجات الإشعارات. لا تحتاج إلى مفاتيح إضافية في Info.plist للإشعارات المحلية؛ تطلب الإضافة الإذن من خلال نافذة حوار النظام في وقت التشغيل.
تهيئة الإضافة
هيّئ FlutterLocalNotificationsPlugin مرة واحدة عند بدء التطبيق — عادةً في main() قبل runApp(). تقوم بإنشاء كائن إعدادات التهيئة لكل منصة ودمجها في نسخة واحدة من InitializationSettings.
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter/material.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// --- إعدادات تهيئة Android ---
const AndroidInitializationSettings androidSettings =
AndroidInitializationSettings('@mipmap/ic_launcher');
// --- إعدادات تهيئة iOS ---
const DarwinInitializationSettings iosSettings =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
const InitializationSettings initSettings = InitializationSettings(
android: androidSettings,
iOS: iosSettings,
);
await flutterLocalNotificationsPlugin.initialize(
initSettings,
onDidReceiveNotificationResponse: (NotificationResponse response) {
// يُستدعى عند نقر المستخدم على الإشعار
debugPrint('تم النقر على الإشعار. البيانات: ${response.payload}');
},
);
runApp(const MyApp());
}
WidgetsFlutterBinding.ensureInitialized() مطلوب قبل أي عمل async في main(). بدونه لن يكون ربط محرك Flutter مهيَّأً بعد وستُطلق قنوات الإضافات استثناء MissingPluginException.طلب إذن وقت التشغيل (Android 13+ / iOS)
على iOS وAndroid 13+، يجب طلب إذن المستخدم قبل عرض الإشعارات. تُعرض الإضافة طريقة ملائمة للقيام بذلك:
Future<void> requestNotificationPermissions() async {
// iOS
final bool? grantedIOS = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
// Android 13+
final bool? grantedAndroid = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
debugPrint('iOS: $grantedIOS, Android: $grantedAndroid');
}
عرض إشعار محلي بسيط
بمجرد تهيئة الإضافة ومنح الإذن، يتطلب عرض الإشعار ثلاثة كائنات: AndroidNotificationDetails وDarwinNotificationDetails (iOS) وNotificationDetails المدمجة. استدعِ show() مع معرّف صحيح وعنوان وجسم ونص حمولة اختياري.
Future<void> showSimpleNotification({
required int id,
required String title,
required String body,
String? payload,
}) async {
const AndroidNotificationDetails androidDetails =
AndroidNotificationDetails(
'general_channel', // معرّف القناة (فريد لكل تطبيق)
'General Notifications', // اسم القناة (يظهر في الإعدادات)
channelDescription: 'General app notifications',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
);
const DarwinNotificationDetails iosDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
);
const NotificationDetails notificationDetails = NotificationDetails(
android: androidDetails,
iOS: iosDetails,
);
await flutterLocalNotificationsPlugin.show(
id,
title,
body,
notificationDetails,
payload: payload,
);
}
// مثال على الاستخدام:
// await showSimpleNotification(
// id: 0,
// title: 'مرحباً من Flutter!',
// body: 'هذا أول إشعار محلي لك.',
// payload: 'home_screen',
// );
'general_channel' أعلاه) يجب أن يكون متسقاً عبر الاستدعاءات — يُنشئ النظام القناة عند الاستخدام الأول. تغيير معرّف القناة ينشئ قناة جديدة منفصلة مرئية في تطبيق الإعدادات على الجهاز.معالجة نقرات الإشعارات والبيانات
معامل payload هو سلسلة نصية حرة ترفقها بالإشعار. عندما ينقر المستخدم عليه، يُطلق رد الاتصال onDidReceiveNotificationResponse (المسجَّل أثناء initialize()) مع كائن NotificationResponse تحمل خاصيته .payload سلسلتك النصية. استخدمها للتنقل إلى الشاشة الصحيحة:
// داخل ودجت يملك وصولاً إلى Navigator (مثلاً خدمة بـ GlobalKey)
void handleNotificationTap(NotificationResponse response) {
final String? payload = response.payload;
if (payload == 'home_screen') {
navigatorKey.currentState?.pushNamed('/home');
} else if (payload == 'settings') {
navigatorKey.currentState?.pushNamed('/settings');
}
}
ملخص
في هذا الدرس تعلمت تدفق الإعداد الكامل لـ flutter_local_notifications:
- إضافة الاعتمادية وتهيئة
AndroidManifest.xml/build.gradleلـ Android - إنشاء إعدادات التهيئة الخاصة بكل منصة (
AndroidInitializationSettingsوDarwinInitializationSettings) - استدعاء
FlutterLocalNotificationsPlugin.initialize()فيmain()بعدWidgetsFlutterBinding.ensureInitialized() - طلب أذونات وقت التشغيل على iOS وAndroid 13+
- تعريف قناة إشعارات (Android فقط) واستدعاء
show()مع المعرّف والعنوان والجسم وبيانات الحمولة الاختيارية - معالجة أحداث النقر عبر رد الاتصال
onDidReceiveNotificationResponse
zonedSchedule()) وإشعارات متكررة (periodicallyShow()) وإشعارات غنية بصور وأزرار إجراءات أو أشرطة تقدم — كلها مُغطَّاة في الدروس القادمة.