9. الإشعارات المحلية (AppsKitSDKLocalNotificationManager)
يوفّر AKS مجموعة أدوات صغيرة للإشعارات المحلية — قائمة انتظار، وأداة لإنشاء الإشعارات، وفئة BroadcastReceiver مجرّدة — يمكنك استخدامها لعرض إشعاراتك المحلية. لا يسجّل AKS مستقبِل البث في ملف البيان الخاص به، ولا يجدول أي شيء نيابةً عنك؛ فأنت المسؤول عن الأمرين.
9.1 ملف البيان
أنشئ فئة فرعية من AppsKitSDKLocalNotificationBroadCastReceiver (كما هو موضح في §9.2) وصرّح عنها كعنصر <receiver>، مع دمجها في عنصر <application> نفسه الوارد في §2:
<application
android:name=".YourApplication">
<receiver
android:name=".YourNotificationReceiver"
android:exported="false" />
</application>إذا كنت تستهدف Android 13 أو أحدث (API 33)، فأضف أيضًا إذن الإشعارات الذي يُطلب وقت التشغيل — إذ لا يصرّح ملف البيان الخاص بـ AKS بهذا الإذن، لذا لن يُدمج تلقائيًا في ملف بيان تطبيقك:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />الإذن POST_NOTIFICATIONS هو إذن يُطلب وقت التشغيل، لذا لا يزال عليك طلبه من المستخدم (مثلًا عبر ActivityResultContracts.RequestPermission()) قبل أن تتمكن من عرض الإشعارات فعليًا.
9.2 إضافة إشعار إلى قائمة الانتظار
أنشئ فئة فرعية من AppsKitSDKLocalNotificationBroadCastReceiver ونفّذ checkNotifications() — وهي نقطة التخصيص التي تتيح لك تحديد ما إذا كان قد حان موعد إشعار، وتُستدعى في كل مرة يُفعّل فيها مستقبِل البث:
class YourNotificationReceiver : AppsKitSDKLocalNotificationBroadCastReceiver() {
override fun checkNotifications() {
addNotificationInQueue(
NotificationModel(
id = "daily_reminder", // dedup key — a second add with the same id is ignored
title = "Come back!",
description = "You have unfinished items waiting.",
icon = R.drawable.ic_notification,
notificationId = 1001, // the actual Android notification ID passed to notify()
targetScreen = "com.yourapp.MainActivity" // fully-qualified Activity class opened on tap
)
)
}
}بمجرد انتهاء checkNotifications()، تستدعي onReceive تلقائيًا AppsKitSDKLocalNotificationManager.showNotification(context) — فتسحب أقدم عنصر NotificationModel من قائمة الانتظار وتعرضه. لا تحتاج إلى استدعاء showNotification بنفسك في هذا المسار؛ تكفي إضافة الإشعار إلى قائمة الانتظار داخل checkNotifications().
يتحقق مسار العرض من قائمة الانتظار بنفسه من الإذن
POST_NOTIFICATIONSعلى Android 13 أو أحدث، ويتخطى العرض بصمت (مع تسجيل سطر في السجل) إذا لم يُمنح الإذن، لذا تأكد من طلبه أولًا وفقًا لـ §9.1.
9.3 الجدولة
لا يسجّل AKS مستقبِل البث هذا ولا يشغّله وفق أي جدول زمني — أنت من يحدد وقت استدعاء onReceive، وعادةً ما يكون ذلك باستخدام AlarmManager:
val intent = Intent(context, YourNotificationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + intervalMs,
intervalMs,
pendingIntent
)بالنسبة إلى intervalMs، يمكنك تحديد الفاصل الزمني مباشرةً في الشيفرة، أو استخدام القيمة المحددة في الإعدادات عن بُعد في بوابة AKS (HOURS_TO_MAKE_NOTIFICATION، وقيمتها الافتراضية ساعتان إذا لم تُضبط). تتوفر هذه القيمة عبر getTimeIntervalInMilliSeconds() في الفئة الأساسية لمستقبِل البث، لكنها protected، لذا استدعها من داخل فئتك الفرعية بدلًا من موضع الاستدعاء أعلاه:
class YourNotificationReceiver : AppsKitSDKLocalNotificationBroadCastReceiver() {
fun intervalMillis(): Long = getTimeIntervalInMilliSeconds()
override fun checkNotifications() { /* ... */ }
}لا تضمن
AlarmManager.setRepeatingتوقيتًا دقيقًا عند تفعيل وضع Doze أو تحسينات البطارية — إذا كنت تحتاج إلى تشغيلها بشكل موثوق أثناء خمول الجهاز، فأعد الجدولة باستخدامsetExactAndAllowWhileIdleعند كل تشغيل بدلًا من ذلك، أو انتقل إلىPeriodicWorkRequestفيWorkManager(بفاصل زمني أدنى قدره 15 دقيقة). لا يفرض AKS أيًا من الخيارين؛ اختر ما يناسب تطبيقك. لاحظ أيضًا أن المنبّهات لا تبقى مسجّلة بعد إعادة تشغيل الجهاز إلا إذا أعدت تسجيلها بنفسك (مثلًا من مستقبِل بثBOOT_COMPLETED).
9.4 عرض إشعار مباشرةً (دون قائمة انتظار)
لعرض إشعار فورًا، دون المرور بمسار قائمة الانتظار ومستقبِل البث الموضح أعلاه:
// Tapping opens the Activity at classPath
AppsKitSDKLocalNotificationManager.showNotification(
context = this,
id = 2001,
classPath = "com.yourapp.MainActivity",
channelId = "general",
title = "New message",
message = "You've got a new message waiting.",
notificationIcon = R.drawable.ic_notification
)
// Or pass a fully-built Intent instead of a class path
AppsKitSDKLocalNotificationManager.showNotification(
context = this,
id = 2002,
intent = Intent(this, MainActivity::class.java).putExtra("from", "notification"),
channelId = "general",
title = "New message",
message = "Tap to view details.",
notificationIcon = R.drawable.ic_notification
)تنشئ كلتا الصيغتين المحمّلتين تحميلًا زائدًا قناة الإشعارات نيابةً عنك إذا لم تكن موجودة مسبقًا. وعلى خلاف مسار قائمة الانتظار في §9.2، لا تتحقق أيٌّ منهما بنفسها من الإذن POST_NOTIFICATIONS — اطلب إذن وقت التشغيل بنفسك على Android 13 أو أحدث، وإلا فقد يفشل الاستدعاء في عرض الإشعار بصمت.